knockout.js 解析JSON对象中的循环引用

f8rj6qna  于 2022-11-10  发布在  其他
关注(0)|答案(6)|浏览(130)

如果我有一个来自www.example.com的序列化JSONjson.net,如下所示:

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

我想在FooList上敲除输出foreach,但我不确定如何继续,因为$ref可能会抛出一些东西。
我认为解决方案是通过不使用以下命令强制所有Foos在FooList中呈现:

PreserveReferencesHandling = PreserveReferencesHandling.Objects

但那似乎是浪费。

vfh0ocws

vfh0ocws1#

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

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

2ul0zpep2#

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

  • 在您的情况下,它可能指向ID为1的用户对象 *

为此,你应该查看Douglas Crockfords Plugin on 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;
}

如果有用的话告诉我!

wa7juj8i

wa7juj8i3#

如果利用JSON.parsereviver参数,这实际上非常简单。
下面的示例。请查看浏览器控制台的输出,因为StackOverflow的代码片段控制台输出不会提供结果的准确图片。
第一个

a9wyjsp7

a9wyjsp74#

我在 Alexandria ·瓦西里耶夫的回答中遇到了数组校正的麻烦。
我不能评论他的回答(不要自己的名声不够分;- )),所以我不得不添加一个新的答案...(在那里我有一个弹出作为最佳做法,不回答其他答案,只回答原来的问题- 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;
    }
r1wp621o

r1wp621o5#

在可接受的实现中,如果你在检查一个数组时遇到一个原始值,你将返回该值并覆盖该数组。你想继续检查数组的所有元素,并在最后返回数组。

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

mtb9vblg6#

我的解决方案(也适用于数组):
用法:重新生成JsonDotNetObj(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;
}

相关问题