XPath Cookbook

node()と*の違い

//node()

//*

をそれぞれ実行してみればわかるが、node()はテキストノードなどを含めたすべてのノードを、*はNode.ELEMENT_NODEな要素だけを選択する。この違いはパフォーマンスに影響を与えるので、意識して使い分けるのが良い。

なお、 * はattributeとnamespaceを基準点とした場合はそれぞれattributeとnamespaceを選択する(例://@* は全てのAttrを選択する)。 詳細は仕様書でXML Path Language (XPath) - 2.3 ノードテスト

省略シンタックスと非省略、そして少しの応用

// は /descendant-or-self::node()/ の省略形である。/divは/child::divの省略形で、//div[1]は//div[position()=1]を(さらに)省略した形である。この省略されていない形を把握することで、ちょっとした応用ができる。 省略シンタックスの詳細はXML Path Language (XPath) - 2.5 省略シンタックスをどうぞ。

例えば、id="hoge"な要素の親から見て、2つ目のdiv要素以降で5つ目のdivより前のdiv要素を選択

id("hoge")/parent::div/div[position() > 2 and position() < 5]

link rel="next"

//link[@rel="next"]

div class="hoge"

//div[@class="hoge"]

厳密に書くと

//div[contains(concat(" ",normalize-space(@class)," "), " hoge ")]

( normalize-space についての議論はコチラ : SITEINFO中のnormalize-space()削除について )

クラス・セレクタ値で 複数値指定でどちらか一つが含まれる場合(複数値参照)

クラス・セレクタ値で”AAA”もしくは”BBB”を持つ要素を指定する場合

//*[contains(concat(" ", @class, " "), " AAA ") or contains(concat(" ", @class, " "), " BBB ")]

id="hoge"より後

id("hoge")/following-sibling::node()

td align="right"より前

following-sibling::node()[ ./following-sibling::*/descendant-or-self::td[@align="right"] ]

もしくは

following-sibling::node()[ following::td[@align="right"] ]

( via ここよりも後でここより前を指定するXPath - 0x廃棄階層 - 統治局 )

id="content"以下のh1からh6

id("content")//h1 | id("content")//h2 | id("content")//h3 | id("content")//h4 | id("content")//h5 | id("content")//h6

よりも

id("content")/descendant::*[self::h1 or self::h2 or self::h3 or self::h4 or self::h5 or self::h6]

の方が高速。

( via jottit.comのLDRize用XPath - 0x廃棄階層 - 統治局 )

テキストノードにhogeが含まれるaタグ

//a[contains(text(), "hoge")]

例:http://f.hatena.ne.jp/images/fotolife/c/cool_ni_ikou/20080423/20080423015523.gif

テキストノードが「次のxx件」から始まるaタグ

//a[starts-with(text(),"次の")]

例:http://f.hatena.ne.jp/images/fotolife/c/cool_ni_ikou/20080423/20080423015522.gif

コンテキストノードの最後のa要素

//a[last()]

例:http://f.hatena.ne.jp/images/fotolife/c/cool_ni_ikou/20080423/20080423015521.gif

ただし最終ページでは、「コンテキストノードの最後のa要素」は最終ページの一つ前のページを指すことが多いので注意。

コンテキストノードの最後のa要素から一つ前の兄弟要素

//a[last()-1]

例:http://f.hatena.ne.jp/images/fotolife/c/cool_ni_ikou/20080423/20080423020834.gif

演算子"-”(減算)を使うことができる。

ただし、XMLでは名前に - を使用できるため、- 演算子の前に空白を入れなければならないケースがある。

こちらの場合も最終ページではどうなるか確認は必要。

コンテキストノードの最初のa要素

//a[1]

img src="down.gif"かimg src="up.gif"が子孫に含まれるtableの1番目

//img[contains(@src,"down.gif") or contains(@src,"up.gif")]/ancestor::table[1]

上の例はimgを基準にして書かれている。tableを基準にして、子孫にimg src="down.gif"かimg src="up.gif"が含まれるtableの1番目というかたちでも書ける。

//table[1][ descendant::img[contains(@src,"down.gif") or contains(@src,"up.gif")] ]

id関数(id("hoge"))がうまく機能しない場合

ページ内に同じidを持つ要素が2つ以上ある場合(あってはいけないことだが)、id関数は1つ目のidを持つ要素しか選択できない。その場合はclassなどを選択するときと同様に書くしかない。

//div[@id="hoge"]

子にbやfont要素が無いsmall

//small[ not(child::b or child::font) ]

nextLinkを@hrefの数値を見て大きいほうを選ぶ

//a[starts-with(@href,"/page/")][1][number(substring-after(self::a/@href,"/page/")) > number(substring-after(following-sibling::a/@href,"/page/"))] | //a[starts-with(@href,"/page/")][2][number(substring-after(self::a/@href,"/page/")) > number(substring-after(preceding-sibling::a/@href,"/page/"))]

( via こんなXPathはいや - 0x廃棄階層 - 統治局 )

changed September 18, 2014 delete history edit