E4XのDOM変換

昨日(JavaScript中でのHTML表現にE4Xを提案してみる)の続き

コメントでくれたid:piro_orさんのサンプル

function xmlToDom(xml, xmlns) {
  var doc = (new DOMParser).parseFromString(
    '<root xmlns="' + xmlns + '">' + xml.toXMLString() + "</root>",
    "application/xml");
  var imported = document.importNode(doc.documentElement, true);
  var range = document.createRange();
  range.selectNodeContents(imported);
  var fragment = range.extractContents();
  range.detach();
  return fragment.childNodes.length > 1 ? fragment : fragment.firstChild; 
}

これ、すばらしい。

  1. 全ての要素をきちんとDOM化できる
  2. 内部に他の名前空間の要素があっても対応できる
  3. オイラのxmlToDom関数にはデメリットがある

1. 全ての要素をきちんとDOM化できる

何を当たり前な...と感じるかもしれないけど、オイラが今まで知っていた方法は

function createHTMLDocument(str){
  var htmlFragment = document.implementation.createDocument(null,'html',null);
  var range = document.createRange();
  range.setStartAfter(document.body);
  htmlFragment.documentElement.appendChild(
    htmlFragment.importNode(range.crateContextualFragment(str), true));
  return htmlFragment;
}

というものだった。これだと

var xml = <html>
  <head>
    <title>title</title>
  </head>
  <body>
    <p>hogehoge</p>
  </body>
</html>;
XML.prettyPrinting = false;
var dom = createHTMLDocument(xml.toXMLString());

と作ったときに、何故か、

<html>
  <title>title</title>
  <p>hogehoge<p>
</html>

となってしまって困っていたのだ。それが解消されてきちんと定義どおりのDOMツリーができあがる。

2.内部に他の名前空間の要素があっても対応できる

var xml = <div>
  <p>hogehoge</p>
  <svg xmlns="http://www.w3.org/2000/svg">
    <circle cx="10" cy="10" r="10"/>
  </svg>
</div>;

のようにSVGが含まれていても対応可能でSVGの要素(SVGSVGElement)として作られる。

3. オイラのxmlToDom関数のデメリット

  1. 2で上げた他の名前空間に対応していない
  2. E4XだとCDATAノードもnodeKind()では'text'が返ってしまうためcreateTextNodeされてしまう

もう一度、素晴らしいサンプルをありがとう。