web-dev-qa-db-ja.com

xpathを使用してノードの位置を見つける

誰でもxpathを使用してノードの位置を取得する方法を知っていますか?

次のxmlがあるとします。

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

次のxpathクエリを使用して、3番目の<b>ノード(<b> tsr </ b>)を選択できます。

a/b[.='tsr']

これはすべてうまくいきますが、私はそのノードの順序位置をreturnしたいです:

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

(しかし、もう少し機能します!)

それも可能ですか?

edit:.net 2を使用していることを忘れていたため、xpath 1.0です!


UpdateJames Sulakexcellent answer を使用して終了しました。興味がある人のために、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);
}
85
Wilfred Knievel

試してください:

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

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
Steven Huwig

私はこのポストが古代であることに気づきました。

アスタリスクをノード名に置き換えると、より良い結果が得られます

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

の代わりに

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

XPath 2.0にアップグレードする場合、関数 index-of を提供することに注意してください。この方法で問題が解決します。

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

どこ:

  • 1番目のパラメーターは検索のシーケンスです
  • 2番目は検索対象
3
CroWell

前述の「preceding-sibling」は実際に使用する軸であり、まったく異なることを行う「preceding」とは異なり、現在のノードの開始タグの前にあるドキュメント内のすべてを選択します。 ( http://www.w3schools.com/xpath/xpath_axes.asp を参照)

3
Damien

James Sulakによる回答へのメモ。

ノードが存在しない可能性があることを考慮し、純粋にXPATHを保持したい場合は、ノードが存在しない場合に0を返す以下を試してください。

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

問題は、ノードの位置がコンテキストなしではあまり意味がないことです。

次のコードは、親子ノード内のノードの場所を提供します

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;
                }
            }
        }
    }
}
0
Andrew Cox

私は多くのNovell Identity Managerのことをしていますが、そのコンテキストでのXPATHは少し異なっています。

探している値がTARGETという文字列変数にあると仮定すると、XPATHは次のようになります。

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

さらに、スペースのいくつかの文字を節約するために、以下も同様に機能することが指摘されました:

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

また、NovellのCool Solutionsにこのきれいなバージョンを投稿しました。 XPATHを使用して位置ノードを取得

0
geoffc