在不知道命名空间的情况下使用LINQsearchXDocument

有没有办法在不知道命名空间的情况下searchXDocument? 我有一个logging所有SOAP请求并encryption敏感数据的进程。 我想find任何基于名称的元素。 就像给我所有的名字是CreditCard的元素。 我不在乎命名空间是什么。

我的问题似乎与LINQ和需要一个XML命名空间。

我有其他进程从XML检索值,但我知道这些其他进程的命名空间。

XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); XNamespace xNamespace = "http://CompanyName.AppName.Service.Contracts"; var elements = xDocument.Root .DescendantsAndSelf() .Elements() .Where(d => d.Name == xNamespace + "CreditCardNumber"); 

我真的想有能力searchXML不知道命名空间,如下所示:

 XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); var elements = xDocument.Root .DescendantsAndSelf() .Elements() .Where(d => d.Name == "CreditCardNumber") 

这是行不通的,因为我不知道编译时的命名空间。

如何才能做到这一点?

 <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Request xmlns="http://CompanyName.AppName.Service.ContractA"> <Person> <CreditCardNumber>83838</CreditCardNumber> <FirstName>Tom</FirstName> <LastName>Jackson</LastName> </Person> <Person> <CreditCardNumber>789875</CreditCardNumber> <FirstName>Chris</FirstName> <LastName>Smith</LastName> </Person> ... <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"> <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <Request xmlns="http://CompanyName.AppName.Service.ContractsB"> <Transaction> <CreditCardNumber>83838</CreditCardNumber> <TransactionID>64588</FirstName> </Transaction> ... 

正如Adam在注释中所说的那样,XName可以转换为string,但是当有string时,该string需要命名空间。 这就是为什么.Name与string的比较失败,或者为什么不能将“Person”作为parameter passing给XLinq方法来过滤其名称。
XName由一个前缀(Namespace)和一个LocalName组成。 如果您忽略命名空间,则本地名称就是您要查询的内容。
谢谢亚当:)

您不能将节点的名称作为.Descendants()方法的参数,但您可以通过以下方式进行查询:

 var doc= XElement.Parse( @"<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/""> <s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> <Request xmlns=""http://CompanyName.AppName.Service.ContractA""> <Person> <CreditCardNumber>83838</CreditCardNumber> <FirstName>Tom</FirstName> <LastName>Jackson</LastName> </Person> <Person> <CreditCardNumber>789875</CreditCardNumber> <FirstName>Chris</FirstName> <LastName>Smith</LastName> </Person> </Request> </s:Body> </s:Envelope>"); 

编辑: 坏的复制/过去从我的testing:)

 var persons = from p in doc.Descendants() where p.Name.LocalName == "Person" select p; foreach (var p in persons) { Console.WriteLine(p); } 

这对我行得通…

你可以从根元素中获取命名空间:

 XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); var ns = xDocument.Root.Name.Namespace; 

现在,您可以使用加号运算符轻松获得所有需要的元素:

 root.Elements(ns + "CreditCardNumber") 

我想我find了我正在寻找的东西。 你可以在下面的代码中看到我做了评估Element.Name.LocalName == "CreditCardNumber" 。 这似乎在我的testing中工作。 我不确定这是否是最佳做法,但是我打算使用它。

 XDocument xDocument = XDocument.Load(@"C:\temp\Packet.xml"); var elements = xDocument.Root.DescendantsAndSelf().Elements().Where(d => d.Name.LocalName == "CreditCardNumber"); 

现在我有可以encryption值的元素。

如果有人有更好的解决scheme,请提供。 谢谢。

如果您的XML文档始终在同一个节点中定义名称空间(给出的两个示例中的Request节点),则可以通过查询并查看结果具有的命名空间来确定它:

 XDocument xDoc = XDocument.Load("filename.xml"); //Initial query to get namespace: var reqNodes = from el in xDoc.Root.Descendants() where el.Name.LocalName == "Request" select el; foreach(var reqNode in reqNodes) { XNamespace xns = reqNode.Name.Namespace; //Queries making use of namespace: var person = from el in reqNode.Elements(xns + "Person") select el; } 

只需使用后代方法:

 XDocument doc = XDocument.Load(filename); String[] creditCards = (from creditCardNode in doc.Root.Descendents("CreditCardNumber") select creditCardNode.Value).ToArray<string>();