Ajaxで取得したXML文書を加工して元のHTML文書に組込みたいと言う場合に、インターネットエクスプローラではしばしばトラブルに遭います。
ここでは、その理由と対策、そして制作者が用意しているコード HTTPRequest.js での具体例を解説いたします。
通常のDOM操作では、元のHTML文書基準のDOMのみを取扱いますので、問題になる事は先ずありませんが、AjaxではHTTPを用いて他のXML文書をDOMの形で取り込めます。
つまり、Ajaxでは複数の文書のDOMを同時に取扱うケースが非常に多いと言う事になります。
例えば、HTTPで読み込んだ他のXML文書から欲しいノードを抽出して、元のHTML文書のDOMに加えたくなる事があります。
また、インタラクティヴなAjaxアプリケーションであれば、逆に閲覧者の入力に合わせて、読み込んだXML文書のDOMにノードを付け加えてそれをサーヴァに送るような事も考えられます。
これらの操作では、いずれも異なる文書間でノードを移転させる行為となりますが、実はこれはインターネットエクスプローラではエラーとなってしまうのです。
いや、実はDOMの仕様に従えば、インターネットエクスプローラの執る措置こそ正しいのであり、他のブラウザが見逃すのが間違っているのです。
今、
xdとします。
このとき、以下のようにして、読み込んだXML文書内にある HORIKITA と言うIDを持つ要素を、元のHTML文書のノードに付け加えようとするとエラーとなります。
dest=d.getElementById('KAWAII');source=x.getElementById('HORIKITA');dest.appendChild(source);
DOM第一水準の仕様に拠れば、文書ノード以外のノードには必ずownerDocument プロパティが与えられ、どの文書のノードであるかが示されます。
このプロパティは読み出し専用で、それが作成された文書と結びつけるものとされており、従って変えられる事は考えられません。
もし、異なった文書間でノードを移転しようとすると、このプロパティの値が変わってしまい、作成された文書との結び付きが否定され、結果定義に反する事になってしまいます。
ですから、このプロパティの定義がある以上、異なる文書間でのノードの移転は出来ないと言う事になるのです。
DOM第二水準では、この問題を解決するため、importNode() メソッドを導入しております。
これを用いれば、簡単にノードを移転させる事が可能になります。但し、実装さえしていればの話しですが。
実際、問題になっているインターネットエクスプローラではこのメソッドは定義されておらず、従ってこの仕様に従った方法では解決策になりません。
このため、原始的な方法で対処するしかないのです。
つまり、移転したいノードを解析して、ノードのタイプ, 名前, 値などを基に継ぎ足したい文書側でノードを作って行き、それを文書に継ぎ足すというやり方を執らざるを得ません。
制作者が Ajax の通信をいちいち書かなくて済むように用意した HTTPRequest.js には、やはりAjaxでは利用する機会が多そうで汎用性もあると言う事から、この処理も用意しております。
具体的にはコードの後半に以下のように書いております。(平成21年11月25日 コード修正)
/********************************************************************************
(別文書の)要素ノードを付け足す処理。
※IEは文書間のノードの移動を許さないため(実は仕様に沿っている)、
このようにノードのデータを一個一個移して行くしかない。
********************************************************************************/
// 平成21年12月 5日更新
function appendOthersNode(o, e) {
var ow=o.ownerDocument || o; //追加先が属する文書
var o1=ow.createElement(e.tagName); //新要素ノード
var i,j;
// 属性。
var a=e.attributes;
j=a.length;
while (--j>=0) {
var a1=a.item(j);
o1.setAttribute(a1.nodeName, a1.nodeValue);
}
var ele=e.childNodes;
var i=-1;
while (++i<ele.length) {
var t=ele[i].nodeType;
// 子要素は新要素に継ぎ足す。
if (t==1) {
appendOthersNode(o1, ele[i]); continue;
}
// 内容テキストの附加。
if (t==3) {
o1.appendChild(ow.createTextNode(ele[i].nodeValue));
continue;
}
// 他のノードはコピー不要(?)。
}
o.appendChild(o1);
}
コードをご覧になればお分かり頂けるかと思いますが、継ぎ足す側のノードを作成し、移転したいノードが持つ属性をそのまま新ノードにも与え、更に移転元ノードの直下にあるテキストノードは新ノードの子要素として追加し、要素ノードがあればこの処理を再帰的に呼び出して新ノードに継ぎ足します。
そうして完成した新ノードを移転先ノードに継ぎ足す事で目的を果たせると言う事になります。
Copyright ©平成21年-平成24年 さいたま・しらぎくさいと 版権所有
marguerite.site@gmail.com