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の場合は空になるようにしてある。

Comment: 0

Comment Form
Name
URL
Comment

Trackback: 0

Trackback URL
http://mayokara.info/note/trackback/320
Attention
スパム対策のため、当エントリへのリンクがないトラックバックをブロックしています。