【问题标题】:Xpath to find first occurrence of two different elementsXpath查找两个不同元素的第一次出现
【发布时间】:2013-09-25 20:39:47
【问题描述】:

使用下面的示例,我想使用 xPath 来查找两个不同元素的第一次出现。例如,我想弄清楚是 b 还是 d 先出现。我们可以清楚地看出 b 出现在 d 之前(自上而下,而不是在树级别)。但是,如何使用 xpath 解决这个问题?

<a>
   <b>
   </b>
</a>
<c>
</c>
<d>
</d>

现在,我通过获取节点集中的第一个元素来找到节点(在本例中为 b 和 d),我使用以下代码找到它:

String xPathExpression = "//*[local-name()='b']";
XPathNodeIterator nodeSet = (XPathNodeIterator)navigator.Evaluate(xPathExpression);

和

String xPathExpression = "//*[local-name()='d']";
XPathNodeIterator nodeSet = (XPathNodeIterator)navigator.Evaluate(xPathExpression);

现在使用 xpath,我只是不知道哪个先出现,b 还是 d。

【问题讨论】:

  • 你需要用 xpath 做这个吗?这可以在构建树后使用 LINQ to XML 轻松解决。
  • 我很乐意看到如何使用 LINQ to XML 来完成这项工作。效率真的是我唯一关心的问题。

标签: c# xml xpath xpathnavigator


【解决方案1】:

您想以文档顺序(元素出现的顺序)扫描树。好像这是默认搜索顺序一样,您所要做的就是选择第一个元素,即 &lt;b/&gt; 或 &lt;d/&gt; 节点:

//*[local-name() = 'b' or local-name() = 'd'][1]

如果您想要名称,请添加另一个 local-name(...) 调用:

local-name(//*[local-name() = 'b' or local-name() = 'd'][1])

【讨论】:

    【解决方案2】:

    如果您想使用 LINQ to XML 解决相同的解决方案,您可以尝试以下方法:

    XDocument xmlDoc = new XDocument(filepath);
    XElement first = (from x in xmlDoc.Descendants()
                where x.Name == "b" || x.Name == "d"
                select x).FirstOrDefault();
    

    现在您可以运行一个简单的 if 语句来确定“b”或“d”是否是找到的第一个符合我们条件的元素。

     if(first.Name.Equals("b")
        //code for b being first
     else if(first.Name.Equals("d")
        //code for d being first
    

    根据评论员的建议,您的代码使用 lambda 表达式而不是完整的 LINQ 查询会更简洁,但如果您是 LINQ 新手,这有时会令人困惑。以下是我上面的XElement 分配的完全相同的查询:

    XElement first = xmlDoc.Descendants().FirstOrDefault(x => x.Name == "b" || x.Name == "d");
    

    如果您愿意不使用 xpath,我希望这就是您正在寻找的。​​p>

    【讨论】:

    • xmlDoc.Descendants().FirstOrDefault(x =&gt; x.Name == "b" || x.Name == "d") 看起来更干净,IMO,但它是一个不错的选择。
    • 那个 lambda 表达式做同样的事情,是的,它更清晰。但是,我写出了完整的查询,因为 OP 没有请求 LINQ 答案,所以我想提供完整的查询以供参考。这不是 SO 的最佳实践吗?
    • 不过,我会将其添加到我的答案中。
    【解决方案3】:

    这个 XPath 表达式可以工作:

    //*[local-name()='b' or local-name()='d'][1]
    

    或者对于更短的解决方案,你可以试试这个:

    (//b|//d)[1]
    

    两个表达式都将选择b 元素或d 元素,按照它们出现的顺序,并且只选择结果集中的第一个元素。

    【讨论】:

    • 这肯定适用于我在上面发布的情况。但在我的实际情况中,这些元素位于不同的树级别,并且每个元素名称中都有命名空间。不过感谢您的反馈,很高兴知道。
    • @jsirr13 当然,我知道这是一个示例,但我的主要目标是指出您可以使用| 将两个结果集合并为一个(无论它们是如何构造的)然后使用(...)[1] 选择任何这些集合中的第一个元素。
    猜你喜欢
    • 1970-01-01
    • 2015-06-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多