E4X traps

散々ハマった後でようやく原典に当たった。そのメモ。

toString
p.innerHTML += <b>NG</b>
p.innerHTML += <b>NG</b>.toString()
p.innerHTML += <b>OK</b>.toXMLString()
XML.prototype.toString = function toString()
  this.hasSimpleContent() ? this.text().toString() : this.toXMLString();

hasSimpleContent() かどうかで挙動が変わる。

replace
<_>OK</_>.replace('*', 'NG')
<_>OK</_>.toString().replace('*', 'NG')
javascript:alert([<_>OK</_>.replace('*','NG'),<_>OK</_>.toString().replace('*','NG')])

大抵の文字列メソッドはそのまま呼べるが,XML.prototype.function::replace があるため replace はダメ。

empty element
document.body.innerHTML = <><b style="display:none"></b><b>hoge</b></>

とやると何も表示されない。(<b></b><b/> になり,</b> は省略出来ないので <b style="display:none"><b>hoge</b></b> と解釈される。)
間に何か挟めば問題無い。しかし単に空白だと

<o><x/></o> "<o>\n <x/>\n</o>"
<o><x></x></o> "<o>\n <x/>\n</o>"
<o><x> </x></o> "<o>\n <x></x>\n</o>"
<o>{<x> </x>}</o> "<o>\n <x/>\n</o>"
javascript:alert([<o><x/></o>,<o><x></x></o>,<o><x>&#32;</x></o>,<o>{<x>&#32;</x>}</o>])

なんとも不安定な結果に。

XML.prettyPrinting = true
<x> </x>.toXMLString() //=> '<x></x>'
XML.prettyPrinting = false
<x> </x>.toXMLString() //=> '<x> </x>'

XML.prettyPrinting = false して空白文字の揺れを避けると,今度は子要素無しの <x></x> を作れなくなる。

<x>&#x3000;</x>.toXMLString().replace(/>\s+</g, '><')

とでもするのが無難?

compound assignment with anyname

.* += での要素追加。短く書けるものの効率は悪く

x = <x>t</x>
x.* += <a/> // <x>t<a/></x>
x.* += <b/> // <x>t<a/><b/></x>
x.* += 't'  // <x>t&lt;a/&gt;&lt;b/&gt;t</x>

テキストノードの追加でハマる。

// この三つは同じ意味
x.* += 't'
x.* = x.* + 't'
x.setChildren(x.children() + 't')

x.* += XML('t') でもいいが,こう書くくらいなら x.appendChild('t') で。

appendChild
Array.reduce('123', function(l, d) l.appendChild(<li>{d}</li>), <ol/>)
//=> <ol> <li>1</li> <li>2</li> <li>3</li> </ol>

E4X の追加変更系メソッドは自身を返す。DOM と併用するとややこしい。

XML.ignoreWhitespace

入出力両方*1に影響する。

XML.ignoreWhitespace true false
<> <x/> </>.toXMLString()((XML.prettyPrinting = true)) "<x></x>" "\n<x></x>\n"
XML(' <x/> ') <x/> syntax error

Global なのでタチが悪い。
...toXMLString()」の直前に false, 「XML(...)」の直前に true を心掛ける。

comment and processing-instruction

それぞれ XML.ignoreComments, XML.ignoreProcessingInstructionsfalse にしないと生成できない。

[XML.ignoreComments = XML.ignoreProcessingInstructions = b,
 [<!---->.nodeKind(), <?_?>.nodeKind()]
 for each(b in [true, false])].join(' ')
//=> text,text comment,processing-instruction
type ambiguity
typeof <x/>         //=> "xml"
<x/> instanceof XML //=> false
<x/> ==  <x/>       //=> true
<x/> === <x/>       //=> false

厳密には object だが、 primitive のように振る舞う。

__proto__
typeof <_/>.__proto__.__proto__.__proto__ /*...*/
//=> "xml"

https://bugzilla.mozilla.org/show_bug.cgi?id=634150

E4X@Bugzilla

未完成かつ開発が止まっている。

*1:xml <=> string