使用xpath查找节点的位置


86

有人知道如何使用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);
}

请尽量不要在这个问题后的答案- >倒不如已经张贴了这个作为一个答案,然后可能链接到它的问题。
–theMayer

Answers:


94

尝试:

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

1
'Coz,我正在使用.net及其它,否则我将无法处理所要使用的功能:int position = doc.SelectNodes(“ a / b [。='tsr'] / preceding-Sibling :: b”) .Count + 1; if(position> 1 || doc.SelectSingleNode(“ a / b [。='tsr']”)!= null)//检查节点是否确实存在{//在这里做魔术}
Wilfred Knievel

在零索引语言中,您不需要+1
JonnyRaa

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>

9

我知道这个职位很古老。

用nodename替换星号会给你更好的结果

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

代替

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

4

如果要升级到XPath 2.0,请注意,它提供了index-of函数,它可以通过以下方式解决问题:

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

哪里:

  • 第一个参数是搜索顺序
  • 第二是要搜索的内容

应该注意的是,这仅适用于XPath 2+。低于此值的任何内容都必须使用“奇怪”计数功能。
Dan Atkinson

1
@Dan,它已在原始文档的链接中指出,并添加了明确的通知,谢谢!
CroWell 2015年

3

不同于先前所述的“ preceding-sibling”实际上是要使用的轴,而不是“ preceding”会做完全不同的事情,它选择了文档中当前节点的开始标记之前的所有内容。(请参阅http://www.w3schools.com/xpath/xpath_axes.asp


4
不包括祖先节点。不要相信w3schools的细节!但我同意...尽管在此情况下可以使用before ::,因为在相关b元素之前除了a祖先之前没有其他元素,所以它比先前的兄弟姐妹更脆弱。OTOH,OP并没有告诉我们他想知道其中的位置的上下文,因此可能在前面::可能是正确的。
LarsH

2

只是对James Sulak所作回答的说明。

如果要考虑该节点可能不存在,并仅将其保留为XPATH,请尝试以下操作,如果该节点不存在,则该操作将返回0。

count(a/b[.='tsr']/preceding-sibling::*)+number(boolean(a/b[.='tsr']))

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;
                }
            }
        }
    }
}

1
因此,现在不是真正的XPath查找器,而是C#查找器。
jamesh

0

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

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

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

此外,有人指出,要节省一些字符,以下内容也可以工作:

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

我还在Novell的Cool Solutions上发布了一个更漂亮的版本:使用XPATH获取位置节点

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.