一応捕捉。
・Firefox、Opera、Safari は (new XMLSerializer).serializeToString(node) で、どんな場合でも(ノードが HTMLElement ではなく、innerHTML を持っていなくとも)シリアライズできます。
・ごくごく簡単なシリアライザは、以下のように書けます。遅いし、空要素の処理もしていませんが。function serializer (node) {
switch (node.nodeType) {
case 1 : // Node.ELEMENT_NODE
return String.prototype.concat.call (
'<', node.tagName, serializeAttributes (node), '>',
serializeChildNodes (node),
'<\/', node.tagName, '>'
);
case 2 : // Node.ATTRIBUTE_NODE
return String.prototype.concat.call (node.name, '="', node.value, '"');
case 3 : // Node.TEXT_NODE
return node.data;
/* 以下、ノードタイプに応じた書式で出力
* ...
*/
default :
return '';
}
}
function serializeAttributes (node) {
var result = [ ], nodes = node.attributes;
for (var i = 0, I = nodes.length; i < I; i++)
if (nodes[i].specified) result.push (' ', serialize (nodes[i]));
return result.join ('');
}
function serializeChildNodes (node) {
var result = [ ], nodes = node.childNodes;
for (var i = 0, I = nodes.length; i < I; i++)
result.push (serialize (nodes[i]));
return result.join ('');
}
・もう少し考慮すれば、各ノードのプロパティには、XML では文脈上許されない文字がありえます。特に、利用者にデータ入力させた場合など、出力時(入力時ではない)に以下のチェックを行わねばなりません。
要素:
・要素名が名前文字列であるかチェック。
・空要素の処理(NET 処理)。
属性:
・属性名が名前文字列であるかチェック。
・属性値内の「<」「&」「'」「"」をエスケープ。
テキスト:
・データ内の「<」「&」「]]>」をエスケープ。
CDATA セクション:
・データ内の「]]>」をエスケープ。
処理命令:
・ターゲット名が名前文字列であり、かつ「/xml/i」以外であるかチェック。
・データ内の「?>」をエスケープ。
コメント:
・データ内の「--」、データ末尾の「-」をエスケープ。
文書型宣言:
・ルート要素の名前と一致しているかチェック。
・外部識別子が適切な文字列であるかどうか。
これでもまだまだ不十分ではあるのですが、一応。