91

有人知道如何使用 XPath 获取节点的位置吗?

假设我有以下 xml:

<a>
    <b>zyx</b>
    <b>wvu</b>
    <b>tsr</b>
    <b>qpo</b>
</a>

我可以使用以下 xpath 查询来选择第三个 <b> 节点 (<b>tsr</b>):

a/b[.='tsr']

这一切都很好,但我想返回该节点的序数位置,例如:

a/b[.='tsr']/position()

(但更多的工作!)

甚至可能吗?

编辑:忘了提到我正在使用.net 2,所以它是 xpath 1.0!


更新:最终使用了James Sulak出色答案。对于那些感兴趣的人,这里是我在 C# 中的实现:

int position = doc.SelectNodes("a/b[.='tsr']/preceding-sibling::b").Count + 1;

// Check the node actually exists
if (position > 1 || doc.SelectSingleNode("a/b[.='tsr']") != null)
{
    Console.WriteLine("Found at position = {0}", position);
}
4

8 回答 8

102

尝试:

count(a/b[.='tsr']/preceding-sibling::*)+1.
于 2008-10-22T18:46:02.790 回答
9

您可以使用 XSLT 做到这一点,但我不确定直接的 XPath。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="utf-8" indent="yes" 
              omit-xml-declaration="yes"/>
  <xsl:template match="a/*[text()='tsr']">
    <xsl:number value-of="position()"/>
  </xsl:template>
  <xsl:template match="text()"/>
</xsl:stylesheet>
于 2008-10-22T16:39:01.627 回答
9

我意识到这篇文章很古老……但是……

用节点名替换星号会给你更好的结果

count(a/b[.='tsr']/preceding::a)+1.

代替

count(a/b[.='tsr']/preceding::*)+1.
于 2010-08-09T02:32:11.663 回答
6

如果您曾经升级到 XPath 2.0,请注意它提供了函数index-of,它以这种方式解决问题:

index-of(//b, //b[.='tsr'])

在哪里:

  • 第一个参数是搜索顺序
  • 第二是搜索什么
于 2015-09-21T16:14:12.480 回答
3

与前面所说的不同,“preceding-sibling”实际上是要使用的轴,而不是完全不同的“preceding”,它选择文档中当前节点开始标记之前的所有内容。(见http://www.w3schools.com/xpath/xpath_axes.asp

于 2010-08-04T20:57:07.833 回答
2

只是对 James Sulak 所做答案的注释。

如果您想考虑节点可能不存在并希望将其保留为纯 XPATH,请尝试以下操作,如果节点不存在,则返回 0。

count(a/b[.='tsr']/preceding-sibling::*)+number(boolean(a/b[.='tsr']))
于 2014-11-27T14:35:02.060 回答
0

问题是节点的位置在没有上下文的情况下意义不大。

以下代码将为您提供节点在其父子节点中的位置

using System;
using System.Xml;

public class XpathFinder
{
    public static void Main(string[] args)
    {
        XmlDocument xmldoc = new XmlDocument();
        xmldoc.Load(args[0]);
        foreach ( XmlNode xn in xmldoc.SelectNodes(args[1]) )
        {
            for (int i = 0; i < xn.ParentNode.ChildNodes.Count; i++)
            {
                if ( xn.ParentNode.ChildNodes[i].Equals( xn ) )
                {
                    Console.Out.WriteLine( i );
                    break;
                }
            }
        }
    }
}
于 2008-10-23T08:20:51.850 回答
0

我做了很多 Novell Identity Manager 的工作,而 XPATH 在这种情况下看起来有点不同。

假设您要查找的值在一个名为 TARGET 的字符串变量中,那么 XPATH 将是:

count(attr/value[.='$TARGET']/preceding-sibling::*)+1

另外有人指出,为了节省几个字符的空间,以下内容也可以使用:

count(attr/value[.='$TARGET']/preceding::*) + 1

我还在 Novell 的酷解决方案上发布了一个更漂亮的版本:使用 XPATH 获取位置节点

于 2008-11-12T20:07:22.623 回答