Ответ 1
Try:
count(a/b[.='tsr']/preceding-sibling::*)+1.
Кто-нибудь знает, как получить позицию node с помощью xpath?
Скажем, у меня есть следующий xml:
<a>
<b>zyx</b>
<b>wvu</b>
<b>tsr</b>
<b>qpo</b>
</a>
Я могу использовать следующий запрос xpath для выбора третьего <b> node (<b> tsr </b> ):
a/b[.='tsr']
Что все хорошо и хорошо, но я хочу вернуть порядковое положение этого node, что-то вроде:
a/b[.='tsr']/position()
(но немного больше работает!)
Возможно ли это?
edit: Забыл упомянуть, что я использую .net 2, поэтому он xpath 1.0!
Обновление: закончено с помощью Джеймса Сулака отличный ответ. Для тех, кто интересуется здесь, моя реализация в С#:
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);
}
Try:
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>
Я понимаю, что пост древний.. но..
замена звездочки на nodename даст вам лучшие результаты
count(a/b[.='tsr']/preceding::a)+1.
вместо
count(a/b[.='tsr']/preceding::*)+1.
В отличие от предыдущего ранее "предшествующего брака" на самом деле является осью, а не "предшествующей", которая делает что-то совершенно другое, она выбирает все в документе, который находится перед началом тега текущего node. (см. http://www.w3schools.com/xpath/xpath_axes.asp)
Проблема в том, что позиция node не имеет большого значения без контекста.
Следующий код предоставит вам местоположение node в родительских дочерних узлах
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;
}
}
}
}
}
Просто примечание к ответу, сделанному Джеймсом Сулаком.
Если вы хотите принять во внимание, что node может не существовать и хотите сохранить его просто XPATH, попробуйте следующее, которое вернет 0, если node не существует.
count(a/b[.='tsr']/preceding-sibling::*)+number(boolean(a/b[.='tsr']))
Если вы когда-либо обновляетесь до XPath 2.0, обратите внимание, что он предоставляет функцию index-of, она решает проблему следующим образом:
index-of(//b, //b[.='tsr'])
Где:
Я занимаюсь большим количеством материалов Novell Identity Manager, и XPATH в этом контексте выглядит немного по-другому.
Предположим, что значение, которое вы ищете, находится в строковой переменной, называемой TARGET, тогда XPATH будет:
count(attr/value[.='$TARGET']/preceding-sibling::*)+1
Кроме того, было указано, что для сохранения нескольких символов пробела будет работать следующее:
count(attr/value[.='$TARGET']/preceding::*) + 1
Я также опубликовал более красивую версию этого в Novell Cool Solutions: Использование XPATH для получения позиции node