今、せっせと誰が使うかわからない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; }