Come posso risolvere $ ref in un oggetto JSON?

5

Ho scritto un'applicazione a singola pagina che utilizza i servizi di riposo per recuperare oggetti JSON. Gli oggetti JSON restituiti sono oggetti C # serializzati utilizzando la libreria Newtonsoft.JSON. L'oggetto JSON restituito contiene $ ref puntatori a specifici $ id oggetti all'interno dello stesso oggetto JSON ( The la domanda qui mostra un esempio ). Ho bisogno di accedere ai dati effettivi a cui punta l'$ ref, ma non so come accedervi senza localizzare la fonte originale.

Ho trovato soluzioni come scrivere un nuovo serializzatore del contratto e scrivere la mia implementazione per risolvere i riferimenti. Sento che dovrebbe esserci una soluzione più semplice di questi due. Ho anche esplorato le impostazioni di serializzazione JSON di Newtonsoft; Ho provato a impostare PreserveReferenceHandling su None, ma non ho avuto alcun successo lì.

Sto cercando soluzioni diverse da quelle che ho menzionato. Spero che esista una soluzione semplice che richiede pochissimo codice da implementare e nessun framework aggiuntivo.

UPDATE

Ne ho letto ancora un po 'e ho scoperto che $ ref è un frammento di Pointer JSON. Il numero di riferimento è un ID che fa riferimento a un elemento da uno schema diverso. Questa sembra essere la soluzione, ma è necessario definire uno schema perché funzioni.

RFC per frammenti di puntatore JSON

Informazioni sui frammenti del puntatore JSON

Riferimenti:
Risoluzione dei riferimenti JSON circolari
< a href="http://james.newtonking.com/json/help/index.html?topic=html/SerializationSettings.htm"> Impostazioni di serializzazione

    
posta Cameron McKay 26.08.2014 - 15:33
fonte

1 risposta

3

Sono stato in grado di risolvere i collegamenti "$ ref" nel mio codice json adattando il codice, questo blogger pubblicato, per essere conforme a Angular.

link

Ho creato un servizio angolare per risolvere il "$ ref" che ottengo dal serializzatore JSON di NewtonSoft.

// http://willseitz-code.blogspot.com/2013/01/javascript-to-deserialize-json-that.html
(function () {
'use strict';

angular
    .module('app')
    .factory('jsonPointerParseService', jsonPointerParseService);

jsonPointerParseService.$inject = [];

function jsonPointerParseService() {
    var hashOfObjects = {};

    var service = {
        pointerParse: pointerParse
    };

    return service;

    function collectIds(obj) {
        if (jQuery.type(obj) === "object") {
            if (obj.hasOwnProperty("$id")) {
                hashOfObjects[obj.$id] = obj;
            }
            for (var prop in obj) {
                collectIds(obj[prop]);
            }
        } else if (jQuery.type(obj) === "array") {
            obj.forEach(function (element) {
                collectIds(element);
            });
        }
    }

    function setReferences(obj) {
        if (jQuery.type(obj) === "object") {
            for (var prop in obj) {
                if (jQuery.type(obj[prop]) === "object" &&
                    obj[prop].hasOwnProperty("$ref")) {
                    obj[prop] = hashOfObjects[obj[prop]["$ref"]];
                } else {
                    setReferences(obj[prop]);
                }
            }
        } else if (jQuery.type(obj) === "array") {
            obj.forEach(function (element, index, array) {
                if (jQuery.type(element) === "object" &&
                    element.hasOwnProperty("$ref")) {
                    array[index] = hashOfObjects[element["$ref"]];
                } else {
                    setReferences(element);
                }
            });
        }
    }

    // Set the max depth of your object graph because JSON.stringify will not be able to
    // serialize a large object graph back to 
    function setMaxDepth(obj, depth) {
        // If this is not an object or array just return there is no need to 
        // set its max depth.
        if (jQuery.type(obj) !== "array" && jQuery.type(obj) !== "object") {
            return obj;
        }

        var newObj = {};

        // If this object was an array we want to return the same type in order
        // to keep this variable's consistency.
        if (jQuery.type(obj) === "array") {
            newObj = [];
        }

        // For each object or array cut off its tree at the depth value by 
        // recursively diving into the tree.
        angular.forEach(obj, function (value, key) {
            if (depth == 1) {
                newObj = null;
            }
            else if (jQuery.type(value) === "array") {
                if (setMaxDepth(value, depth - 1)) {
                    newObj[key] = setMaxDepth(value, depth - 1)
                } else {
                    newObj = [];
                }
            } else if (jQuery.type(value) === "object") {
                if (setMaxDepth(value, depth - 1)) {
                    newObj[key] = setMaxDepth(value, depth - 1)
                } else {
                    newObj = [];
                }
            } else {
                newObj[key] = value;
            }
        }, newObj);

        return newObj;
    }

    function pointerParse(obj, depth) {
        var newObj = obj;

        hashOfObjects = {};
        collectIds(newObj);
        setReferences(newObj);

        if (depth) {
            newObj = setMaxDepth(newObj, depth);
        }

        return newObj;
    }
}
})();

L'utilizzo sarebbe come tale:

 var newObj = jsonPointerParseService.pointerParse(obj);

Si prega di tenere presente, questo è un servizio angolare. Quindi l'ho iniettato in qualsiasi controller che ha bisogno di avere questi riferimenti risolti, e di conseguenza effettuare la chiamata a pointerParse ().

Si noti che se si desidera inviare questo oggetto al server, la chiamata JSON.stringify () del browser deve essere in grado di gestire un oggetto con riferimenti circolari. Per impostazione predefinita, nel mio caso, Angular non chiama JSON.stringify () con i parametri richiesti per essere in grado di stringificare un oggetto con riferimenti circolari. Quindi, in questo caso, suggerirei di postare solo una piccola porzione di dati e non restituire l'intero oggetto o creare un'istanza della propria chiamata per stringificare un oggetto come questo.

Infine, devo dire che trattare con $ ref è un dolore e ho deciso di mantenere la gestione dei riferimenti con solo array. Questo sembrava funzionare bene per me. Avevo ancora bisogno di accedere ai valori dell'array con $ values, tuttavia non dovevo preoccuparmi di risolvere i riferimenti e non dovevo preoccuparmi che il server facesse esplodere tentando di serializzare tutti i riferimenti circolari dell'oggetto a json.

json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;

json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Arrays;

Aggiornamento: anche con i soli array di risoluzione ci sono ancora riferimenti che potrebbe essere necessario risolvere. In questi casi usa la funzione pointerParse () per prenderti cura di loro.

    
risposta data 08.10.2015 - 23:25
fonte

Leggi altre domande sui tag