Serializza e deserializza Json e Json Array in Unity


96

Ho un elenco di elementi inviati da un file PHP all'unità utilizzando WWW.

Gli WWW.textassomiglia:

[
    {
        "playerId": "1",
        "playerLoc": "Powai"
    },
    {
        "playerId": "2",
        "playerLoc": "Andheri"
    },
    {
        "playerId": "3",
        "playerLoc": "Churchgate"
    }
]

Dove taglio l'extra []dal file string. Quando provo ad analizzarlo utilizzando Boomlagoon.JSON, viene recuperato solo il primo oggetto. Ho scoperto di essere deserialize()nella lista e ho importato MiniJSON.

Ma sono confuso su come deserialize()questo elenco. Voglio scorrere ogni oggetto JSON e recuperare i dati. Come posso farlo in Unity usando C #?

La classe che sto usando è

public class player
{
    public string playerId { get; set; }
    public string playerLoc { get; set; }
    public string playerNick { get; set; }
}

Dopo aver tagliato il []sono in grado di analizzare il json utilizzando MiniJSON. Ma sta tornando solo il primo KeyValuePair.

IDictionary<string, object> players = Json.Deserialize(serviceData) as IDictionary<string, object>;

foreach (KeyValuePair<string, object> kvp in players)
{
    Debug.Log(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
}

Grazie!


Perché hai rimosso l'esterno [e ]? Questo è ciò che lo rende un elenco. Smetti di rimuoverlo e deserializzalo come un array o un elenco e mi aspetto che vada bene. Inserisci il codice che hai provato.
Jon Skeet

Mostraci la classe utilizzata per la deserializzazione. Il formato è strano, perché il secondo playerId non è racchiuso tra parentesi graffe? Dovrebbe deserializzarsi in un elenco di qualcosa, come List<PlayerLocation>, perché questo è un array.
Maximilian Gerhardt

@MaximilianGerhardt Siamo spiacenti, le parentesi graffe erano un errore di battitura. Risolto il problema nella domanda e aggiunto anche il codice. Grazie.
dil33pm

1
Penso che ci sia qualcosa di sbagliato nella tua comprensione di come questa libreria qui gestisce la deserializzazione. Non è la solita deserializzazione (come forse vedrai Newtonsoft.Json), ma Json.Deserialize()SEMPRE ti restituisce una IDictionary<string,object>e tu operi List<object>. Guarda stackoverflow.com/a/22745634/5296568 . Preferibilmente, ottieni un deserializzatore JSON migliore che esegua la deserializzazione a cui sei abituato.
Maximilian Gerhardt

@MaximilianGerhardt con cui ho provato IDictionary<string,object>. Sono in grado di ottenere il valore, ma solo il primo KeyValuePair<>.
dil33pm

Risposte:


244

Unity ha aggiunto JsonUtility alla propria API dopo l' aggiornamento 5.3.3 . Dimentica tutte le librerie di terze parti a meno che tu non stia facendo qualcosa di più complicato. JsonUtility è più veloce di altre librerie Json. Aggiorna alla versione Unity 5.3.3 o successiva, quindi prova la soluzione di seguito.

JsonUtilityè un'API leggera. Sono supportati solo i tipi semplici. Esso non supporta le collezioni, come dizionario. Un'eccezione è List. Supporta Liste Listschiera!

Se è necessario serializzare Dictionaryo eseguire operazioni diverse dalla serializzazione e deserializzazione di tipi di dati semplici, utilizzare un'API di terze parti. Altrimenti, continua a leggere.

Classe di esempio da serializzare:

[Serializable]
public class Player
{
    public string playerId;
    public string playerLoc;
    public string playerNick;
}

1. UN OGGETTO DI DATI (JSON NON ARRAY)

Serializzazione della parte A :

Serializza su Json con il public static string ToJson(object obj);metodo.

Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";

//Convert to JSON
string playerToJson = JsonUtility.ToJson(playerInstance);
Debug.Log(playerToJson);

Uscita :

{"playerId":"8484239823","playerLoc":"Powai","playerNick":"Random Nick"}

Serializzazione della parte B :

Serializza in Json con l' public static string ToJson(object obj, bool prettyPrint);overload del metodo. Il semplice passaggio truealla JsonUtility.ToJsonfunzione formatterà i dati. Confronta l'output sotto con l'output sopra.

Player playerInstance = new Player();
playerInstance.playerId = "8484239823";
playerInstance.playerLoc = "Powai";
playerInstance.playerNick = "Random Nick";

//Convert to JSON
string playerToJson = JsonUtility.ToJson(playerInstance, true);
Debug.Log(playerToJson);

Uscita :

{
    "playerId": "8484239823",
    "playerLoc": "Powai",
    "playerNick": "Random Nick"
}

Deserializzazione della parte A :

Deserializza json con l' public static T FromJson(string json);overload del metodo.

string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = JsonUtility.FromJson<Player>(jsonString);
Debug.Log(player.playerLoc);

Deserializzazione della parte B :

Deserializza json con l' public static object FromJson(string json, Type type);overload del metodo.

string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";
Player player = (Player)JsonUtility.FromJson(jsonString, typeof(Player));
Debug.Log(player.playerLoc);

Deserializzazione della parte C :

Deserializza json con il public static void FromJsonOverwrite(string json, object objectToOverwrite);metodo. Quando JsonUtility.FromJsonOverwriteviene utilizzato, non verrà creata alcuna nuova istanza dell'oggetto che si desidera deserializzare. Riutilizzerà semplicemente l'istanza trasmessa e ne sovrascriverà i valori.

Questo è efficiente e dovrebbe essere usato se possibile.

Player playerInstance;
void Start()
{
    //Must create instance once
    playerInstance = new Player();
    deserialize();
}

void deserialize()
{
    string jsonString = "{\"playerId\":\"8484239823\",\"playerLoc\":\"Powai\",\"playerNick\":\"Random Nick\"}";

    //Overwrite the values in the existing class instance "playerInstance". Less memory Allocation
    JsonUtility.FromJsonOverwrite(jsonString, playerInstance);
    Debug.Log(playerInstance.playerLoc);
}

2. DATI MULTIPLI (ARRAY JSON)

Il tuo Json contiene più oggetti dati. Ad esempio è playerIdapparso più di una volta . Unity's JsonUtilitynon supporta l'array poiché è ancora nuovo, ma puoi usare una classe helper di questa persona per far funzionare l' arrayJsonUtility .

Crea una classe chiamata JsonHelper. Copia il JsonHelper direttamente dal basso.

public static class JsonHelper
{
    public static T[] FromJson<T>(string json)
    {
        Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
        return wrapper.Items;
    }

    public static string ToJson<T>(T[] array)
    {
        Wrapper<T> wrapper = new Wrapper<T>();
        wrapper.Items = array;
        return JsonUtility.ToJson(wrapper);
    }

    public static string ToJson<T>(T[] array, bool prettyPrint)
    {
        Wrapper<T> wrapper = new Wrapper<T>();
        wrapper.Items = array;
        return JsonUtility.ToJson(wrapper, prettyPrint);
    }

    [Serializable]
    private class Wrapper<T>
    {
        public T[] Items;
    }
}

Serializzazione di Json Array :

Player[] playerInstance = new Player[2];

playerInstance[0] = new Player();
playerInstance[0].playerId = "8484239823";
playerInstance[0].playerLoc = "Powai";
playerInstance[0].playerNick = "Random Nick";

playerInstance[1] = new Player();
playerInstance[1].playerId = "512343283";
playerInstance[1].playerLoc = "User2";
playerInstance[1].playerNick = "Rand Nick 2";

//Convert to JSON
string playerToJson = JsonHelper.ToJson(playerInstance, true);
Debug.Log(playerToJson);

Uscita :

{
    "Items": [
        {
            "playerId": "8484239823",
            "playerLoc": "Powai",
            "playerNick": "Random Nick"
        },
        {
            "playerId": "512343283",
            "playerLoc": "User2",
            "playerNick": "Rand Nick 2"
        }
    ]
}

Deserializzazione di Json Array :

string jsonString = "{\r\n    \"Items\": [\r\n        {\r\n            \"playerId\": \"8484239823\",\r\n            \"playerLoc\": \"Powai\",\r\n            \"playerNick\": \"Random Nick\"\r\n        },\r\n        {\r\n            \"playerId\": \"512343283\",\r\n            \"playerLoc\": \"User2\",\r\n            \"playerNick\": \"Rand Nick 2\"\r\n        }\r\n    ]\r\n}";

Player[] player = JsonHelper.FromJson<Player>(jsonString);
Debug.Log(player[0].playerLoc);
Debug.Log(player[1].playerLoc);

Uscita :

Powai

Utente2


Se questo è un array Json dal server e non l'hai creato manualmente :

Potrebbe essere necessario aggiungere {"Items":prima della stringa ricevuta, quindi aggiungere }alla fine di essa.

Ho creato una semplice funzione per questo:

string fixJson(string value)
{
    value = "{\"Items\":" + value + "}";
    return value;
}

allora puoi usarlo:

string jsonString = fixJson(yourJsonFromServer);
Player[] player = JsonHelper.FromJson<Player>(jsonString);

3.Deserializza la stringa JSON senza classe && De-serializza Json con proprietà numeriche

Questo è un Json che inizia con un numero o proprietà numeriche.

Per esempio:

{ 
"USD" : {"15m" : 1740.01, "last" : 1740.01, "buy" : 1740.01, "sell" : 1744.74, "symbol" : "$"}, 

"ISK" : {"15m" : 179479.11, "last" : 179479.11, "buy" : 179479.11, "sell" : 179967, "symbol" : "kr"},

"NZD" : {"15m" : 2522.84, "last" : 2522.84, "buy" : 2522.84, "sell" : 2529.69, "symbol" : "$"}
}

Unity's JsonUtilitynon lo supporta perché la proprietà "15m" inizia con un numero. Una variabile di classe non può iniziare con un numero intero.

Scarica SimpleJSON.csdal wiki di Unity .

Per ottenere la proprietà "15 m" di USD:

var N = JSON.Parse(yourJsonString);
string price = N["USD"]["15m"].Value;
Debug.Log(price);

Per ottenere la proprietà "15 m" di ISK:

var N = JSON.Parse(yourJsonString);
string price = N["ISK"]["15m"].Value;
Debug.Log(price);

Per ottenere la proprietà "15 m" di NZD:

var N = JSON.Parse(yourJsonString);
string price = N["NZD"]["15m"].Value;
Debug.Log(price);

Il resto delle proprietà Json che non inizia con una cifra numerica possono essere gestite da JsonUtility di Unity.


4. RISOLUZIONE DEI PROBLEMI JsonUtility:

Problemi durante la serializzazione con JsonUtility.ToJson?

Ricevi una stringa vuota o " {}" con JsonUtility.ToJson?

A . Assicurati che la classe non sia un array. Se lo è, usa la classe helper sopra con JsonHelper.ToJsoninvece di JsonUtility.ToJson.

B . Aggiungi [Serializable]all'inizio della classe che stai serializzando.

C . Rimuovi proprietà dalla classe. Ad esempio, nella variabile, public string playerId { get; set; } rimuovi { get; set; } . Unity non può serializzare questo.

Problemi durante la deserializzazione con JsonUtility.FromJson?

A . In Nulltal caso , assicurati che Json non sia un array Json. Se lo è, usa la classe helper sopra con JsonHelper.FromJsoninvece di JsonUtility.FromJson.

B . Se si ottiene NullReferenceExceptiondurante la deserializzazione, aggiungere [Serializable]in cima alla classe.

C. Eventuali altri problemi, verifica che il tuo json sia valido. Vai su questo sito qui e incolla il file json. Dovrebbe mostrarti se il json è valido. Dovrebbe anche generare la classe corretta con Json. Assicurati solo di rimuovere remove { get; set; } da ogni variabile e aggiungi anche [Serializable]all'inizio di ogni classe generata.


Newtonsoft.Json:

Se per qualche motivo è necessario utilizzare Newtonsoft.Json, controlla la versione biforcuta per Unity qui . Tieni presente che potresti riscontrare un arresto anomalo se viene utilizzata una determinata funzione. Stai attento.


Per rispondere alla tua domanda :

I tuoi dati originali sono

 [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]

Aggiungere {"Items": a fronte di esso poi aggiungere } alla fine di esso.

Codice per fare questo:

serviceData = "{\"Items\":" + serviceData + "}";

Adesso hai:

 {"Items":[{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]}

Per serializzare i molteplici dati dal PHP come array , ora è possibile farlo

public player[] playerInstance;
playerInstance = JsonHelper.FromJson<player>(serviceData);

playerInstance[0] sono i tuoi primi dati

playerInstance[1] sono i tuoi secondi dati

playerInstance[2] è il terzo dato

o dati all'interno della classe con playerInstance[0].playerLoc, playerInstance[1].playerLoc, playerInstance[2].playerLoc......

È possibile utilizzare playerInstance.Lengthper verificare la lunghezza prima di accedervi.

NOTA: rimuovere { get; set; } dalla playerclasse. Se lo hai { get; set; }, non funzionerà. Unity JsonUtilityfa NON lavorare con i membri della classe che sono definiti come proprietà .


Sto restituendo un array di righe di una mysqlquery da PHP utilizzando json_encode($row). Quindi la risposta è costituita da più JSONObject nel formato [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. Ho provato JsonUtility, ma non sono riuscito a deserializzare gli oggetti e ottenere singoli oggetti Json. Se puoi aiutarmi con quello.
dil33pm

2
Guarda il codice che ho postato sopra. Ti mostra tre modi per farlo con JsonUtility.FromJson. Ho dimenticato di dirti di toglierti { get; set; }dalla playerclasse. Se lo hai { get; set; }, non funzionerà. Confronta la tua playerclasse con quella che ho pubblicato sopra e capirai cosa sto dicendo.
Programmatore

1
Nessun problema. Lo modificherò quando Unity aggiunge il supporto per array (che è molto presto), quindi non avrai più bisogno di quella classe Helper.
Programmatore

1
Non mi spingerei a dire "Dimentica tutte le librerie di terze parti". JsonUtility ha dei limiti. Non restituisce un oggetto JSON su cui è possibile eseguire azioni. Ad esempio, ottengo un file json e desidero verificare se è disponibile una chiave di "successo". Non posso farlo. JsonUtility richiede che il consumatore conosca il contenuto esatto del file json. Inoltre, nessun convertitore di dizionario. Quindi fa alcune cose buone, ma è ancora richiesto l'uso di terze parti.
Everts

2
Usa JsonHelper. Va bene. Se crei Json con esso, puoi anche leggere json con esso senza passaggi aggiuntivi. L'unica volta in cui potresti dover fare cose extra è se stai ricevendo l'array json dal server e che è incluso nella soluzione è nella mia risposta. Un altro modo senza JsonHelperè mettere la classe in un'altra classe e poi renderla a List. Questo ha funzionato per la maggior parte delle persone. Se stai cercando un modo per salvare e caricare i dati di gioco, guarda questo . Si carica e si salva con una riga di codice.
Programmatore

17

Supponi di avere un JSON come questo

[
    {
        "type": "qrcode",
        "symbol": [
            {
                "seq": 0,
                "data": "HelloWorld9887725216",
                "error": null
            }
        ]
    }
]

Per analizzare il JSON di cui sopra in unità, puoi creare un modello JSON come questo.

[System.Serializable]
public class QrCodeResult
{
    public QRCodeData[] result;
}

[System.Serializable]
public class Symbol
{
    public int seq;
    public string data;
    public string error;
}

[System.Serializable]
public class QRCodeData
{
    public string type;
    public Symbol[] symbol;
}

E quindi analizza semplicemente nel modo seguente ...

var myObject = JsonUtility.FromJson<QrCodeResult>("{\"result\":" + jsonString.ToString() + "}");

Ora puoi modificare il codice JSON / CODE in base alle tue esigenze. https://docs.unity3d.com/Manual/JSONSerialization.html


In realtà funziona abbastanza bene, ha funzionato con una classe come Symbol che non è anche un array.
Gennon

4
Lo sto provando con Unity 2018 ma non funziona: gli array non vengono analizzati
Jean-Michaël Celerier

Utilizzato nell'unità 2018 e 2019. Funziona alla grande. Accedi ai dati dell'array come: Debug.Log(myObject.result[0].symbol[0].data);o for(var i = 0; i <= myObject.result.Length - 1; i ++) { Debug.Log(myObject.result[i].type); }oforeach (var item in myObject.result) { Debug.Log(item.type); }
Towerss

@Narottam Goyal, il tuo metodo non funziona in alcuni casi, anche una soluzione molto difficile per i principianti, fai riferimento a questa risposta da me su questo link
Juned Khan Momin

@ JunedKhanMomin la tua risposta fa fondamentalmente lo stesso, ma senza affrontare il fatto che questa domanda qui riguardava un array a livello di radice nei dati JSON in particolare. In generale dovresti piuttosto fare riferimento alla risposta del programmatore che è molto più elaborata.
derHugo

2

devi aggiungere [System.Serializable]alla PlayerItemclasse, in questo modo:

using System;
[System.Serializable]
public class PlayerItem   {
    public string playerId;
    public string playerLoc;
    public string playerNick;
}

0

Non tagliare il []e dovresti stare bene. []identificare un array JSON che è esattamente ciò di cui hai bisogno per essere in grado di iterare i suoi elementi.


0

Come ha detto @Maximiliangerhardt, MiniJson non ha la capacità di deserializzare correttamente. Ho usato JsonFx e funziona a meraviglia. Funziona con[]

player[] p = JsonReader.Deserialize<player[]>(serviceData);
Debug.Log(p[0].playerId +" "+ p[0].playerLoc+"--"+ p[1].playerId + " " + p[1].playerLoc+"--"+ p[2].playerId + " " + p[2].playerLoc);

0

Per leggere il file JSON, fare riferimento a questo semplice esempio

Il tuo file JSON (StreamingAssets / Player.json)

{
    "Name": "MyName",
    "Level": 4
}

Script C #

public class Demo
{
    public void ReadJSON()
    {
        string path = Application.streamingAssetsPath + "/Player.json";
        string JSONString = File.ReadAllText(path);
        Player player = JsonUtility.FromJson<Player>(JSONString);
        Debug.Log(player.Name);
    }
}

[System.Serializable]
public class Player
{
    public string Name;
    public int Level;
}

1
E gli array? E cosa aggiunge questa risposta che non era già menzionata nella risposta accettata di oltre 3 anni fa?
derHugo

0

Puoi usare Newtonsoft.Jsonsolo aggiungere Newtonsoft.dllal tuo progetto e usare lo script sottostante

using System;
using Newtonsoft.Json;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{

    [Serializable]
    public class Person
    {
        public string id;
        public string name;
    }
    public Person[] person;

    private void Start()
    {
       var myjson = JsonConvert.SerializeObject(person);

        print(myjson);

    }
}

inserisci qui la descrizione dell'immagine

un'altra soluzione sta usando JsonHelper

using System;
using Newtonsoft.Json;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{

    [Serializable]
    public class Person
    {
        public string id;
        public string name;
    }
    public Person[] person;

    private void Start()
    {
        var myjson = JsonHelper.ToJson(person);

        print(myjson);

    }
}

inserisci qui la descrizione dell'immagine


0

SE stai usando Vector3 questo è quello che ho fatto

1- Creo una classe Name it Player

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[Serializable]
public class Player
{
    public Vector3[] Position;

}

2- allora lo chiamo così

if ( _ispressed == true)
        {
            Player playerInstance = new Player();
            playerInstance.Position = newPos;
            string jsonData = JsonUtility.ToJson(playerInstance);

            reference.Child("Position" + Random.Range(0, 1000000)).SetRawJsonValueAsync(jsonData);
            Debug.Log(jsonData);
            _ispressed = false;
        }

3- e questo è il risultato

"Posizione": [{"x": - 2.8567452430725099, "y": - 2.4323320388793947, "z": 0.0}]}


0

Unità <= 2019

Narottam Goyal ha avuto una buona idea di avvolgere l'array in un oggetto json e quindi deserializzarlo in una struttura. Quanto segue usa Generics per risolvere questo problema per array di tutti i tipi, invece di creare una nuova classe ogni volta.

[System.Serializable]
private struct JsonArrayWrapper<T> {
    public T wrap_result;
}

public static T ParseJsonArray<T>(string json) {
    var temp = JsonUtility.FromJson<JsonArrayWrapper<T>>("{\" wrap_result\":" + json + "}");
    return temp.wrap_result;
}

Può essere utilizzato nel modo seguente:

string[] options = ParseJsonArray<string[]>(someArrayOfStringsJson);

Unità 2020

In Unity 2020 c'è un pacchetto newtonsoft ufficiale che è una libreria json molto migliore.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.