【问题标题】:Find Element when XPath is variableXPath 可变时查找元素
【发布时间】:2013-02-17 21:56:14
【问题描述】:

我正在尝试编写一个将 XML 作为输入的算法,并找到与特定元素关联的值,但 XML 正文中元素的位置会有所不同。我见过许多使用 XDocument.Descendants() 的示例,但大多数(如果不是全部)示例期望结构是一致的,并且后代是众所周知的。我想我需要递归 XML 才能找到这个值,但在朝着这个方向前进之前,请询问一般人群。

当元素的路径在每次调用中可能不同时,在 XDocument 中查找元素的最佳方法是什么?只需要找到第一次出现,而不是按任何特定顺序。可以通过变宽或深入找到第一次出现。

例如,如果我正在尝试查找元素“FirstName”,并且 Call one 的输入 XML 看起来像..

<?xml version="1.0"?>
<PERSON><Name><FirstName>BOB</FirstName></Name></PERSON>

下一个调用看起来像:

<?xml version="1.0"?>
<PERSONS><PERSON><Name><FirstName>BOB</FirstName></Name></PERSON></PERSONS>

你有什么推荐的? XDocument 中有没有我没见过的“查找”选项?

更新:

上面的简单示例适用于 XDocument.Descendents 的lazyberezovsky 答案,但真正的 XML 不能。我有问题的 XML...

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:52087/Service1.svc</To>
    <Action s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://tempuri.org/IService1/GetDataUsingDataContract</Action>
  </s:Header>
  <s:Body>
    <GetDataUsingDataContract xmlns="http://tempuri.org/">
      <composite xmlns:a="http://schemas.datacontract.org/2004/07/WcfService2" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
        <a:BoolValue>false</a:BoolValue>
        <a:Name>
          <a:FirstName>BOB</a:FirstName>
        </a:Name>
        <a:StringValue i:nil="true" />
      </composite>
    </GetDataUsingDataContract>
  </s:Body>
</s:Envelope>

更新:

lazyberezovsky 极大地帮助我向我展示了 Descendents 应该如何工作。注意 XML 中的名称空间。学过的知识。又发现了一个。有类似问题的文章..

Search XDocument using LINQ without knowing the namespace

使用以下sn-p解决...

var xdoc = XDocument.Parse(xml);
var name = (from p in xdoc.Descendants() where p.Name.LocalName == "FirstName" select p.Value).FirstOrDefault();

【问题讨论】:

  • 对于这些示例,您可以只使用正则表达式来搜索文档文本。有什么不可行的原因吗?
  • 你能提供一个你所指的正则表达式的例子吗?上面的示例是一个简单的问题示例,但我正在使用的 XML 具有可变名称空间,因此字符串解析即使不是不可能也变得困难。
  • @barrypicker 使用 Descendants 有什么问题?
  • @lazyberezovsky - 也许我只是错误地使用了 Descendents,但是当我尝试时,第一个调用会找到下一级元素。如果我按名称“FirstName”指定,如上面的示例所示,并且该元素不存在,我将得不到任何结果。如果我不指定名称,我会得到当前元素以下的所有元素,那么我需要更深入地了解。这就是我所说的需要递归结构的意思。我觉得这可能是我最好的选择...

标签: c# xml linq xpath


【解决方案1】:

当您使用 Descendants 查找第一次出现的元素时,您不需要知道 文件结构。以下代码适用于您的两种情况:

var xdoc = XDocument.Load(path_to_xml);
var name = (string)xdoc.Descendants("FirstName").FirstOrDefault();

与 XPath 相同

var name = (string)xdoc.XPathSelectElement("//FirstName[1]");

【讨论】:

  • 我喜欢你的代码示例带给我的方向。我尝试了您提供的 XDocument Descendents 示例,它适用于我提供的简单 XML 示例,但不适用于我正在处理的实际 XML。这让我相信我的 XML 有一些特别之处,而不是使用 Descendents。
  • 我将有问题的 XML 添加到问题中。有什么想法吗?
  • 好的,@lazyberezovsky 你绝对是在正确的轨道上。命名空间把我扔了。我找到了另一个\。文章在...stackoverflow.com/questions/2610947/… 这里的诀窍是一点 LINQ。 var xdoc = XDocument.Parse(xml); var name = (from p in xdoc.Descendants() where p.Name.LocalName == "FirstName" select p.Value).FirstOrDefault();
  • @barrypicker 抱歉,被AFK了。感谢您接受,很高兴看到您管理的命名空间!顺便说一句,如果 FirstName 元素的命名空间保持不变,您可以创建 XNamespace 对象,并像这样查询元素 Descendants(ns + "FirstName")
【解决方案2】:

在不知道 XML 文档的所有可能排列方式的情况下(顺便说一句,这很不寻常),我认为没有人希望给您任何有价值的建议。

【讨论】:

  • 这是一个答案,只是不是他要找的那个。
【解决方案3】:

“只需​​要找到的第一个匹配项,而不是任何特定的顺序。”我认为Descendants 会耍花招。看看这个:

string xml = @"<?xml version=""1.0""?>
             <PERSONS>
                  <PERSON>
                      <Name>
                         <FirstName>BOB</FirstName>
                      </Name>
                  </PERSON>
             </PERSONS>";
XDocument doc = XDocument.Parse(xml);
Console.WriteLine(string.Join(",", doc.Descendants("FirstName").Select(e =>(string)e)));

xml = @"<?xml version=""1.0""?>
            <PERSON>
               <Name>
                   <FirstName>BOB</FirstName>
               </Name>
            </PERSON>";
doc = XDocument.Parse(xml);
Console.WriteLine(string.Join(",", doc.Descendants("FirstName").Select(e =>(string)e)));

【讨论】:

    猜你喜欢
    • 2021-10-11
    • 2020-05-02
    • 1970-01-01
    • 1970-01-01
    • 2018-07-09
    • 2020-05-03
    • 2020-05-19
    • 2021-03-31
    • 1970-01-01
    相关资源
    最近更新 更多