Sérialiser et désérialiser Json et Json Array dans Unity

97

J'ai une liste d'éléments envoyés depuis un fichier PHP vers unity en utilisant WWW.

Le WWW.textressemble à:

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

Où je coupe le supplément []du string. Lorsque j'essaye de l'analyser en utilisant Boomlagoon.JSON, seul le premier objet est récupéré. J'ai découvert que je suis sur deserialize()la liste et que j'ai importé MiniJSON.

Mais je ne sais pas comment deserialize()cette liste. Je veux parcourir chaque objet JSON et récupérer des données. Comment puis-je faire cela dans Unity en utilisant C #?

La classe que j'utilise est

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

Après avoir coupé le, []je suis capable d'analyser le json en utilisant MiniJSON. Mais il ne renvoie que le premier 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));
}

Merci!

dil33pm
la source
Pourquoi avez-vous supprimé l'extérieur [et ]? C'est ce qui en fait une liste. Arrêtez simplement de supprimer cela et désérialisez-le sous forme de tableau ou de liste et je m'attendrais à ce que tout se passe bien. Veuillez publier le code que vous avez essayé.
Jon Skeet
Montrez-nous la classe utilisée pour la désérialisation. Le format est bizarre, pourquoi le deuxième playerId n'est-il pas entouré d'accolades? Il devrait se désérialiser en une liste de quelque chose, comme List<PlayerLocation>, car il s'agit d' un tableau.
Maximilian Gerhardt
@MaximilianGerhardt Désolé, les accolades étaient une faute de frappe. Correction de cela dans la question et ajout du code également. Merci.
dil33pm
1
Je pense qu'il y a quelque chose qui ne va pas avec votre compréhension de la façon dont cette bibliothèque gère ici la désérialisation. Ce n'est pas la désérialisation habituelle (comme vous l'avez peut-être vu Newtonsoft.Json), mais Json.Deserialize()TOUJOURS vous renvoie un IDictionary<string,object>et vous opérez List<object>. Regardez stackoverflow.com/a/22745634/5296568 . De préférence, obtenez un meilleur désérialiseur JSON qui effectue la désérialisation à laquelle vous êtes habitué.
Maximilian Gerhardt
@MaximilianGerhardt j'ai essayé avec IDictionary<string,object>. Je suis capable d'en tirer la valeur, mais seulement le premier KeyValuePair<>.
dil33pm

Réponses:

246

Unity a ajouté JsonUtility à son API après la mise à jour 5.3.3 . Oubliez toutes les bibliothèques tierces à moins que vous ne fassiez quelque chose de plus compliqué. JsonUtility est plus rapide que les autres bibliothèques Json. Mettez à jour vers la version Unity 5.3.3 ou supérieure, puis essayez la solution ci-dessous.

JsonUtilityest une API légère. Seuls les types simples sont pris en charge. Il ne prend pas en charge les collections telles que Dictionary. Une exception est List. Il prend en charge Listet Listtableau!

Si vous devez sérialiser un Dictionaryou faire autre chose que simplement sérialiser et désérialiser des types de données simples, utilisez une API tierce. Sinon, continuez à lire.

Exemple de classe à sérialiser:

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

1. UN OBJET DE DONNÉES (JSON NON-ARRAY)

Sérialisation de la partie A :

Sérialisez vers Json avec la public static string ToJson(object obj);méthode.

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

Sortie :

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

Sérialisation de la partie B :

Sérialisez vers Json avec la public static string ToJson(object obj, bool prettyPrint);surcharge de méthode. Le simple fait de passer trueà la JsonUtility.ToJsonfonction formatera les données. Comparez la sortie ci-dessous à la sortie ci-dessus.

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

Sortie :

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

Désérialisation de la partie A :

Désérialisez json avec la public static T FromJson(string json);surcharge de méthode.

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

Désérialisation de la partie B :

Désérialisez json avec la public static object FromJson(string json, Type type);surcharge de méthode.

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

Désérialisation de la partie C :

Désérialisez json avec la public static void FromJsonOverwrite(string json, object objectToOverwrite);méthode. Quand JsonUtility.FromJsonOverwriteest utilisé, aucune nouvelle instance de cet objet que vous désérialisez ne sera créée. Il réutilisera simplement l'instance que vous transmettez et écrasera ses valeurs.

Ceci est efficace et doit être utilisé si possible.

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. DONNÉES MULTIPLES (ARRAY JSON)

Votre Json contient plusieurs objets de données. Par exemple playerIdest apparu plus d' une fois . Unity JsonUtilityne prend pas en charge le tableau car il est encore nouveau, mais vous pouvez utiliser une classe d' assistance de cette personne pour faire fonctionner le tableauJsonUtility .

Créez une classe appelée JsonHelper. Copiez le JsonHelper directement à partir du dessous.

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

Sérialisation de la baie Json :

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

Sortie :

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

Désérialisation de 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);

