tohokuaikiのチラシの裏

技術的ネタとか。

XPathではまり

OR(もしくは、和集合)ではまり

XPathで、「タグA、またはタグAの中にB/Cって入ってる場合はA/B/C」ってのを表現したくて、要するに

<root>
<A/>
<A><B><C/></B></A>
</root>

で、//A と //A/B/C って2回書くのが面倒で1回で済ます方法を探してて。

//A[. or B/C] じゃんって思ってたんだけど、なんか違う。。。。そう、これって
「A要素自体、もしくは子供にB/Cって持ってるA要素自体」
って意味だったのに気づくのに時間かかった。

ネームスペースでハマり

XSLTに使うXPathは不慣れなので、PHPでちょいちょいとXPath自体のチェックをしながら使っているんだけど、名前空間でハマリが。

Jaxen 苦闘 (4) :XPath オブジェクトに名前空間コンテキストを設定する - 倭マン's BLOG
に書いてある。

扱う XML 文書が名前空間を使用していて、その名前空間に属するノードを検索したいとき、たとえ XML 文書中で接頭辞を使っていなくても(デフォルト名前空間)、XPath 式では名前空間を指定しなければいけません。

これをやらずに、

<ac:confluence xmlns:ac="http://www.atlassian.com/schema/confluence/4/ac/"
               xmlns:ri="http://www.atlassian.com/schema/confluence/4/ri/"
               xmlns="http://www.atlassian.com/schema/confluence/4/"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

みたいにバリバリ拡張しているXMLXPATH使って「あれー、接頭辞無しのXPath指定が効かない〜〜」と悩んでたわけです。

PHPのDOMXPathのドキュメント読んでて気づいた。
http://cz1.php.net/manual/ja/domxpath.registernamespace.php#105854
結論としては、↑で書いてある通り、デフォルトのネームスペースの接頭辞を登録してやる必要がある。

<?php
$xml = new DomDocument();
$xml->load('data.xml');
$xpath = new DOMXPath($xml);
$rootNamespace = $xml->lookupNamespaceUri($xml->namespaceURI);
$xpath->registerNamespace('x', $rootNamespace);
?>

And then just query:

<?php $elementList = $xpath->query('//x:items/x:name'); ?>

これって、XPathの表現が処理系に依存するわけでXSLTだと不格好だなぁ・・・。XSLTXPathはそうならないようになっているのかしら・・・・。