XSLT関数に慣れていると名前空間の仕様に混乱するかもしれないので簡単な説明を書いておく。PHPのバージョンは4.3.4だ。
まずはXHTML文章の名前空間を思い出す。
<?xml version="1.0" encoding="UTF-8"?>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>テストページ</title>
</head>
<body>
<h1>見出し</h1>
<p>本文</p>
</body>
</html>
このXHTML文章(のようなXML文章)はxmlns="http://www.w3.org/1999/xhtml"
という属性によりデフォルトの名前空間が設定されている。html
要素以下の各要素には名前空間接頭辞が付いていないが、それらはデフォルトの名前空間に属していることに注意しなくてはならない。つまり、接頭辞を「xhtml」にすれば(XML文章としては)以下と等価である。
<?xml version="1.0" encoding="UTF-8"?>
<xhtml:html xmlns:xhtml="http://www.w3.org/1999/xhtml">
<xhtml:head>
<xhtml:title>テストページ</xhtml:title>
</xhtml:head>
<xhtml:body>
<xhtml:h1>見出し</xhtml:h1>
<xhtml:p>本文</xhtml:p>
</xhtml:body>
</xhtml:html>
次に、PHPのXpathメソッドで以下のようなXML文章を扱う。
<?xml version="1.0" encoding="UTF-8"?>
<root>
<node>foo</node>
</root>
デフォルトの名前空間が宣言されていないのでnode
ノードが属する名前空間はnullである。このようなノードならば$dom
をDOMオブジェクトだとすれば以下の様に取得できる。
$xpath = $dom->xpath_new_context();
$node = $xpath->xpath_eval("/root/node");
ここまではXSLT関数でのXpathと同じような感覚で扱える。
次に名前接頭辞付きの場合を考える
<?xml version="1.0" encoding="UTF-8"?>
<foo:root xmlns:foo="http://foo/">
<foo:node>bar</foo:node>
</foo:root>
これはXpathの式に接頭辞を付けて
$xpath = $dom->xpath_new_context();
$node = $xpath->xpath_eval("/foo:root/foo:node");
とすれば問題ないように思えるが、これはXpathメソッドでは期待通りに動作しない
XSLT関数では動作するので理由がわからなくて混乱するが、これはPHPの仕様だ。名前接頭辞を持ったノードはマニュアルに載っていないxpath_register_ns()
関数を使ってPHP側で登録しなければ扱えない。引数はxpath_register_ns(context, prefix, uri)
になる。
$xpath = $dom->xpath_new_context();
xpath_register_ns($xpath, "foo", "http://foo/");
$node = $xpath->xpath_eval("/foo:root/foo:node");
ここで注意するのは名前空間のURIが同じならばPHP側での名前接頭辞は任意でかまわないということだ。つまり、下記のコードも期待どおりに動作する。
$xpath = $dom->xpath_new_context();
xpath_register_ns($xpath, "hoge", "http://foo/");
$node = $xpath->xpath_eval("/hoge:root/hoge:node");
XHTMLに話を戻す。始めに書いた通り、XHTML文章の各要素はデフォルトの名前空間に属している。よってXpath系のメソッドで扱う際には名前空間の登録が必要になる。
xpath_register_ns($xpath, "prefix", "http://www.w3.org/1999/xhtml");
PHP側の名前接頭辞に""
は使えないので何かしら適当な名前接頭辞を付けなければならない。
XSLT関数と動作が違う上マニュアルにも載っていない(User Contributed Notesに書いてある)ので気が付かないとかなり混乱するが名前接頭辞を任意に設定できるので分かってさえしまえば便利である。