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")]
例:
テキストノードが「次のxx件」から始まるaタグ
//a[starts-with(text(),"次の")]
例:
コンテキストノードの最後のa要素
//a[last()]
例:
ただし最終ページでは、「コンテキストノードの最後のa要素」は最終ページの一つ前のページを指すことが多いので注意。
コンテキストノードの最後のa要素から一つ前の兄弟要素
//a[last()-1]
例:
演算子"-”(減算)を使うことができる。
ただし、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廃棄階層 - 統治局 )