web-dev-qa-db-ja.com

XPath contains(text()、 'some string')は、複数のTextサブノードを持つノードで使用すると機能しません

私はXpathがdom4jに含まれていると小さな問題があります...

私のXMLは

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

ルート要素が与えられたテキスト内にABCを持つすべてのノードを見つけたいとしましょう...

それで私が書く必要があったであろうxpathはそうなるでしょう

//*[contains(text(),'ABC')]

しかし、これはDom4jが返すものではありません....これはdom4jの問題なのか、それともxpathがどのように機能するのか私の理解です。そのクエリはStreet要素のみを返し、Comment要素は返さないからです。

DOMはComment要素を4つのタグを持つ複合要素にします

[Text = 'XYZ'][BR][BR][Text = 'ABC'] 

私はそれが要素を見つけて実行する必要がありますが、それはしていないので、クエリはまだ要素を返すべきだと思いますが... ...

次のクエリは要素を返しますが、それは単なる要素よりもはるかに多くを返し、それは親要素も返します...これは問題には望ましくありません...

//*[contains(text(),'ABC')]

要素<Street/><Comment/>だけを返すxpathクエリを知っている人はいますか

218
Mike Milkin

<Comment>タグには、子として2つのテキストノードと2つの<br>ノードが含まれています。

あなたのxpath式は

//*[contains(text(),'ABC')]

これを打破するには、

  1. *は、任意の要素(つまりタグ)に一致するセレクタです - ノードセットを返します。
  2. []は、そのノードセット内の個々のノードごとに動作する条件です。それが操作する個々のノードのいずれかが括弧内の条件に一致する場合に一致します。
  3. text()は、セレクタで、コンテキストノードの子であるすべてのテキストノードに一致します。ノードセットを返します。
  4. containsは文字列を操作する関数です。ノードセットを渡すと、ノードセット内のノードの文字列値をドキュメント順で最初に返すことで、ノードセットは に変換されます 。したがって、それはあなたの<Comment>要素の最初のテキストノード、すなわちBLAH BLAH BLAHだけにマッチすることができます。それが一致しないので、あなたはあなたの結果に<Comment>を得ません。

これをに変更する必要があります

//*[text()[contains(.,'ABC')]]
  1. *は、任意の要素(つまりタグ)に一致するセレクタです - ノードセットを返します。
  2. 外側の[]は、そのノードセット内の個々のノードごとに動作する条件式です。ここでは、ドキュメント内の各要素について動作します。
  3. text()は、セレクタで、コンテキストノードの子であるすべてのテキストノードに一致します。ノードセットを返します。
  4. 内側の[]は、そのノードセットの各ノード(ここでは個々のテキストノード)に対して作用する条件です。個々のテキストノードはそれぞれ括弧内のパスの開始点であり、括弧内で.として明示的に表すこともできます。それが操作する個々のノードのいずれかが括弧内の条件に一致する場合に一致します。
  5. containsは文字列を操作する関数です。ここには個々のテキストノード(.)が渡されます。これは<Comment>タグ内の2番目のテキストノードに個別に渡されるため、'ABC'文字列が表示され、それを照合できます。
608
Ken Bloom

[contains(text(),'')]はtrueまたはfalseのみを返します。要素の結果は返されません。

6
Ratna

少し時間がかかりましたが、ついに考え出しました。以下のテキストを含むカスタムxpathは私にとっては完璧に機能しました。

//a[contains(text(),'JB-')]
0
zagoo2000

XMLドキュメント:

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

XPath式:

//*[contains(text(), 'ABC')]

//*は、 ルートノード子孫要素 に一致します。つまり、ルートノード以外の要素。

[...]述語 で、ノードセットをフィルタリングします。 ...trueであるノードを返します。

述語はノードセット[...]をフィルタリングして、新しいノードセットを生成します。フィルタリングされるノードセット内の各ノードに対して、PredicateExprが評価されます[...];そのノードでPredicateExprがtrueと評価された場合、そのノードは新しいノードセットに含まれます。それ以外の場合は含まれません。

contains('haystack', 'needle')trueを返しますhaystackの場合 含むneedle

関数:boolean contains(string、string)

Contains関数は、最初の引数文字列に2番目の引数文字列が含まれる場合はtrueを返し、それ以外の場合はfalseを返します。

ただし、contains()は文字列を最初のパラメーターとして受け取ります。そして、ノードを渡しました。最初のパラメーターとして渡されたすべてのノードまたはノードセットが、string()関数によって文字列に 変換済み であることに対処するには:

引数は、string関数を呼び出した場合のように、string型に変換されます。

string()関数は、 最初のノードstring-valueを返します。

ノードセットは、ドキュメント順で最初のノードセット内のノードの文字列値を返すことにより、文字列に変換されます。ノードセットが空の場合、空の文字列が返されます。

要素ノードstring-value

要素ノードの文字列値は、要素ノードのすべてのテキストノードの子孫の文字列値をドキュメント順に連結したものです。

string-valueの-​​ テキストノード

テキストノードの文字列値は文字データです。

したがって、基本的にstring-valueは、ノードに含まれるすべてのテキスト(すべての子孫テキストノードの連結)です。

text() は、任意のテキストノードに一致するノードテストです。

ノードテストtext()は、すべてのテキストノードに対してtrueです。たとえば、child :: text()はコンテキストノードのテキストノードの子を選択します。

そうは言っても、//*[contains(text(), 'ABC')]は、最初のテキストノードにABCが含まれる任意の要素(ただしルートノード)に一致します。 text()は、(式の評価に関連する)コンテキストノードのすべての子テキストノードを含むノードセットを返すため。しかし、contains()は最初のもののみを取ります。したがって、上記のドキュメントの場合、パスはStreet要素と一致します。

次の式//*[text()[contains(., 'ABC')]]は、ABCを含む少なくとも1つの子テキストノードを持つ任意の要素(ただしルートノード)に一致します。 .はコンテキストノードを表します。この場合、それはルートノード以外の任意の要素の子テキストノードです。そのため、上記のドキュメントの場合、パスはStreetおよびComment要素と一致します。

ここで、//*[contains(., 'ABC')]は、ABC(子孫テキストノードの連結内)を含む任意の要素(ただしルートノード)と一致します。上記のドキュメントでは、HomeAddrStreet、およびCommentエレメントと一致します。そのため、//*[contains(., 'BLAH ABC')]は、HomeAddr、およびComment要素と一致します。

0
x-yuri