从JSON对象解析循环引用

Fut*_*oad 13 javascript jquery json.net knockout.js

如果我有一个来自json.net的序列化JSON,如下所示:

User:{id:1,{Foo{id:1,prop:1}},
FooList{$ref: "1",Foo{id:2,prop:13}}
Run Code Online (Sandbox Code Playgroud)

我想让淘汰输出超过FooList,但我不知道如何继续,因为$ ref的东西可以抛出东西.

我认为解决方案是通过不使用以某种方式强制所有Foos在FooList中呈现:

PreserveReferencesHandling = PreserveReferencesHandling.Objects
Run Code Online (Sandbox Code Playgroud)

但这似乎很浪费..

Ale*_*yev 26

我发现了一些错误并实现了数组支持:

function resolveReferences(json) {
    if (typeof json === 'string')
        json = JSON.parse(json);

    var byid = {}, // all objects by id
        refs = []; // references to objects that could not be resolved
    json = (function recurse(obj, prop, parent) {
        if (typeof obj !== 'object' || !obj) // a primitive value
            return obj;
        if (Object.prototype.toString.call(obj) === '[object Array]') {
            for (var i = 0; i < obj.length; i++)
                // check also if the array element is not a primitive value
                if (typeof obj[i] !== 'object' || !obj[i]) // a primitive value
                    continue;
                else if ("$ref" in obj[i])
                    obj[i] = recurse(obj[i], i, obj);
                else
                    obj[i] = recurse(obj[i], prop, obj);
            return obj;
        }
        if ("$ref" in obj) { // a reference
            var ref = obj.$ref;
            if (ref in byid)
                return byid[ref];
            // else we have to make it lazy:
            refs.push([parent, prop, ref]);
            return;
        } else if ("$id" in obj) {
            var id = obj.$id;
            delete obj.$id;
            if ("$values" in obj) // an array
                obj = obj.$values.map(recurse);
            else // a plain object
                for (var prop in obj)
                    obj[prop] = recurse(obj[prop], prop, obj);
            byid[id] = obj;
        }
        return obj;
    })(json); // run it!

    for (var i = 0; i < refs.length; i++) { // resolve previously unknown references
        var ref = refs[i];
        ref[0][ref[1]] = byid[ref[2]];
        // Notice that this throws if you put in a reference at top-level
    }
    return json;
}
Run Code Online (Sandbox Code Playgroud)


Gau*_*rav 13

您从服务器接收的json对象包含循环引用.在使用对象之前,您必须首先$ref从对象中删除所有属性,代替$ref : "1"您必须放置此链接指向的对象.

在你的情况下,它可能是指向id为1的User对象

为此你应该在github上查看Douglas Crockfords插件.有一个cycle.js可以帮你完成这项工作.

或者您可以使用以下代码(未测试):

function resolveReferences(json) {
    if (typeof json === 'string')
        json = JSON.parse(json);

    var byid = {}, // all objects by id
        refs = []; // references to objects that could not be resolved
    json = (function recurse(obj, prop, parent) {
        if (typeof obj !== 'object' || !obj) // a primitive value
            return obj;
        if ("$ref" in obj) { // a reference
            var ref = obj.$ref;
            if (ref in byid)
                return byid[ref];
            // else we have to make it lazy:
            refs.push([parent, prop, ref]);
            return;
        } else if ("$id" in obj) {
            var id = obj.$id;
            delete obj.$id;
            if ("$values" in obj) // an array
                obj = obj.$values.map(recurse);
            else // a plain object
                for (var prop in obj)
                    obj[prop] = recurse(obj[prop], prop, obj)
            byid[id] = obj;
        }
        return obj;
    })(json); // run it!

    for (var i=0; i<refs.length; i++) { // resolve previously unknown references
        var ref = refs[i];
        ref[0][ref[1]] = byid[refs[2]];
        // Notice that this throws if you put in a reference at top-level
    }
    return json;
}  
Run Code Online (Sandbox Code Playgroud)

如果有帮助,请告诉我!


JLR*_*she 6

这其实是非常简单的,如果你好好把握JSON.parsereviver参数,。

下面的例子。请参阅浏览器控制台以获取输出,因为StackOverflow的代码段控制台输出将无法提供有关结果的准确图片。

// example JSON
var j = '{"$id":"0","name":"Parent","child":{"$id":"1", "name":"Child","parent":{"$ref":"0"}},"nullValue":null}'

function parseAndResolve(json) {
    var refMap = {};

    return JSON.parse(json, function (key, value) {
        if (key === '$id') { 
            refMap[value] = this;
            // return undefined so that the property is deleted
            return void(0);
        }

        if (value && value.$ref) { return refMap[value.$ref]; }

        return value; 
    });
}

console.log(parseAndResolve(j));
Run Code Online (Sandbox Code Playgroud)