2014-06-22

XPath で名前空間を指定しないと欲しいノードがみつからないとか

結論から言うと *[name()='タグ名'] の一つ覚えでいいわけですが、なんでそうなるかとか。(コードはテストしてないです。typoご容赦)

XMLには名前空間というものがあります。タグの羅列を読み取ったソフトウェアの中では要素というものができることになっているわけですが、その要素は名前空間 URI とローカルパート(コロン以降)で特定されます。逆に言うと名前空間プレフィクス(コロン以前)が違っても同一視されます。

たとえば

  <html xmlns="http://www.w3.org/1999/xhtml">
  <xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <app:html xmlns:app="http://www.w3.org/1999/xhtml">

などなどは、 {http://www.w3.org/1999/xhtml}html (libxml2のスキーマ検証エラーでの表示法)として同一視されます。

一方、ただの <html> は名前空間なし {}html とみなされ、XML としてはまったく別物です。

で、XPath のノードテストの規則をみると、こうだっていうんです。

html
名前空間なしの html 要素つまり {}html だけにマッチする。デフォルト名前空間宣言を使った   <html xmlns="..."> にはマッチしない。
*[local-name()='html']
名前空間の有無・相違を問わず、ローカルパートが html である要素には何でもマッチする。いわば、 {*}html である。
*[local-name()='html' and namespace-uri()='http://www.w3.org/1999/xhtml']
名前空間プレフィクスの有無・相違を問わず、XHTML の html 要素つまり {http://www.w3.org/1999/xhtml}html だけにマッチする。
xhtml:html
名前空間プレフィクスが外から定義されるなら、前項つまり {http://www.w3.org/1999/xhtml}html がこう簡潔にかける。XSLT ならばプログラム全体が XML なので、そこで xmlns:xhtml="http://www.w3.org/1999/xhtml" と書けばよい。XPathの内部には、不幸にしてプレフィクスを定義する構文は無い。
*[name()='html']
名前空間の有無を問わず、実際のタグ名が html である要素には何でもマッチする。
*[name()='xhtml:html']
名前空間の相違を問わず、実際のタグ名が xhtml:html である要素には何でもマッチする。プレフィクスが違えば XHTML であってもマッチしないし、プレフィクスがあっていれば XHTML じゃ無くてもマッチする。

0 件のコメント:

コメントを投稿