
[1] [[DOM水準3]] で定義されている[DFN[[[界面]] [CODE(DOMi)[XPathNSResolver]]]]
は、 [[XPath]] [[式]]を解釈するに当たって[[名前空間接頭辞]]を[[名前空間URI]]
に[[解決]]する必要が生じた時に呼び出される[[メソッド]]
[CODE(DOMm)[[[lookupNamespaceURI]]]] が定義されている[[界面]]です。

[2] 仕様書:
- [[DOM水準3]]
-- [[XPath]] [CODE(DOMi)[XPathNSResolver]] 
<IW:DOM3:"XPath/xpath.html#XPathNSResolver">

[3] 界面:
- '''メソッド [CODE(DOMm)[[[lookupNamespaceURI]]]]''':
[[名前空間接頭辞]]を受け取り、[[名前空間URI]] を返します。

[4] '''[CODE(DOMi)[Node]] の [CODE(DOMm)[XPathNSResolver]]''':
[[DOM水準3]] の [CODE(DOMi)[[[Node]]]] [[界面]]でも
[CODE(DOMm)[lookupNamespaceURI]] メソッドが定義されています。
[CODE(DOMi)[XPathNSResolver]] のメソッドは [CODE(DOMi)[Node]]
のメソッドの subset のような定義になっています。
([CODE(DOMi)[Node]] 界面を直接使わないのは、
[[節点]]を使わなくても名前空間解決ができるようにするためと、
[[DOM水準3]] [[中核]]モジュールの実装がなくても [[XPath]] 
モジュールを使えるようにするためらしいです。)

[5] '''接頭辞無しの既定名前空間''':
[[XPath 1.0]] において[[名前空間接頭辞]]が無い [CODE[[[QName]]]]
([[既定名前空間]]) は [[null名前空間]]に固定されています。
ですから少なくても [[XPath 1.0]] の[[式]]の解釈のために
[CODE(DOMm)[[[lookupNamespaceURI]]]] の引数に [CODE(DOM)[[[null]]]]
や空文字列が渡されることはなく、渡された場合の結果は未定義とされています
[SRC[DOM 水準3 XPath]]。
[WEAK[([CODE(DOMi)[[[Node]]]] 界面の同名のメソッドは [CODE(DOM)[[[null]]]] が渡された場合の動作も定義されています。)]]

