■
- B.4 Namespace URI Lookup(Namespace Algorithms)
Node.lookupNamespaceURIメソッドはこのように名前空間URIを解決するらしい。実装がこの手順をきちんと守るのであれば、先ほどのようなものに書き換えても問題は起こらないはず。むしろ軽量化を図れるのではないか。逆に、evaluateメソッドでノードテストのQNameを評価する際に、毎度このプロセスが行われるのだとしたら、相当に遅くなるのではないか。
なんだかいい加減な用語連発でダラダラ書いてしまったけれども、きちんと纏めておきたいところ。
- Hawk'sW3L: XMLメモ
prefix無しの名前空間をもったノードをQNameで表現できないなんて馬鹿な話があったとしたら、DOM level 3 XPathは屑だと思った。まだ勧告されていないけれど。
全く信じられなかったので、読みたくないDocument Object Model (DOM) Level 3 XPath Specification(31 March 2003)を真面目に読んでみたのだけれど、もう驚きの一言。目が覚めたよ。
隅から隅まで読んだけれど、「QName」の一言も出てこない。prefixから名前空間を解決する際、Node.lookupNamspaceURIメソッドと似た方法で行うそうで(それくらいしか書かれていない)、この引数にprefixを与えると、そのノードのスコープ内でprefixで関連付けられた名前空間URIを得られる。このメソッドがprefix無しの名前空間URIを得るには、引数にnull値を与えるのだそうだ。しかしこのnullをXPathでどう表現するのか。そんなデータ型はノードテストのQNameで表現できない。それどころかXPathにもない。
そもそも「XPathNSResolver」が名前空間の解決をするというのに、このインターフェイスを持ったオブジェクトを作成する唯一のメソッド、 DOMDocument.createNSResolverの引数がNodeだというのだから、これはもう、名前空間接頭辞を事前に知らなければDOMでXPathを使えないということでは。悪あがき的に、node = document.createElementNS('http://www.w3.org/1999/xhtml', 'xht:div'); を作成して、node.lookupNamespaceURI('xht')を試してみたのだけれど、駄目だった。少なくともMozillaの実装では。もし可能だったとしても、prefixと名前空間URIを関連付けるためにノードを作成するなんて馬鹿げた話もない。
で、私の結論としてはこれを解決するにはXPathNSResolverインターフェイスと同じメソッドを持ったオブジェクトを自作すること。JavaScriptで書くと例えばこんな風になる:
var nsresolver = { lookupNamespaceURI: function(prefix){ switch(prefix){ case 'xht': return 'http://www.w3.org/1999/xhtml'; default: break; } } };
これをXPathNSResolverとして渡せば、少なくともMozillaではQName xht:htmlを XHTMLのhtml要素として扱ってくれた。要するに引数のlookupNamesaceURIメソッドを呼んでいるだけであって、型のチェック等はしていないらしい。多分、「本物の」lookupNamespaceURIメソッドを書き換えても大丈夫だろうというかそっちの方が良い。以下実験したコード:
var de = document.documentElement; var type = XPathResult.FIRST_ORDERED_NODE_TYPE; var result = document.evaluate('/xht:html', de, nsresolver, type, null);
参照している「XMLメモ」では、XPathExpression インターフェイスを持ったオブジェクトを生成しているけれども、これはXPath式を使いまわす際に有効な方法で、一度しか使わないならXPathEvaluatorのevaluateメソッドを使うこともできるようだ。上の「document.evaluate()」がそれ。私の場合はそのような使い方のほうが多いと思う。
しかしこんな引数が四つも五つもあるような汚いインターフェイスは常用したくないから、当然別の何かを被せて使用することになる筈。
あーもう驚いた。
ちなみにDOM Level 2/3 標準技術をMSIEで使う(XML読み込みとXPath) @ レナ姫のWeb研究室経由。でもノードテストに主ノード型しか使えないXPathなんて駄目でしょう。絶対に何とかすべきです。
つづきというか修正
function _XPathNSResolver(nsmap, nodeResolver){ this._nsmap = nsmap; this._resolver = nodeResolver? nodeResolver.ownerDocument.createNSResolver(nodeResolver) : null; } _XPathNSResolver.prototype.lookupNamespaceURI = function(prefix){ var v; if (v = this._nsmap[prefix]) return v; if (v = this._resolver) return v.lookupNamespaceURI(prefix); return v; }; var de = document.documentElement; var type = XPathResult.FIRST_ORDERED_NODE_TYPE; var nsresolver = new _XPathNSResolver({xht: "http://www.w3.org/1999/xhtml"}, de); var result = document.evaluate('descendant::xht:*', de, nsresolver, type, null);