Sortie :

Powai

Utilisateur2


S'il s'agit d'un tableau Json du serveur et que vous ne l'avez pas créé à la main :

Vous devrez peut-être ajouter {"Items":devant la chaîne reçue, puis ajouter }à la fin de celle-ci.

J'ai fait une fonction simple pour cela:

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

alors vous pouvez l'utiliser:

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

3. désérialiser la chaîne json sans classe && désérialiser Json avec des propriétés numériques

Il s'agit d'un Json qui commence par un nombre ou des propriétés numériques.

Par exemple:

{ 
"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 JsonUtilityne prend pas en charge cela car la propriété "15m" commence par un nombre. Une variable de classe ne peut pas commencer par un entier.

Téléchargez à SimpleJSON.cspartir du wiki d'Unity .

Pour obtenir la propriété "15m" de USD:

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

Pour obtenir la propriété "15m" d'ISK:

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

Pour obtenir la propriété "15m" de NZD:

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

Le reste des propriétés Json qui ne commencent pas par un chiffre numérique peuvent être gérés par JsonUtility d'Unity.


4.DÉPANNAGE JsonUtility:

Problèmes lors de la sérialisation avec JsonUtility.ToJson?

Obtenir une chaîne vide ou " {}" avec JsonUtility.ToJson?

A . Assurez-vous que la classe n'est pas un tableau. Si tel est le cas, utilisez la classe d'assistance ci-dessus avec JsonHelper.ToJsonau lieu de JsonUtility.ToJson.

B . Ajoutez [Serializable]en haut de la classe que vous sérialisez.

C . Supprimez la propriété de la classe. Par exemple, dans la variable, public string playerId { get; set; } supprimez { get; set; } . Unity ne peut pas sérialiser cela.

Problèmes lors de la désérialisation avec JsonUtility.FromJson?

A . Si vous obtenez Null, assurez-vous que Json n'est pas un tableau Json. Si tel est le cas, utilisez la classe d'assistance ci-dessus avec JsonHelper.FromJsonau lieu de JsonUtility.FromJson.

B . Si vous obtenez NullReferenceExceptionlors de la désérialisation, ajoutez [Serializable]en haut de la classe.

C. Pour tout autre problème, vérifiez que votre json est valide. Allez sur ce site ici et collez le fichier json. Il devrait vous montrer si le json est valide. Il devrait également générer la classe appropriée avec le Json. Assurez-vous simplement de supprimer remove { get; set; } de chaque variable et d'ajouter également [Serializable]en haut de chaque classe générée.


Newtonsoft.Json:

Si pour une raison quelconque Newtonsoft.Json doit être utilisé, consultez la version fourchue pour Unity ici . Notez que vous pouvez rencontrer des plantages si certaines fonctionnalités sont utilisées. Faites attention.


Pour répondre à votre question :

Vos données d'origine sont

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

Ajouter {"Items": à l' avant de celui - ci , puis ajouter } à la fin de celui - ci.

Code pour ce faire:

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

Maintenant vous avez:

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

Pour sérialiser les multiples données de php sous forme de tableaux , vous pouvez maintenant faire

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

playerInstance[0] est vos premières données

playerInstance[1] est votre deuxième donnée

playerInstance[2] est votre troisième donnée

ou des données à l' intérieur de la classe playerInstance[0].playerLoc, playerInstance[1].playerLoc, playerInstance[2].playerLoc......

Vous pouvez utiliser playerInstance.Lengthpour vérifier la longueur avant d'y accéder.

REMARQUE: retirez { get; set; } de la playerclasse. Si c'est le cas { get; set; }, cela ne fonctionnera pas. Unity JsonUtilityne fonctionne PAS avec les membres de classe définis comme propriétés .

Programmeur
la source
Je retourne un tableau de lignes d'une mysqlrequête de PHP en utilisant json_encode($row). La réponse se compose donc de plusieurs JSONObjects au format [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. J'ai essayé JsonUtility, mais je ne pouvais pas désérialiser les objets et obtenir des objets json individuels. Si vous pouvez m'aider avec ça.
dil33pm
2
Regardez le code que j'ai posté ci-dessus. Il vous montre trois façons de faire cela avec JsonUtility.FromJson. J'ai oublié de vous dire de vous retirer { get; set; }de la playerclasse. Si vous en avez { get; set; }, cela ne fonctionnera pas. Comparez votre playerclasse avec celle que j'ai postée ci-dessus et vous comprendrez ce que je dis.
Programmeur
1
Aucun problème. Je modifierai cela lorsque Unity ajoutera la prise en charge de array (ce qui est très bientôt) afin que vous n'ayez plus besoin de cette classe Helper.
Programmeur
1
Je n'irais pas jusqu'à dire "Oubliez toutes les bibliothèques tierces". JsonUtility a des limites. Il ne renvoie pas d'objet JSON sur lequel vous pouvez effectuer des actions. Par exemple, j'obtiens un fichier json et je veux vérifier si une clé "succès" est disponible. Je ne peux pas faire. Le JsonUtility nécessite que le consommateur connaisse le contenu exact du fichier json. De plus, pas de convertisseur de dictionnaire. Donc, il fait de bonnes choses mais l'utilisation de tiers est toujours nécessaire.
Everts
2
Utilisez JsonHelper. C'est bon. Si vous créez Json avec lui, vous pouvez également lire json avec lui sans étapes supplémentaires. Le seul moment où vous devrez peut-être faire des choses supplémentaires est si vous recevez le tableau json du serveur et que cela est inclus dans la solution est dans ma réponse. Une autre façon sans JsonHelperest de mettre la classe dans une autre classe puis d'en faire un List. Cela a fonctionné pour la plupart des gens. Si vous cherchez un moyen de sauvegarder et de charger les données du jeu, voyez ceci . Vous chargez et enregistrez avec une ligne de code.
Programmeur
17

Supposons que vous ayez un JSON comme celui-ci

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

Pour analyser le JSON ci-dessus à l'unité, vous pouvez créer un modèle JSON comme celui-ci.

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

Et puis analysez simplement de la manière suivante ...

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

Vous pouvez maintenant modifier le JSON / CODE en fonction de vos besoins. https://docs.unity3d.com/Manual/JSONSerialization.html

Narottam Goyal
la source
Cela fonctionne plutôt bien, cela fonctionne avec une classe comme Symbol qui n'est pas non plus un tableau.
Gennon
4
J'essaye ceci avec unity 2018 mais cela ne fonctionne pas: les tableaux ne sont pas analysés
Jean-Michaël Celerier
Utilisé à l'unité 2018 et 2019. Fonctionne très bien. Accédez aux données du tableau comme: Debug.Log(myObject.result[0].symbol[0].data);ou for(var i = 0; i <= myObject.result.Length - 1; i ++) { Debug.Log(myObject.result[i].type); }ouforeach (var item in myObject.result) { Debug.Log(item.type); }
Towerss
@Narottam Goyal, votre méthode ne fonctionne pas dans certains cas, également une solution très difficile pour les débutants,
renvoyez
@JunedKhanMomin votre réponse fait fondamentalement la même chose mais sans aborder le fait que cette question ici concernait un tableau de niveau racine dans les données JSON en particulier. En général, vous devriez plutôt vous référer à la réponse du programmeur qui est beaucoup plus élaborée.
derHugo
2

vous devez ajouter [System.Serializable]à la PlayerItemclasse, comme ceci:

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

Ne coupez pas le []et tout devrait aller bien. []identifiez un tableau JSON qui est exactement ce dont vous avez besoin pour pouvoir itérer ses éléments.

Thomas Hilbert
la source
0

Comme @Maximiliangerhardt l'a dit, MiniJson n'a pas la capacité de désérialiser correctement. J'ai utilisé JsonFx et fonctionne comme un charme. Fonctionne avec le[]

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
la source
0

Pour lire le fichier JSON, reportez-vous à cet exemple simple

Votre fichier 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;
}
Juned Khan Momin
la source
1
Qu'en est-il des tableaux? Et qu'est-ce que cette réponse ajoute qui n'était pas déjà mentionnée dans la réponse acceptée d'il y a plus de 3 ans?
derHugo
0

Vous pouvez utiliser Newtonsoft.Jsonsimplement ajouter Newtonsoft.dllà votre projet et utiliser le script ci-dessous

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

    }
}

entrez la description de l'image ici

une autre solution utilise 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);

    }
}

entrez la description de l'image ici

Seyed Morteza Kamali
la source
0

SI vous utilisez Vector3, c'est ce que j'ai fait

1- Je crée une classe Name it Player

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

}

2- alors je l'appelle comme ça

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- et c'est le résultat

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

Gara
la source
0

Unité <= 2019

Narottam Goyal a eu une bonne idée d'encapsuler le tableau dans un objet json, puis de le désérialiser dans une structure. Ce qui suit utilise Generics pour résoudre ce problème pour les tableaux de tous types, par opposition à la création d'une nouvelle classe à chaque fois.

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

Il peut être utilisé de la manière suivante:

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

Unity 2020

Dans Unity 2020, il existe un package newtonsoft officiel qui est une bien meilleure bibliothèque json.

Justin Meiners
la source