堀北真希うさぎ
主な作品
堀北真希うさぎ:平成一桁頃の『オプティマ』CM風にソフトコンタクトレンズをつけている場面と仮想CM動画

ページ案内

異なる文書間でのDOMノードの移転方法。

Ajaxで取得したXML文書を加工して元のHTML文書に組込みたいと言う場合に、インターネットエクスプローラではしばしばトラブルに遭います。

ここでは、その理由と対策、そして制作者が用意しているコード HTTPRequest.js での具体例を解説いたします。

異なる文書間でのDOMノードの移転方法・目次。

Ajaxで頻繁に起こり得る文書間でのノード移転と言う問題。

通常のDOM操作では、元のHTML文書基準のDOMのみを取扱いますので、問題になる事は先ずありませんが、AjaxではHTTPを用いて他のXML文書をDOMの形で取り込めます。

つまり、Ajaxでは複数の文書のDOMを同時に取扱うケースが非常に多いと言う事になります。

例えば、HTTPで読み込んだ他のXML文書から欲しいノードを抽出して、元のHTML文書のDOMに加えたくなる事があります。

また、インタラクティヴなAjaxアプリケーションであれば、逆に閲覧者の入力に合わせて、読み込んだXML文書のDOMにノードを付け加えてそれをサーヴァに送るような事も考えられます。

これらの操作では、いずれも異なる文書間でノードを移転させる行為となりますが、実はこれはインターネットエクスプローラではエラーとなってしまうのです。

いや、実はDOMの仕様に従えば、インターネットエクスプローラの執る措置こそ正しいのであり、他のブラウザが見逃すのが間違っているのです。

Ajaxで起こり得る不正なノード移転の例。

今、

とします。

このとき、以下のようにして、読み込んだXML文書内にある HORIKITA と言うIDを持つ要素を、元のHTML文書のノードに付け加えようとするとエラーとなります。

dest=d.getElementById('KAWAII');
source=x.getElementById('HORIKITA');
dest.appendChild(source);

異なる文書間でのノード移転の何がいけないのか。

DOM第一水準の仕様に拠れば、文書ノード以外のノードには必ずownerDocument プロパティが与えられ、どの文書のノードであるかが示されます。

このプロパティは読み出し専用で、それが作成された文書と結びつけるものとされており、従って変えられる事は考えられません。

もし、異なった文書間でノードを移転しようとすると、このプロパティの値が変わってしまい、作成された文書との結び付きが否定され、結果定義に反する事になってしまいます。

ですから、このプロパティの定義がある以上、異なる文書間でのノードの移転は出来ないと言う事になるのです。

それでは、どうすればノード移転が出来るのか。(平成21年11月25日 更新)

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);
}

コードをご覧になればお分かり頂けるかと思いますが、継ぎ足す側のノードを作成し、移転したいノードが持つ属性をそのまま新ノードにも与え、更に移転元ノードの直下にあるテキストノードは新ノードの子要素として追加し、要素ノードがあればこの処理を再帰的に呼び出して新ノードに継ぎ足します。

そうして完成した新ノードを移転先ノードに継ぎ足す事で目的を果たせると言う事になります。

しらぎくのウェブサイト作成入門サイトマップ



marguerite.site@gmail.com