Serialisieren und deserialisieren Sie Json und Json Array in Unity

95

Ich habe eine Liste von Elementen, die von einer PHP-Datei an Unity mit gesendet werden WWW.

Das WWW.textsieht aus wie:

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

Wo ich das Extra []von der trimme string. Wenn ich versuche, es mit zu analysieren Boomlagoon.JSON, wird nur das erste Objekt abgerufen. Ich habe herausgefunden, dass ich zur deserialize()Liste muss und MiniJSON importiert habe.

Aber ich bin verwirrt, wie zu deserialize()dieser Liste. Ich möchte jedes JSON-Objekt durchlaufen und Daten abrufen. Wie kann ich dies in Unity mit C # tun?

Die Klasse, die ich benutze, ist

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

Nach dem Trimmen des kann []ich den json mit MiniJSON analysieren. Aber es gibt nur das erste zurück 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));
}

Vielen Dank!

dil33pm
quelle
Warum hast du das äußere [und entfernt ]? Das macht es zu einer Liste. Hören Sie einfach auf, das zu entfernen, und deserialisieren Sie es als Array oder Liste, und ich würde erwarten, dass es in Ordnung ist. Bitte posten Sie den Code, den Sie versucht haben.
Jon Skeet
Zeigen Sie uns die Klasse, die für die Deserialisierung verwendet wird. Das Format ist seltsam, warum ist die zweite PlayerId nicht in geschweifte Klammern eingeschlossen? Es sollte auf eine Liste von etwas deserialisieren, wie List<PlayerLocation>, denn dies ist ein Array.
Maximilian Gerhardt
@ MaximilianGerhardt Sorry, die geschweiften Klammern waren ein Tippfehler. Es wurde in der Frage behoben und der Code wurde ebenfalls hinzugefügt. Vielen Dank.
dil33pm
1
Ich denke, es stimmt etwas nicht mit Ihrem Verständnis, wie diese Bibliothek hier die Deserialisierung behandelt. Es ist nicht die übliche Deserialisierung (wie Sie vielleicht gesehen haben Newtonsoft.Json), aber das gibt Json.Deserialize()IMMER ein IDictionary<string,object>an Sie zurück und Sie operieren weiter List<object>. Schauen Sie sich stackoverflow.com/a/22745634/5296568 an . Besorgen Sie sich vorzugsweise einen besseren JSON-Deserializer, der die gewohnte Deserialisierung ausführt.
Maximilian Gerhardt
@ MaximilianGerhardt Ich habe es mit versucht IDictionary<string,object>. Ich kann den Wert herausholen, aber nur den ersten KeyValuePair<>.
dil33pm

Antworten:

241

Unity hat JsonUtility nach dem 5.3.3- Update zu seiner API hinzugefügt . Vergessen Sie alle Bibliotheken von Drittanbietern, es sei denn, Sie tun etwas Komplizierteres. JsonUtility ist schneller als andere Json-Bibliotheken. Aktualisieren Sie auf Unity 5.3.3 oder höher und probieren Sie die folgende Lösung aus.

JsonUtilityist eine leichte API. Es werden nur einfache Typen unterstützt. Es ist nicht Sammlungen wie Wörterbücher unterstützen. Eine Ausnahme ist List. Es unterstützt Listund ListArray!

Wenn Sie eine Datierung serialisieren Dictionaryoder etwas anderes tun müssen, als nur einfache Datentypen zu serialisieren und zu deserialisieren, verwenden Sie eine API eines Drittanbieters. Andernfalls lesen Sie weiter.

Beispielklasse zum Serialisieren:

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

1. EIN DATENOBJEKT (NON-ARRAY JSON)

Teil A serialisieren :

Serialisieren Sie mit der public static string ToJson(object obj);Methode an Json .

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

Ausgabe :

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

Serialisierung von Teil B :

Serialisieren Sie mit der public static string ToJson(object obj, bool prettyPrint);Methodenüberladung an Json . Durch einfaches Übergeben truean die JsonUtility.ToJsonFunktion werden die Daten formatiert. Vergleichen Sie die Ausgabe unten mit der Ausgabe oben.

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

