XPathを使用して特定の属性を持つ最初の要素を選択する方法


300

XPath bookstore/book[1]は、の下の最初のブックノードを選択しますbookstore

より複雑な条件に一致する最初のノードを選択するにはどうすればよいですか(例:一致する最初のノード) /bookstore/book[@location='US']

回答:


444

使用する:

(/bookstore/book[@location='US'])[1]

これは、最初に、location属性が「US」に等しい本の要素を取得します。次に、そのセットから最初のノードを選択します。いくつかの実装で必要な括弧の使用に注意してください。

これは同じではないことに注意してください /bookstore/book[1][@location='US']、最初の要素にもたまたまその場所属性がない場合。


// bookstore / book [@ location = 'US']で同じようにするにはどうすればよいですか?
Alexander V. Ilyin

7
これにより、すべての書籍が「米国」から取得されます。(/ bookstore / book [@ location = 'US'])[1]は最初のものを取得します。
ケビン・ドライガー

3
@KevinDriedger /bookstore/book[@location='US'][1]は 'US'のすべての本を返すわけではありません。私はそれを複数回、さまざまな言語のxpath実装の下でテストしました。/bookstore/book[@location='US'][1]書店の最初の「米国」の本を返します。複数の書店がある場合は、それぞれから最初の書店が返されます。これは、OPが要求したものです(書店の下の最初のノード)。このバージョンでは、すべての書店から最初の1冊だけが返されます(最初の一致)。
ジョナサン・フィンランド

3
@JonathanFingland誤解-AlexanderV.Ilyinの質問のコンテキストとともに、KevinDriedgerの回答をもう一度読んでください。どちらも同じ意味です。
kiedysktos

175

/bookstore/book[@location='US'][1] 単純な構造でのみ機能します。

もう少し構造を追加すると、物事が壊れます。

<bookstore>
 <category>
  <book location="US">A1</book>
  <book location="FIN">A2</book>
 </category>
 <category>
  <book location="FIN">B1</book>
  <book location="US">B2</book>
 </category>
</bookstore> 

/bookstore/category/book[@location='US'][1] 収量

<book location="US">A1</book>
<book location="US">B2</book>

「より複雑な条件に一致する最初のノード」ではありません。/bookstore/category/book[@location='US'][2]何も返しません。

括弧を使用すると、元の質問の結果を得ることができます。

(/bookstore/category/book[@location='US'])[1] 与える

<book location="US">A1</book>

そして(/bookstore/category/book[@location='US'])[2]期待通りに動作します。


11
ここで受け入れられた回答の著者。OPの質問は考慮され/bookstore/book[1]、無視され(/bookstore/book)[1]ます。あなたが提供したケースは、OPが要求したケースと同じではありません。おそらく、OPは私の答えを彼が期待した(そして要求した)とおりに受け入れたでしょう。
ジョナサン・フィンランド

提供されたこの回答は、この特異なケースで私を助けました。それが「より複雑な状況」を処理しない理由を誰かが説明できますか?基本的には2つのアイテムのリストを見つけるので、[2]はそれを(私の世界では)ピックアップする必要があります
Skurpi

私の場合も、[1]を追加するだけで複数のノードが返される、より複雑な構造になっているため、この回答も選択した回答よりも正しいことがわかりました。ありがとう!
mydoghasworms 2012

2
括弧が機能します!次のように、(..)[1]の後にパスを追加することもできます'(//div[text() = "'+ name +'"])[1]/following-sibling::*/div/text()'。一致するノードが多数ある場合name
Hlung、

1
私の意見は変わります。しばらくすると、私はこの答えが言っていることを理解し、OPの例が見当たらない場合、私はこれに投票しました。私はこの答えの口調に反応していたと思います。@tkurkiが条件を最初のノードの選択から分離することについてもう少し説明していたとしたら、私はすぐにそれを見ました。おそらくジョンフィンランドも同じだろう。
Gerard ONeill 2013年

51

ジョナサン・フィンランドの答えの説明として:

  • 同じ述語([position()=1 and @location='US'])内の複数の条件は、全体として真でなければなりません
  • 連続する述語([position()=1][@location='US'])内の複数の条件は次々と真でなければなりません
  • これは、[position()=1][@location='US']!= [@location='US'][position()=1]
    while [position()=1 and @location='US']==[@location='US' and position()=1]
  • ヒント:ローン[position()=1]は次のように省略できます[1]

ブール演算子 " and"および " or"とブールXPath関数を使用して、述語に複雑な式を作成できます。not()true()そしてfalse()。さらに、括弧でサブ式を囲むことができます。


15

(ドキュメント全体で)最初の英語の本のノードを見つける最も簡単な方法は、次のようなより複雑な構造化xmlファイルを考慮に入れます。

<bookstore>
 <category>
  <book location="US">A1</book>
  <book location="FIN">A2</book>
 </category>
 <category>
  <book location="FIN">B1</book>
  <book location="US">B2</book>
 </category>
</bookstore> 

xpath式です:

/descendant::book[@location='US'][1]


10
    <bookstore>
     <book location="US">A1</book>
     <category>
      <book location="US">B1</book>
      <book location="FIN">B2</book>
     </category>
     <section>
      <book location="FIN">C1</book>
      <book location="US">C2</book>
     </section>
    </bookstore> 

上記を考えると、あなたは最初の本を選択することができます

(//book[@location='US'])[1]

そして、これは、場所がUSである最初の1つを見つけます。[A1]

//book[@location='US']

USの場所にあるすべてのブックを含むノードセットを返します。[A1、B1、C2]

(//category/book[@location='US'])[1]

ドキュメント内の任意の場所のカテゴリに存在する最初の本の場所USを返します。[B1]

(/bookstore//book[@location='US'])[1]

ルート要素の書店の下のどこかに存在する、場所がUSの最初の本を返します。/ bookstoreの部分を本当に冗長にする。[A1]

直接的な答え:

/bookstore/book[@location='US'][1]

bookstore [A1]の下にあるUSの場所を持つbook要素の最初のノードを返します

ちなみに、必要に応じて、この例では、書店の直接の子ではない最初の米国の本を見つけます。

(/bookstore/*//book[@location='US'])[1]

4

xpathが複雑であるか、同じxpathで複数のノードが存在する場合は、インデックスを使用して目的のノードを取得します。

例:

(//bookstore[@location = 'US'])[index]

必要なノード番号を指定できます。


2

指定されたxmlで名前空間が提供されている場合は、これを使用することをお勧めします。

(/*[local-name() ='bookstore']/*[local-name()='book'][@location='US'])[1]


-1

オンラインのxpathテスターの助けを借りて、私はこの答えを書いています...
このために:

<table id="t2"><tbody>
<tr><td>123</td><td>other</td></tr>
<tr><td>foo</td><td>columns</td></tr>
<tr><td>bar</td><td>are</td></tr>
<tr><td>xyz</td><td>ignored</td></tr>
</tbody></table>

次のxpath:

id("t2") / tbody / tr / td[1]

出力:

123
foo
bar
xyz

1は、直接の親の最初の子であるすべてのtd要素を選択することを意味するため。
しかし、次のxpath:

(id("t2") / tbody / tr / td)[1]

出力:

123
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.