Titanium は、JavaScript でコードがかけると言っても色々と制約があり、eval() を使うようなライブラリは使用できません。
2013/02/28追記
dom2json に渡すオブジェクトを dom.documentElement に変更しました。dom を直接渡すと、Android でエラーが発生することがあります。
2011/01/18追記
Titanium.include(“TiDOMParser.js”) だと実機のほうでエラーが発生するという報告を頂いたので、TiDomParser に変更しました。合わせて、プログラム中の TiDOMParser を TiDomParser に変更しました。ご報告ありがとうございました。
2010/09/15追記
eval() が使えないと書きましたが、使えることが判明しました。。。KitchenSink のサンプルにもありました。。 僕の環境で動かないと思っていたのは、eval(“1+1”); と試していたからで、eval() の中はコードになるので正確にはセミコロンが必要で、eval(“1+1;”); としないとダメでした。。訂正です。。
XML を JSON にするライブラリに、XML to JSON というライブラリがありますが、内部で eval を使っているため動きません。(中身を書き換えれば動きそうですね。。)
そこで、DOM から JSON に変換する XML.ObjTree というライブラリを元に、Titanium 上で XML を JSON に変換するライブラリを作ってみました。
ライセンスとか気にしたつもりですが、ObjTree のライセンスに引っかかるとかあればご連絡ください。すぐに対応します。
Titanium で XML を JSON に変換する
Titanium 上で XML を JSON に変換するには次のような手順を踏みます。
- XML 文字列を Titanium.XML.parseString() を使って DOM に変換する
- DOM を本ライブラリを使ってパースし、JSON に変換する
もともと、XML.ObjTree というライブラリを使う予定でしたが、Titanium.XML.parseString() で得られるオブジェクトは純粋な DOM ではなく、TiDOMDocument というオブジェクトのため ObjTree をそのままでは使えませんでした。
そこで、一部修正して、内部で TiDOMDocument を処理できるようにしてみました。使い方は次の通り。
Titanium.include("TiDomParser.js"); var parser = new com.hamasyou.XML.TiDomParser(); var dom = Titanium.XML.parseString(xml); var json = parser.dom2Json(dom.documentElement);
バグやおかしな点があれば、コメントください。
Download
ソースコード全文
TiDomParser.js
/** * @author hamasyou * Copyright (C) 2010 hamasyou, INC. All Rights Reserved. * * @License: * This program is free software; you can redistribute it * and/or modify it under the Artistic license. * Or whatever license I choose, which I will do instead of * keeping this documentation like it is. * * @See http://www.kawa.net/works/js/xml/objtree.html - ObjTree.js */ var com = {}; if (typeof(com.hamasyou) == "undefined") com.hamasyou = {}; if (typeof(com.hamasyou.XML) == "undefined") com.hamasyou.XML = {}; (function() { var Node = { ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12 }; var ns = com.hamasyou.XML; ns.TiDomParser = function() { this.initialize.apply(this, arguments); }; ns.TiDomParser.prototype = { initialize: function() { }, dom2Json: function(root) { this.__force_array = {}; if (this.force_array) { for (var i = 0; i < this.force_array.length; i++) { this.__force_array[this.force_array[i]] = 1; } } var json = this._parseElement(root); // parse root node if (this.__force_array[root.nodeName]) { json = [json]; } if (root.nodeType != Node.DOCUMENT_FRAGMENT_NODE) { var tmp = {}; tmp[root.nodeName] = json; // root nodeName json = tmp; } return json; }, _parseElement: function(elem) { if (elem.nodeType == Node.COMMENT_NODE) { return; } if (elem.nodeType == Node.TEXT_NODE || elem.nodeType == Node.CDATA_SECTION_NODE) { var bool = elem.text.match(/[^\x00-\x20\u00A0]/); if (bool == null) return; // ignore white spaces return elem.text; } var retval; var cnt = {}; // parse attributes if (elem.attributes && elem.attributes.length) { retval = {}; for (var i = 0, len = elem.attributes.length; i < len; i++) { var key = elem.attributes.item(i).nodeName; if (typeof(key) != "string") continue; var val = elem.attributes.item(i).nodeValue; if (!val) continue; if (typeof(cnt[key]) == "undefined") cnt[key] = 0; cnt[key]++; this._addNode(retval, key, cnt[key], val); } } // parse child nodes (recursive) if (elem.childNodes && elem.childNodes.length) { var textonly = true; if (retval) textonly = false; // some attributes exists for (var i = 0, len = elem.childNodes.length; i < len && textonly; i++) { var ntype = elem.childNodes.item(i).nodeType; if (ntype == Node.TEXT_NODE || ntype == Node.CDATA_SECTION_NODE) continue; textonly = false; } if (textonly) { if (!retval) retval = ""; for (var i = 0, len = elem.childNodes.length; i < len; i++) { retval += elem.childNodes.item(i).text; } } else { if (!retval) retval = {}; for (var i = 0, len = elem.childNodes.length; i < len; i++) { var key = elem.childNodes.item(i).nodeName; if (typeof(key) != "string") continue; var val = this._parseElement(elem.childNodes.item(i)); if (!val) continue; if (typeof(cnt[key]) == "undefined") cnt[key] = 0; cnt[key]++; this._addNode(retval, key, cnt[key], val); } } } return retval; }, _addNode: function(hash, key, cnts, val) { if (this.__force_array[key]) { if (cnts == 1) hash[key] = []; hash[key][hash[key].length] = val; // push } else if (cnts == 1) { // 1st sibling hash[key] = val; } else if (cnts == 2) { // 2nd sibling hash[key] = [hash[key], val]; } else { // 3rd sibling and more hash[key][hash[key].length] = val; } } }; ns.TiDomParser.VERSION = 0.1; })();