web-dev-qa-db-ja.com

複数のタグを選択するXPath

この単純化されたデータ形式を考えると:

<a>
    <b>
        <c>C1</c>
        <d>D1</d>
        <e>E1</e>
        <f>don't select this one</f>
    </b>
    <b>
        <c>C2</c>
        <d>D2</d>
        <e>E1</e>
        <g>don't select me</g>
    </b>
    <c>not this one</c>
    <d>nor this one</d>
    <e>definitely not this one</e>
</a>

C要素の子であるすべてのDs、Es、およびBsをどのように選択しますか?

基本的に、次のようなものです:

a/b/(c|d|e)

私自身の状況では、a/b/だけでなく、CDEノードを選択するクエリは実際には非常に複雑なので、避けたいと思いますこれを行う:

a/b/c|a/b/d|a/b/e

これは可能ですか?

117
nickf

1つの正解は

/a/b/*[self::c or self::d or self::e]

これに注意してください

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

長すぎて正しくない。このXPath式は、次のようなノードを選択します。

OhMy:c

NotWanted:d 

QuiteDifferent:e
189

代わりに、属性テストを使用して繰り返しを回避できます。

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

Dimitreの敵対的な意見に反して、上記は間違っていないであり、OPは名前空間との相互作用を指定していません。 self::軸はネームスペースに制限がありますが、local-name()はそうではありません。 OPの意図が名前空間に関係なくc|d|eをキャプチャすることである場合(問題のOR性質を考慮すると、可能性の高いシナリオでもあります)間違っています。

あなたは定義なしでは決定的ではありませんが、OPが私が間違っているように彼の質問を明確にした場合、私は本当に間違っているとして私の答えを削除して非常に満足しています。

42
annakata

なぜa/b/(c|d|e)ではありませんか? Saxon XML library (Clojureの良さでうまくまとめられています)で試したところ、うまくいくようです。 abc.xmlはOPによって記述されたドキュメントです。

(require '[saxon :as xml])
(def abc-doc (xml/compile-xml (Slurp "abc.xml")))
(xml/query "a/b/(c|d|e)" abc-doc)
=> (#<XdmNode <c>C1</c>>
    #<XdmNode <d>D1</d>>
    #<XdmNode <e>E1</e>>
    #<XdmNode <c>C2</c>>
    #<XdmNode <d>D2</d>>
    #<XdmNode <e>E1</e>>)
13
Pavel Repin