Ausgabe :

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

Teil A deserialisieren :

Deserialisieren Sie json mit der public static T FromJson(string json);Methodenüberladung.

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

Teil B deserialisieren :

Deserialisieren Sie json mit der public static object FromJson(string json, Type type);Methodenüberladung.

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

Teil C deserialisieren :

Deserialisieren Sie json mit der public static void FromJsonOverwrite(string json, object objectToOverwrite);Methode. Bei JsonUtility.FromJsonOverwriteVerwendung wird keine neue Instanz des Objekts erstellt, für das Sie deserialisieren. Die übergebene Instanz wird einfach wiederverwendet und ihre Werte überschrieben.

Dies ist effizient und sollte nach Möglichkeit verwendet werden.

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. MEHRERE DATEN (ARRAY JSON)

Ihr Json enthält mehrere Datenobjekte. Zum Beispiel playerIderschien mehr als einmal . Unity's JsonUtilityunterstützt kein Array, da es noch neu ist. Sie können jedoch eine Hilfsklasse dieser Person verwenden, um das Array zum Arbeiten zu bringen JsonUtility.

Erstellen Sie eine Klasse namens JsonHelper. Kopieren Sie den JsonHelper direkt von unten.

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

Json-Array serialisieren :

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

Ausgabe :

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

Json-Array deserialisieren :

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

Ausgabe :

Powai

User2


Wenn dies ein Json-Array vom Server ist und Sie es nicht manuell erstellt haben :

Möglicherweise müssen Sie {"Items":vor der empfangenen Zeichenfolge hinzufügen und }am Ende hinzufügen .

Ich habe dafür eine einfache Funktion erstellt:

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

dann können Sie es verwenden:

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

3.Deserialisieren Sie den Json-String ohne Klasse && De-Serialisierung von Json mit numerischen Eigenschaften

Dies ist ein Json, der mit einer Zahl oder numerischen Eigenschaften beginnt.

Beispielsweise:

