在不知道命名空间的情况下使用LINQ搜索XDocument

Mik*_*Dev 73 c# linq-to-xml

有没有办法在不知道命名空间的情况下搜索XDocument?我有一个记录所有SOAP请求并加密敏感数据的进程.我想根据名字找到任何元素.有点像,给我所有名称为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");
Run Code Online (Sandbox Code Playgroud)

我真的希望能够在不知道名称空间的情况下搜索xml,如下所示:

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

这不起作用,因为我在编译时事先不知道名称空间.

如何才能做到这一点?

<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>      
        ...
Run Code Online (Sandbox Code Playgroud)

Sté*_*ane 85

当Adam在注释中进行精确处理时,XName可以转换为字符串,但是当有一个字符串时,该字符串需要命名空间.这就是为什么.Name与字符串的比较失败,或者为什么你不能将"Person"作为参数传递给XLinq方法来过滤他们的名字.
XName由前缀(Namespace)和LocalName组成.如果忽略名称空间,则本地名称是您要查询的名称.
谢谢Adam :)

您不能将节点的名称作为.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>");
Run Code Online (Sandbox Code Playgroud)

编辑: 我的测试中的错误副本/过去:)

var persons = from p in doc.Descendants()
              where p.Name.LocalName == "Person"
              select p;

foreach (var p in persons)
{
    Console.WriteLine(p);
}
Run Code Online (Sandbox Code Playgroud)

这对我行得通...

  • 可能有助于解释*为什么*您的答案是这样的:名称是XName,XName恰好可以转换为字符串,因此.Name与字符串的比较失败,问题提示者的查询.XName由前缀和本地名称组成,如果忽略名称空间,则本地名称是您要查询的名称. (4认同)

Sas*_*cha 82

您可以从root-element获取命名空间:

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

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

root.Elements(ns + "CreditCardNumber")
Run Code Online (Sandbox Code Playgroud)

  • 只有当所有元素都不在根文档的不同名称空间中时,才能接受此答案.是的,如果您只是询问根文档,就很容易知道命名空间,但是要求提供给定名称的任何元素都比较棘手,无论元素本身可能在哪个命名空间.这就是为什么我认为使用XElement的答案. Name.LocalName(通常通过linq)更通用化. (4认同)

Mik*_*Dev 13

我想我找到了我想要的东西.您可以在以下代码中看到我进行评估Element.Name.LocalName == "CreditCardNumber".这似乎在我的测试中起作用.我不确定这是不是最好的做法,但我会用它.

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

现在我有了可以加密值的元素.

如果有人有更好的解决方案,请提供.谢谢.