Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolve circular references from JSON object

If I have a serialized JSON from json.net like so:

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

I want to have knockout output a foreach over FooList but I am not sure how to proceed because the $ref things could throw things.

I'm thinking the solution would be to somehow force all the Foos to be rendered in the FooList by not using:

PreserveReferencesHandling = PreserveReferencesHandling.Objects

but that seems wasteful..

like image 885
FutuToad Avatar asked Mar 09 '13 15:03

FutuToad


People also ask

How do I remove a circular reference in JSON?

stringify() method. The second parameter enables us to control which values get stringified and which don't. The function removes any circular references from the object, so we don't get an error when passing it to the JSON.

How do you preserve references and handle or ignore circular references in system text JSON?

To preserve references and handle circular references, set ReferenceHandler to Preserve. This setting causes the following behavior: On serialize: When writing complex types, the serializer also writes metadata properties ( $id , $values , and $ref ).

How do you solve a circular reference in oops?

Circular reference occurs when two or more interdependent resources cause lock condition. This makes the resource unusable. To handle the problem of circular references in C#, you should use garbage collection. It detects and collects circular references.

What is circular structure in JSON?

A circular structure is an object that references itself. To be able to stringify such objects, developers can utilize the replacer parameter in the stringify() method, making sure the function that is being passed in, filters out repeated or circular data.


1 Answers

I've found some bugs and implemented arrays support:

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;
}
like image 71
Alexander Vasilyev Avatar answered Oct 16 '22 05:10

Alexander Vasilyev