Найти положение узла с помощью 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);
}
8 ответов:
вы можете сделать это с помощью 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