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">
みたいにバリバリ拡張しているXMLでXPATH使って「あれー、接頭辞無しの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だと不格好だなぁ・・・。XSLTのXPathはそうならないようになっているのかしら・・・・。