{ 
"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 JsonUtilityunterstützt dies nicht, da die Eigenschaft "15m" mit einer Zahl beginnt. Eine Klassenvariable kann nicht mit einer Ganzzahl beginnen.

Download SimpleJSON.csaus dem Unity- Wiki .

Um die "15m" -Eigenschaft von USD zu erhalten:

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

Um die "15m" -Eigenschaft von ISK zu erhalten:

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

Um die "15m" -Eigenschaft von NZD zu erhalten:

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

Der Rest der Json-Eigenschaften, die nicht mit einer numerischen Ziffer beginnen, kann von Unitys JsonUtility verarbeitet werden.


4. FEHLERSUCHE JsonUtility:

Probleme beim Serialisieren mit JsonUtility.ToJson ?

Leere Zeichenfolge oder " {}" mitJsonUtility.ToJson ?

A . Stellen Sie sicher, dass die Klasse kein Array ist. Wenn dies der Fall ist, verwenden Sie die obige Hilfsklasse mit JsonHelper.ToJsonanstelle vonJsonUtility.ToJson .

B . Hinzufügen[Serializable] die Spitze der Klasse hinzu, die Sie serialisieren.

C . Entfernen Sie die Eigenschaft aus der Klasse. Entfernen Sie beispielsweise in der Variablenpublic string playerId { get; set; } { get; set; } . Unity kann dies nicht serialisieren.

Probleme beim Deserialisieren mit JsonUtility.FromJson ?

A . Wenn Sie erhalten Null, stellen Sie sicher, dass der Json kein Json-Array ist. Wenn dies der Fall ist, verwenden Sie die obige Hilfsklasse mit JsonHelper.FromJsonanstelle von JsonUtility.FromJson.

B . Wenn Sie NullReferenceExceptionbeim Deserialisieren erhalten, fügen Sie [Serializable]an der Spitze der Klasse.

C. Überprüfen Sie bei allen anderen Problemen, ob Ihr JSON gültig ist. Gehen Sie auf diese Seite hier und die json einfügen. Es sollte Ihnen zeigen, ob der JSON gültig ist. Es sollte auch die richtige Klasse mit dem Json generieren. Stellen Sie einfach sicher, dass Sie remove { get; set; } aus jeder Variablen entfernen und [Serializable]oben in jeder generierten Klasse hinzufügen .


Newtonsoft.Json:

Wenn aus irgendeinem Grund Newtonsoft.Json werden muss , dann schauen Sie in die gegabelten Version für die Einheit verwendet hier . Beachten Sie, dass bei Verwendung einer bestimmten Funktion ein Absturz auftreten kann. Achtung.


Zur Beantwortung Ihrer Frage :

Ihre Originaldaten sind

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

Add {"Items": in Front davon dann fügen } Sie am Ende davon.

Code dazu:

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

Jetzt hast du:

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

Um die mehreren Daten von PHP als Arrays zu serialisieren , können Sie dies jetzt tun

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

playerInstance[0] ist Ihre ersten Daten

playerInstance[1] ist Ihre zweite Daten

playerInstance[2] ist Ihre dritte Daten

oder Daten innerhalb der Klasse mit playerInstance[0].playerLoc, playerInstance[1].playerLoc,playerInstance[2].playerLoc ......

Sie können verwenden playerInstance.Length die Länge überprüfen, bevor Sie darauf zugreifen.

HINWEIS: Aus der Klasse entfernen . Wenn Sie haben , wird es nicht funktionieren. Unity's funktioniert NICHT mit Klassenmitgliedern, die als Eigenschaften definiert sind .{ get; set; }player{ get; set; }JsonUtility

Programmierer
quelle
Ich gebe ein Array von Zeilen einer mysqlAbfrage von PHP mit zurück json_encode($row). Die Antwort besteht also aus mehreren JSONObjects im Format [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. Ich habe JsonUtility ausprobiert, aber ich konnte die Objekte nicht deserialisieren und einzelne Json-Objekte abrufen. Wenn du mir dabei helfen kannst.
dil33pm
2
Schauen Sie sich den Code an, den ich oben gepostet habe. Es zeigt Ihnen drei Möglichkeiten, dies zu tun JsonUtility.FromJson. Ich habe vergessen, dir zu sagen, dass du { get; set; }aus der playerKlasse aussteigen sollst . Wenn Sie haben { get; set; }, wird es nicht funktionieren. Vergleichen Sie Ihre playerKlasse mit der, die ich oben gepostet habe, und Sie werden verstehen, was ich sage.
Programmierer
1
Kein Problem. Ich werde dies bearbeiten, wenn Unity Unterstützung für Arrays hinzufügt (was sehr bald ist), sodass Sie diese Helper-Klasse nicht mehr benötigen.
Programmierer
1
Ich würde nicht so weit gehen zu sagen "Vergessen Sie alle Bibliotheken von Drittanbietern". JsonUtility hat Einschränkungen. Es wird kein JSON-Objekt zurückgegeben, für das Sie Aktionen ausführen können. Zum Beispiel bekomme ich eine JSON-Datei und möchte prüfen, ob ein "Erfolgs" -Schlüssel verfügbar ist. Kann nicht tun. Die JsonUtility erfordert, dass der Verbraucher den genauen Inhalt der json-Datei kennt. Auch kein Wörterbuchkonverter. Es macht also einige gute Dinge, aber die Verwendung von Drittanbietern ist weiterhin erforderlich.
Everts
2
Verwenden Sie JsonHelper. Das ist gut. Wenn Sie Json damit erstellen, können Sie Json auch ohne zusätzliche Schritte damit lesen. Das einzige Mal, dass Sie zusätzliche Dinge tun müssen, ist, wenn Sie das JSON-Array vom Server empfangen und das in der Lösung enthalten ist, ist in meiner Antwort. Ein anderer Weg ohne JsonHelperist, die Klasse in eine andere Klasse zu setzen und sie dann zu einer zu machen List. Dies hat für die meisten Menschen funktioniert. Wenn Sie nach einer Möglichkeit suchen, Spieldaten zu speichern und zu laden, sehen Sie sich diese an . Sie laden und speichern mit einer Codezeile.
Programmierer
17

Angenommen, Sie haben einen solchen JSON

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

Um den obigen JSON in Einheit zu analysieren, können Sie ein JSON-Modell wie dieses erstellen.

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

Und dann einfach folgendermaßen analysieren ...

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

Jetzt können Sie den JSON / CODE nach Bedarf ändern. https://docs.unity3d.com/Manual/JSONSerialization.html

Narottam Goyal
quelle
Das funktioniert eigentlich ganz gut, hat es mit einer Klasse wie Symbol zum Laufen gebracht, die auch kein Array ist.
Gennon
4
Ich versuche dies mit Unity 2018, aber das funktioniert nicht: Die Arrays werden nicht analysiert
Jean-Michaël Celerier
Wird in den Einheiten 2018 und 2019 verwendet. Funktioniert hervorragend. Debug.Log(myObject.result[0].symbol[0].data);for(var i = 0; i <= myObject.result.Length - 1; i ++) { Debug.Log(myObject.result[i].type); }foreach (var item in myObject.result) { Debug.Log(item.type); }
Greifen Sie auf
@ Narottam Goyal, Ihre Methode funktioniert in einigen Fällen nicht, auch eine sehr schwierige Lösung für Anfänger, verweisen Sie diese Antwort von mir auf diesen Thread- Link
Juned Khan Momin
@JunedKhanMomin Ihre Antwort macht im Grunde das Gleiche, ohne jedoch die Tatsache anzusprechen, dass es sich bei dieser Frage hier um ein Array auf Stammebene in den JSON-Daten handelt. Im Allgemeinen sollten Sie sich lieber auf die Antwort des Programmierers beziehen, die viel ausführlicher ist.
derHugo
2

Sie müssen hinzufügen [System.Serializable]zu PlayerItemKlasse, wie folgt aus :

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

Schneiden Sie das nicht []und es sollte Ihnen gut gehen. []Identifizieren Sie ein JSON-Array, das genau das ist, was Sie benötigen, um seine Elemente iterieren zu können.

Thomas Hilbert
quelle
0

Wie @Maximiliangerhardt sagte, hat MiniJson nicht die Fähigkeit, richtig zu deserialisieren. Ich habe JsonFx verwendet und arbeite wie ein Zauber. Arbeitet mit dem[]

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);
dil33pm
quelle
0

Informationen zum Lesen der JSON-Datei finden Sie in diesem einfachen Beispiel

Ihre JSON-Datei (StreamingAssets / Player.json)

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

C # -Skript

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;
}
Juned Khan Momin
quelle
1
Was ist mit Arrays? Und was fügt diese Antwort hinzu, die in der akzeptierten Antwort von vor über 3 Jahren noch nicht erwähnt wurde?
derHugo
0

Sie können Newtonsoft.Jsoneinfach Newtonsoft.dllzu Ihrem Projekt hinzufügen und das folgende Skript verwenden

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

    }
}

Geben Sie hier die Bildbeschreibung ein

Eine andere Lösung ist die Verwendung von 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);

    }
}

Geben Sie hier die Bildbeschreibung ein

Seyed Morteza Kamali
quelle
0

Wenn Sie Vector3 verwenden, habe ich dies getan

1- Ich erstelle eine Klasse Name it Player

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

}

2- dann nenne ich es so

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- und das ist das Ergebnis

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

Gara
quelle
0

Einheit <= 2019

Narottam Goyal hatte eine gute Idee, das Array in ein JSON-Objekt zu verpacken und dann in eine Struktur zu deserialisieren. Im Folgenden werden Generika verwendet, um dies für Arrays aller Art zu lösen, anstatt jedes Mal eine neue Klasse zu erstellen.

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

Es kann folgendermaßen verwendet werden:

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

Einheit 2020

In Unity 2020 gibt es ein offizielles NewtonSoft- Paket, eine weitaus bessere JSON-Bibliothek.

Justin Meiners
quelle