JavaScript: createDocumentFromJSONString
(GM_)XMLHttpRequestなどで取ってきたJSON文字列をDOMツリーに変換する関数を書いたのでメモ。
var createDocumentFromJSONString = function(str){
var json = (new Function('return (' + str + ');'))(),
jsonDoc = document.implementation.createDocument("", "json", null);
if (json instanceof Array) {
jsonDoc.documentElement.setAttribute("type", "array");
json = { jsonarray: json };
} else if (typeof(json) === "object") {
if (json === null) {
jsonDoc.documentElement.setAttribute("type", "null");
return jsonDoc;
} else {
jsonDoc.documentElement.setAttribute("type", "object");
}
} else {
jsonDoc.documentElement.setAttribute("type", ((typeof(json) === "boolean") ? String(json) : typeof(json)));
jsonDoc.documentElement.textContent = String(json);
return jsonDoc;
}
(function(o, elem){
for (var i in o) {
if (o[i] instanceof Array) {
for (var j=0,l=o[i].length; j<l; j++) {
var tmp = {};
tmp[i] = o[i][j];
arguments.callee(tmp, elem);
};
} else if (typeof(o[i]) === "object") {
var child = jsonDoc.createElement(i);
if (o[i] === null) {
child.setAttribute("type", "null");
} else {
child.setAttribute("type", "object");
arguments.callee(o[i], child);
}
elem.appendChild(child);
} else {
var child = jsonDoc.createElement(i);
child.setAttribute("type", ((typeof(o[i]) === "boolean") ? String(o[i]) : typeof(o[i])));
child.textContent = String(o[i]);
elem.appendChild(child);
}
}
})(json, jsonDoc.documentElement);
return jsonDoc;
};
({
count: "",
title: "",
bookmarks: [{
comment: "",
tags: ["", ""],
timestamp: "",
user: "",
}, {
comment: "",
tags: ["", ""],
timestamp: "",
user: "",
},
...
],
url: "",
...
})
こんな構造のJSONが
<json type="object">
<count type=""></count>
<title type=""></title>
<bookmarks type="object">
<comment type=""></comment>
<tags type=""></tags>
<tags type=""></tags>
<timestamp type=""></timestamp>
<user type=""></user>
</bookmarks>
<bookmarks type="object">
<comment type=""></comment>
<tags type=""></tags>
<tags type=""></tags>
<timestamp type=""></timestamp>
<user type=""></user>
</bookmarks>
...
<url type=""></url>
...
</json>
こんな構造のツリーに変換される(値は邪魔なので省略)。
JavaScriptの構文だとJSONからjson.bookmarks[*].userみたいな抽出がしたいとき、for文で回さないといけない(はず)。
DOMツリーに変換すれば、XPathで//bookmarks/userとできる。
追記
booleanのtrueとstringの"true"などの区別ができるように、type属性にobject/string/number/true/false/null(ルートのみarrayの場合あり・後述)のいずれかの文字列をセットするよう修正。
JSONでは真偽値がbooleanではなくtrue/falseと別々に定義されているようなので、それに従った。
また、ルートがobjectではなくarrayやstringだったときのための前処理を付け加えた。
ルートがarrayだった場合はdocumentElementを複数作れないので
<json type="array">
<jsonarray type="object">
</jsonarray>
<jsonarray type="object">
</jsonarray>
</json>
のようにjsonarray要素が作られ、documentElementのtype属性の値がarrayとなる。
XPathで参照する場合は//jsonarray/userや/json/*/userのようにする(苦肉の策)。
true/falseの場合はtextContentにもtrue/falseという文字列をセットするが、nullの場合は空になるようにしてある。