複数のタグを選択するXPath


132

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

<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、S、DSとEの子であるsのB要素を?

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

a/b/(c|d|e)

私自身の状況では、代わりにちょうどのa/b/、それらの選択に至るまで、クエリCDE私はこれを行うことを避けるしたいと思いますので、ノードは、実際には非常に複雑です。

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

これは可能ですか?

回答:


207

正解は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

2
「または」はfor-eachでは機能しません。代わりに縦線を使用する必要があります '|'
グアスケノ2015年

8
@Guasqueño orは論理演算子です。2つのブール値を操作します。XPath ユニオン演算子|は、2つのノードセットで動作します。これらはまったく異なり、それぞれに特定の使用例があります。を使用すると元の問題| 解決できますが、XPath式を理解するのに時間がかかり、より複雑で困難になります。この回答のより単純な式は、or演算子を使用して必要なノードセットを生成し、XSLT操作の「select」属性で指定でき<xsl:for-each>ます。やってみなよ。
Dimitre Novatchev

4
@JonathanBenn、「名前空間を気にしない」人は、実際にはXMLを気にせず、XMLを使用しません。使用はlocal-name()、我々はその地域の名前を持つすべての要素を選択したい場合は、関係なく、名前空間の要素が入っているだけで正しいですこれは非常にまれなケースです-一般の人々の中の違いについてのケアを行います。kitchen:tableそしてsql:table、または間architecture:columnsql:columnarray:columnmilitary:column
Dimitre Novatchev

2
@DimitreNovatchevあなたは良い点を作る。私は...名前空間はそれほど重要ではないエッジケースであるHTML検査のためのXPathを使用しています
ジョナサンベン

2
それはすごいです。どこでそれを思いつきましたか?
キー

46

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

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

Dimitreの敵対的な意見に反して、OPが名前空間との相互作用を指定していない真空状態では、上記は正しくありません。self::軸は、名前空間の制限がlocal-name()ありません。OPの意図がc|d|e名前空間に関係なくキャプチャすることである場合(問題のORの性質を考えると、これは可能性の高いシナリオでさえあります)、それは「まだ肯定的な投票がある別の答え」であり、これは誤りです。

あなたは定義なしで決定的であることはできませんが、OPが彼の質問を不正確であるように明確にした場合、私は完全に不正確であると私の回答を削除して非常にうれしいです。


3
ここでサードパーティとして話す-個人的には、ユーザーが名前空間に関係のないタグ名を気にする明確な(そして正当な)理由がある場合を除いて、ディミトレの提案がより良い実践であると私は思います。私が異なる名前空間のコンテンツ(おそらく別のツールチェーンで読むことを意図している)に混在させていたドキュメントに対して誰かがこれを行った場合、それらの動作は非常に不適切であると考えます。とは言っても、議論は-あなたが示唆するように-少し不愉快なものです。
Charles Duffy、

4
まさに私が探していたもの。XMLネームスペースが実際に使用されている方法は、厄介な混乱です。/ a / b /(:c |:d | * e)のようなものを指定できないので、あなたのソリューションはまさに必要なものです。純粋主義者は望むすべてを主張することができますが、ユーザーが入力ファイルを生成したものは何でも名前空間をめちゃくちゃにしたので、アプリが壊れることを気にしません。彼らはそれが機能することを望んでいます。
ゴーストライダー2012年

7
私はこれらの2つの答えの違いが何であるかという漠然とした考えしか持っておらず、誰も説明する気になりませんでした。「名前空間制限」とはどういう意味ですか?私が使用した場合local-name()、それはタグが任意の名前空間と一致することを意味しますか?を使用する場合self::、どの名前空間に一致させる必要がありますか?どうすればマッチできOhMy:cますか?
meustrus 2014年

15

なんでa/b/(c|d|e)Saxon XMLライブラリ(Clojureの良さで上手くまとめられています)を試しましたが、うまくいくようです。 abc.xmlOPによって記述されたドキュメントです。

(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>>)

8
はい、それはXPath 2.0のだ

これは私にはうまくいきました。XPath 2.0は、Python 2のlxmlのでHTML構文解析のデフォルトであるようだ
マーティン・バーチ

-1

これが役立つかどうかはわかりませんが、XSLを使用すると、次のようになります。

<xsl:for-each select="a/b">
    <xsl:value-of select="c"/>
    <xsl:value-of select="d"/>
    <xsl:value-of select="e"/>
</xsl:for-each>

このXPathはBノードのすべての子を選択しません。

a/b/*

Calvinに感謝しますが、XSLは使用していません。実際には、Bの下に、選択したくない要素がさらにあります。わかりやすくするために例を更新します。
nickf 2009

ああ、その場合でも、アンナカタには解決策があるようです。
カルバン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.