XPathにおけるノード集合とその他のオブジェクトとの比較 - 徒書

北村さんが引用している仕様書の箇所を読んだら、true() != foo(fooは空のノード集合)は真であると気づきました。この時は各ノードではなくてノード集合foo自身にboolean関数が適用されるようです(true() != false()で真)。MSXML4.0は正しかった。4Suiteの実装が間違い。でも片方がブール値の時だけ処理が違うというのも一貫性が無くて混乱の元だし、Ogbujiさんを責める気にはなれません。私も勘違いしていたわけだし。一応原文もチェック:

If one object to be compared is a node-set and the other is a boolean, then the comparison will be true if and only if the result of performing the comparison on the boolean and on the result of converting the node-set to a boolean using the boolean function is true.

3.4 Booleans(XML Path Language (XPath))より

ふと気づいて青い本(謎)を調べたら、やっぱり勘違いしていました。

XSLTで、同じ属性値を持つ要素の範囲内で連番を振る - 徒書

ここで挙げられている問題について、分かりやすく説明する為に更に条件を絞り込んでみました。fooは空のノード集合です。

  • self::* != foo
  • foo != foo
  • 3 != foo
  • 'あ' != foo

以上、全部偽でした。つまり空のノード集合は、ブール値以外の何と比較しても必ず偽でした。

  • true() != foo

MSXMLでは、このようにブール値と比較したときには、予想通りの結果が得られます。真です。4Suiteライブラリを使用すると偽でした。

ここで私は、3 != foo(偽)にスポットを当ててみました。数値(3)とノード集合foo!= で比較するとき、そのノード集合fooに含まれるの各ノードにnumber関数を適用して、3 に等しくないものが一つでもあれば真になります。number(foo)と比較されるのではないのです(number(foo)なら非数値(NaN)なので、3 != number(foo)は真になりますし)。そしてこのノード集合fooは空ですから、中にノードなんてありません。等しくないものが見つからないわけです。なんだかややこし過ぎて笑ってしまいました。

'あ' != fooも全く同じです。fooというノード集合に含まれるノードの中に、'あ'ない文字列が見つからないので、偽なのです。

self::* != fooにしても同様ですが少し複雑です。self::*内の各ノードの文字列値それぞれと、foo内の各ノードの文字列値それぞれとを比較して、一つでも異なるならばこれは真です。しかし、そもそもfoo内にノードが無いので異なるものを見つけることが出来ず、よって偽になります。

しかし、するとtrue() != fooは何故MSXMLで真になるのでしょうか。foo内の各ノードにboolean関数を適用した結果、その中に、一つでもfalse()がなければtrue() != fooは真にならないはずです。実装の不具合でしょうか。片方がブール値の場合は、各ノードではなくてノード集合自身にboolean関数が適用される

更に、foo = foofoo != fooでは何が行われているのか私にはさっぱりわかりません。

私は以前から書いていますが、XPathXSLTでは、自分の意図する型に明示的に変換して、暗黙の型変換は可能な限り避けるべきだと思います。James Clarkあたり以外。