[[#comment]]


* 作成

[6] '''節点から作成''':
[CODE(DOMi)[[[XPathEvaluator]]]] [[界面]]で定義されている
[CODE(DOMm)[[[createNSResolver]]]] メソッドは、 [CODE(DOMi)[[[Node]]]]
を受け取って [CODE(DOMi)[[[XPathNSResolver]]]] を作成します。
作成された [CODE(DOMi)[[[XPathNSResolver]]]] は、
[CODE(DOMm)[[[lookupNamespaceURI]]]] メソッドが呼ばれたら
[CODE(DOMi)[[[Node]]]] の [CODE(DOMm)[[[lookupNamespaceURI]]]]
メソッドを呼ぶような動作をします [SRC[DOM 水準3 XPath]]。

[[XML]] の[[要素]]の[[内容]]として書かれている [[XPath]]
の[[式]]を、その[[要素]]における[[名前空間]]の束縛に従って解釈する、
というような場面でこの方法で作成した [CODE(DOMi)[[[XPathNSResolver]]]]
を使うと便利そうです。

[7] '''節点からキャストで作成''':
[[DOM水準3]] の[[中核]]モジュールと [[XPath]]
モジュールの両方に対応した気が利いた 
[WEAK[([Q[[[界面]]]]の概念を持つ言語での)]] [[DOM]]
の実装なら、 [[DOM水準3]] の [CODE(DOMi)[[[Node]]]]
界面を実装した物体が [CODE(DOMi)[[[XPathNSResolver]]]]
界面も実装しているはずです。ですから、
[PRE(example java code)[
resolver = (XPathNSResolver) document.getElementById ("someElement");
]PRE]

のようなことが [WEAK[(>>6 を使わずに)]] できるでしょう。

[8] '''[CODE(DOMm)[lookupNamespaceURI]] メソッドを持った物体を作成''':
[[型]]に関して弱い言語なら、適当に [CODE(DOMi)[[[lookupNamespaceURI]]]]
メソッドを持つ物体を用意すれば OK です。例えば >>7 にある例は
[PRE(example JS code)[
resolver = document.getElementById ("someElement");
]PRE]

のように特に何もしなくても大丈夫です。また、
[PRE(example JS code)[
resolver = {
  lookupNamespaceURI: function (pfx) {
    switch (pfx) {
      case 'xhtml1': return "http://www.w3.org/1999/xhtml";
      case 'xhtml2': return "http://www.w3.org/2002/06/xhtml2/";
      default:       return null;
    }
  }
};
]PRE]

のような感じで物体を作ってもよいです。

* 呼び出し順序

[16] [[Chrome]] も [[Firefox]] も、[[名前空間接頭辞]]それぞれに対して呼び出します。同じ[[名前空間接頭辞]]を複数使ってもキャッシュされたりはせず、毎回呼び出されます。 [TIME[2013-09-28T10:25:25.600Z]] [SRC[>>15]]

[17] [[Chrome]] も [[Firefox]] も基本的には[[式]]の前から後ろへと呼び出していきます。しかし同じ[[ステップ]]内で
[[Firefox]] は[[名前テスト]] → [[述語]]の順に呼び出しますが、 [[Chrome]] は[[述語]] →
[[名前テスト]]の順に呼び出します。[[述語]]が複数ある場合どちらのブラウザーでも前から後ろへと呼び出します。
[TIME[2013-09-28T10:27:24.500Z]] [SRC[>>15]]

[19] 構文エラーがある場合、 [[Chrome]] も [[Firefox]] もその前にある[[名前空間接頭辞]]については呼び出しますが、
それ以後の[[名前空間接頭辞]]は呼び出しません。 [SRC[>>18]] [[Firefox]]
は[[字句解析]]レベルでのエラーがあるとそれ以前の[[名前空間接頭辞]]についても呼び出しませんが、
[[Chrome]] は呼び出します。 [SRC[>>20]] また [[Chrome]] は >>17
の通り[[述語]]を先に処理するので、[[述語]]で構文エラーがあると[[名前テスト]]の[[名前空間接頭辞]]は呼び出されません。
[SRC[>>21]] [TIME[2013-09-28T10:29:18.00Z]]

[23] [[Chrome]] も [[Firefox]] も、 [[QName]] や [[NameTest]] の全体の構文解析が終わってから[[名前空間接頭辞]]について呼び出すようです。 [TIME[2013-09-28T11:20:02.300Z]]

[REFS[
- [15] <http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cscript%3E%0A%20%20document.evaluate%20(%22hoge%3Aaa%2Fhoge%3Abb%2Ffuga%3Acc%5Bab%3Add%5Bbb%3Acc%5D%5D%5Bac%3Aee%5D%2Fxy%3Aaa%22%2C%20document%2C%20function%20(prefix)%20%7B%20w%20(prefix)%20%7D%2C%200%2C%20null)%3B%0A%3C%2Fscript%3E>
- [18] <http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cscript%3E%0A%20%20document.evaluate%20(%22hoge%3Aaa%20%3C%3E%20fuga%3Aaa%22%2C%20document%2C%20function%20(prefix)%20%7B%20w%20(prefix)%20%7D%2C%200%2C%20null)%3B%0A%3C%2Fscript%3E>
- [20] <http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cscript%3E%0A%20%20document.evaluate%20(%22hoge%3Aaa%20%60%20fuga%3Aaa%22%2C%20document%2C%20function%20(prefix)%20%7B%20w%20(prefix)%20%7D%2C%200%2C%20null)%3B%0A%3C%2Fscript%3E>
- [21] <http://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A%3Cscript%3E%0A%20%20document.evaluate%20(%22hoge%3Aaa%5Bfuga%3Aaa%20%2B%5D%22%2C%20document%2C%20function%20(prefix)%20%7B%20w%20(prefix)%20%7D%2C%200%2C%20null)%3B%0A%3C%2Fscript%3E>
]REFS]

* コールバック this 値

[24] [[Firefox]] でも [[Chrome]] でも [CODE(JS)@en[[[Function]]]] を指定した場合の
[[callback this value]] はその[[関数]]自体になるようです。 [TIME[2013-10-07T14:14:52.000Z]]

* 返す値の解釈

[22] [[Chrome]] も [[Firefox]] も [CODE[[[null]]]] が返されると [CODE(JS)@en[[[document.evaluate]]]]
は [CODE(DOM)@en[[[NamespaceError]]]] を返します。 [CODE[[[undefined]]]] 
や[[空文字列]]を含むその他の値は[[名前空間URL]]と解釈するようです。ただし[[空文字列]]はどの[[名前空間]]とも
([[null名前空間]]とも) 一致しません。 [[例外]]を投げると
[[Firefox]] は [CODE(DOM)@en[[[SyntaxError]]]]、 [[Chrome]] は [CODE(DOM)@en[[[NamespaceError]]]]
を返します。 ([CODE(DOM)@en[[[null]]]] と[[例外]]の場合そこで構文解析は終了します。) [TIME[2013-09-28T10:53:58.800Z]]

* 歴史

** [CODE(DOMi)@en[NSResolver]]

[27] [[Selectors API]] ははじめ [[DOM3 XPath]] を参照していましたが、かなり初期に自身で
[DFN[[CODE(DOMi)@en[[[NSResolver]]]]]] を定義するようになりました。

[REFS[
- [26] [CITE[2006/webapi/selectors-api/Overview.html - diff - 1.6]] ([TIME[2013-10-12 08:38:19 +09:00]] 版) <http://dev.w3.org/cvsweb/2006/webapi/selectors-api/Overview.html.diff?r1=1.5;r2=1.6;f=h>
]REFS]

* メモ

[9] 参考:
- [10]
[CITE[XUL Apps > Tips > DOM3 XPathをノードの検索に活用する - outsider reflex]]
<http://piro.sakura.ne.jp/xul/tips/x0032.html>
- [11]
[CITE[Hawk's W3 Laboratory : XML : XPathと名前空間]] 
<http://www.hawk.34sp.com/stdpls/xml/xpath_ns.html>
- [12] [CITE[Hatena::agenda]] <http://d.hatena.ne.jp/jintrick/20031204>

[[XPath]] モジュール全体の使い方は >>10 を見ればよいでしょう。
>>11 と >>12 は名前空間の扱いに少々誤解がみられます。

[13]
[CITE@ja[XPath, $X function, NSResolver < 16 < March < 2006 < nulog, NULL::something : out of the headphone]] ([CODE[2007-06-09 23:04:20 +09:00]] 版) <http://lowreal.net/logs/2006/03/16/1>
([[名無しさん]] [WEAK[2007-06-09 14:07:18 +00:00]])

[14]
[CITE[d:id:quaa]] ([TIME[2007-06-07 22:15:24 +09:00]] 版) <http://d.hatena.ne.jp/quaa/20070604#p1>
([[名無しさん]] [WEAK[2007-06-09 14:07:44 +00:00]])

[25] [[Chrome]] では [[NoInterfaceObject]] ですが [[Firefox]] では
[CODE(JS)@en[window.XPathNSResolver]] が存在します。 [TIME[2013-10-07T14:18:24.00Z]]

[28] [[Chrome]] は [[null]] が指定された時に [CODE(DOMi)@en[[[Node]]]] の[[既定名前空間]]ではなく、
[[null]] を返すようです。この点で [CODE(DOMi)@en[[[Node]]]] の [CODE(DOMm)@en[[[lookupNamespaceURI]]]]
を呼び出すのと結果が異なります。 ([[空文字列]]だとどちらも [[null]] になります。)
[[Firefox]] はどちらでも [[null]] になるので [CODE(DOMi)@en[[[XPathNSResolver]]]]
で特別な処理をしているのかどうかは観測できません。 [TIME[2013-10-12T08:41:39.300Z]]

[29] [CITE@en-US[Selectors API]]
( ([TIME[2007-08-29 13:51:08 +09:00]] 版))
<http://dev.w3.org/cvsweb/~checkout~/2006/webapi/selectors-api/Overview.html?rev=1.28&content-type=text/html;%20charset=utf-8#nsresolver-interface>

[30] [CITE@en[384003 – XPathEvaluator does not accept a Node as NSResolver]]
( ([TIME[2013-11-01 00:13:05 +09:00]] 版))
<https://bugzilla.mozilla.org/show_bug.cgi?id=384003>

[31] [CITE@en[Add the DOM XPath interfaces from the WHATWG wiki]]
([[annevk]]著, [TIME[2019-08-30 17:38:53 +09:00]])
<https://github.com/whatwg/dom/commit/dea5d92156f144faf57d1a5e54a17227139ca3c5>