解决从JSON对象循环引用(Resolve circular references from JSO

2019-07-21 06:09发布

如果我有json.net像这样一个序列化JSON:

User:{id:1,{Foo{id:1,prop:1}},
FooList{$ref: "1",Foo{id:2,prop:13}}

我想有淘汰赛输出过FooList一个foreach,但我不知道如何着手,因为$裁判事情会扔东西。

我想解决办法是莫名其妙地强迫所有FOOS不使​​用在FooList的显示效果:

PreserveReferencesHandling = PreserveReferencesHandling.Objects

但似乎浪费..

Answer 1:

您是从服务器接收JSON对象包含循环引用 。 使用对象之前,你应该先删除所有的$ref从对象属性,是指代替$ref : "1"你必须把此链接所指向的对象。

你的情况可能是它指向的用户对象,其ID为1

对于这一点,你应该看看道格拉斯康乐福插件在github上 。有一个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;
}  

让我知道这是否有助于!



Answer 2:

我发现了一些错误,并实现阵列的支持:

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;
}


Answer 3:

这,如果你趁其实是非常简单的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)); 



Answer 4:

我曾与亚历山大·瓦西里耶夫的答案阵列校正故障。

我不能评论他的答案(不拥有足够的声望点;-)),所以我不得不添加一个新的答案......(这里我有一个弹出式的最佳实践不要对其他的答案回答,只在原来的问题 - BOF)

    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
                return obj[i];
            if ("$ref" in obj[i])
                obj[i] = recurse(obj[i], i, obj);
            else
                obj[i] = recurse(obj[i], prop, obj);
        }
        return obj;
    }


Answer 5:

在接受的执行,如果你正在检查一个数组,并遇到一个原始值,你将返回值和覆盖该阵列。 你想,而不是继续检查所有的数组中的元素,并在年底返回数组。

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;
}


Answer 6:

我的解决方案(适用于阵列以及):

用法:rebuildJsonDotNetObj(jsonDotNetResponse)

代码:

function rebuildJsonDotNetObj(obj) {
    var arr = [];
    buildRefArray(obj, arr);
    return setReferences(obj, arr)
}

function buildRefArray(obj, arr) {
    if (!obj || obj['$ref'])
        return;
    var objId = obj['$id'];
    if (!objId)
    {
        obj['$id'] = "x";
        return;
    }
    var id = parseInt(objId);
    var array = obj['$values'];
    if (array && Array.isArray(array)) {
        arr[id] = array;
        array.forEach(function (elem) {
            if (typeof elem === "object")
                buildRefArray(elem, arr);
        });
    }
    else {
        arr[id] = obj;
        for (var prop in obj) {
            if (typeof obj[prop] === "object") {
                buildRefArray(obj[prop], arr);
            }
        }
    }
}

function setReferences(obj, arrRefs) {
    if (!obj)
        return obj;
    var ref = obj['$ref'];
    if (ref)
        return arrRefs[parseInt(ref)];

    if (!obj['$id']) //already visited
        return obj;

    var array = obj['$values'];
    if (array && Array.isArray(array)) {
        for (var i = 0; i < array.length; ++i)
            array[i] = setReferences(array[i], arrRefs)
        return array;
    }
    for (var prop in obj)
        if (typeof obj[prop] === "object")
            obj[prop] = setReferences(obj[prop], arrRefs)
    delete obj['$id'];
    return obj;
}


文章来源: Resolve circular references from JSON object