今、せっせと誰が使うかわからないJavaScriptライブラリを作成していますが、.NetのXmlSerializerに相当するクラスが欲しくなったので作成(デモ)してみました(jQuery必須)。
ソース:dq-serial.js
基本的には自前で作成したクラスのインスタンスをXMLまたはJSONへシリアライズ(または逆に復元)します。
そのため幾つか癖があります。
- ‘_’から始まる属性はプライベートとみなしてシリアライズの対象外とします。
- プライベートメンバーから’_'を省いた同一名称のメソッドがあれば、getterまたはsetterとみなします。
- 配列の中のプリミティブなオブジェクトは<string />で括られます
具体的には、以下の様になります。
Foo = function() {}
Foo.prototype = {
name: "", //これはパブリックメンバー扱い
_text : "", //これはプライベートメンバー扱い
text: function(value) {
if(!argument.length) { return this._text; } //引数なしならgetter
this._text = value;
}
}
var object = new Foo();
object.name = "Hellow,";
object.text("World");
で、これをシリアル化すると以下の様になります。
<?xml version="1.0" encoding="UTF-8" ?> <root> <name>Hellow,</name> <text>World</text> </root>
で本題?のXML->JSONを実現するには [XML(文字列)→]XML(DOM) → Object [→任意のクラス(必要なら)]→JSONという段階を踏みます。
とりあえず、XML(DOM)からオブジェクトを作成するコードを示しておきます(後はデモをみてくださいorz)。
_preprocess = function (xml, to) {
if (xml.attributes == null) {
return to;
}
for (var i = 0; i < xml.attributes.length; i++) {
var c = xml.attributes[i];
to[c.nodeName] = $(c).text();//クロスブラウザの為にjQuery経由で参照
}
for (var i = 0; i < xml.childNodes.length; i++) {
var c = xml.childNodes[i];
if (c.nodeName == "#text") { //余分な改行を読み飛ばす
continue;
} else if (c.nodeName == "string") { //プリミティブな値の配列に対応
if (!(to instanceof Array)) {
to = [];
}
to.push($(c).text());
} else if (c.childNodes.length == 1 && c.childNodes[0].nodeType != 1) {
if (to[c.nodeName]) {
if (!(to[c.nodeName] instanceof Array)) {
var tmp = to[c.nodeName]; //複数出現した段階で配列化
to = [];
to.push(tmp);
}
to.push($(c).text());
} else {
if (to instanceof Array) {
to.push($(c).text());
} else {
to[c.nodeName] = $(c).text();
}
}
} else {
if (to[c.nodeName]) {
if (!(to[c.nodeName] instanceof Array)) {
var tmp = to[c.nodeName];
to[c.nodeName] = [];
to[c.nodeName].push(tmp);
}
var value = {};
value = _preprocess(c, value);
to[c.nodeName].push(value);
} else {
to[c.nodeName] = {};
to[c.nodeName] = _preprocess(c, to[c.nodeName]);
}
}
}
return to;
}