Найти положение узла с помощью xpath



кто-нибудь знает, как получить положение узла с помощью xpath?



скажем, у меня есть следующий xml:



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


Я могу использовать следующий запрос xpath для выбора Третьего узла ( tsr):



a/b[.='tsr']


что все хорошо и хорошо, но я хочу возвращение порядковый номер этого узла, что-то вроде:



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


(но немного больше работать!)



это даже возможно?



edit: забыл упомянуть, что я использую .net 2, так что это xpath 1.0!





обновление: в конечном итоге, используя отличный ответ Джеймса Сулака. Для тех, кто заинтересован вот моя реализация на 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);
}
517   8  

8 ответов:

попробуй:

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

вы можете сделать это с помощью 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>

Я понимаю, что пост древний.. но..

замена звездочки на имя узла даст вам лучшие результаты

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

вместо

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

В отличие от заявленного ранее "preceding-sibling" действительно является осью для использования, а не "preceding", которая делает что-то совершенно другое, она выбирает все в документе, который находится перед тегом start текущего узла. (см. http://www.w3schools.com/xpath/xpath_axes.asp)

Если вы когда-либо обновлялись до XPath 2.0, обратите внимание, что он предоставляет функцию index-of, это решает проблему таким образом:

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

где:

  • 1-й параметр-это последовательность поиск
  • 2-й-это то, что нужно искать

проблема в том, что положение узла ничего не значит без контекста.

следующий код даст вам расположение узла в родительской дочерние узлы

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

просто примечание к ответу, сделанному Джеймсом Сулаком.

Если вы хотите принять во внимание, что узел может не существовать и хотите сохранить его чисто XPATH, то попробуйте следующее, что вернет 0, если узел не существует.

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

Я делаю много вещей Novell Identity Manager, и XPATH в этом контексте выглядит немного по-другому.

предположим, что значение, которое вы ищете, находится в строковой переменной, называемой TARGET, тогда XPATH будет:

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

кроме того, было указано, что для сохранения нескольких символов пробела также будет работать следующее:

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

Я также опубликовал более красивую версию этого в Novell's Cool Solutions:использование XPATH для получения позиции узел

Comments

    Ничего не найдено.