Serializar y deserializar Json y Json Array en Unity

97

Tengo una lista de elementos enviados desde un archivo PHP a la unidad usando WWW.

El WWW.textparece:

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

Donde recorto el extra []del string. Cuando intento analizarlo usando Boomlagoon.JSON, solo se recupera el primer objeto. Descubrí que tengo deserialize()la lista y he importado MiniJSON.

Pero estoy confundido sobre cómo hacer deserialize()esta lista. Quiero recorrer cada objeto JSON y recuperar datos. ¿Cómo puedo hacer esto en Unity usando C #?

La clase que estoy usando es

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

Después de recortar, []puedo analizar el json usando MiniJSON. Pero está regresando solo el primero 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));
}

¡Gracias!

dil33pm
fuente
¿Por qué quitó el exterior [y ]? Eso es lo que lo convierte en una lista. Simplemente deje de eliminar eso y deserialícelo como una matriz o una lista y espero que esté bien. Publique el código que ha probado.
Jon Skeet
Muéstranos la clase utilizada para la deserialización. El formato es extraño, ¿por qué el segundo playerId no está envuelto entre llaves? Debería deserializarse a una lista de algo, como List<PlayerLocation>, porque se trata de una matriz.
Maximilian Gerhardt
@MaximilianGerhardt Lo siento, las llaves fueron un error tipográfico. Se corrigió en la pregunta y se agregó el código también. Gracias.
dil33pm
1
Creo que hay algo mal en su comprensión de cómo esta biblioteca maneja la deserialización. No es la deserialización habitual (como tal vez haya visto Newtonsoft.Json), pero Json.Deserialize()SIEMPRE le regresa un IDictionary<string,object>mensaje y continúa operando List<object>. Mire stackoverflow.com/a/22745634/5296568 . Preferiblemente, obtenga un mejor deserializador JSON que realice la deserialización a la que está acostumbrado.
Maximilian Gerhardt
@MaximilianGerhardt lo intenté IDictionary<string,object>. Puedo sacar el valor, pero solo el primero KeyValuePair<>.
dil33pm

Respuestas:

247

Unity agregó JsonUtility a su API después de la actualización 5.3.3 . Olvídese de todas las bibliotecas de terceros a menos que esté haciendo algo más complicado. JsonUtility es más rápido que otras bibliotecas Json. Actualice a la versión Unity 5.3.3 o superior y luego pruebe la solución a continuación.

JsonUtilityes una API ligera. Solo se admiten tipos simples. No , no admite colecciones tales como diccionario. Una excepción es List. ¡Es compatible Listy Listmatriz!

Si necesita serializar Dictionaryo hacer algo más que simplemente serializar y deserializar tipos de datos simples, use una API de terceros. De lo contrario, sigue leyendo.

Clase de ejemplo para serializar:

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

1. UN OBJETO DE DATOS (JSON NO ARRAY)

Serializando la Parte A :

Serializa a JSON con el public static string ToJson(object obj);método.

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

Salida :

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

Serialización de la parte B :

Serializa a JSON con la public static string ToJson(object obj, bool prettyPrint);sobrecarga del método. Simplemente pasar truea la JsonUtility.ToJsonfunción formateará los datos. Compare la salida a continuación con la salida anterior.

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

Salida :

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

Deserializando la Parte A :

Deserializar json con el public static T FromJson(string json);método overload.

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

Deserializar la parte B :

Deserializar json con el public static object FromJson(string json, Type type);método overload.

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

Deserialización de la parte C :

Deserializar json con el public static void FromJsonOverwrite(string json, object objectToOverwrite);método. Cuando JsonUtility.FromJsonOverwritese usa, no se creará una nueva instancia de ese Objeto al que está deserializando. Simplemente reutilizará la instancia que le pase y sobrescribirá sus valores.

Esto es eficaz y debería utilizarse si es posible.

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. DATOS MÚLTIPLES (ARRAY JSON)

Su Json contiene varios objetos de datos. Por ejemplo playerIdapareció más de una vez . Unity JsonUtilityno es compatible con la matriz, ya que todavía es nueva, pero puede usar una clase auxiliar de esta persona para que la matriz funcione JsonUtility.

Crea una clase llamada JsonHelper . Copie JsonHelper directamente desde abajo.

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

Serialización de la matriz 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);

Salida :

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

Deserialización de la matriz Json :

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

Salida :

Powai

Usuario2


Si se trata de una matriz Json del servidor y no la creó a mano :

Puede que tenga que agregar {"Items": delante de la cadena recibida y luego agregar }al final.

Hice una función simple para esto:

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

entonces puedes usarlo:

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

3.Deserializar la cadena json sin clase && Desserializar Json con propiedades numéricas

Este es un Json que comienza con un número o propiedades numéricas.

Por ejemplo:

{ 
"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" : "$"}
}

Unidad JsonUtility no admite esto porque la propiedad "15m" comienza con un número. Una variable de clase no puede comenzar con un número entero.

Descarga SimpleJSON.csdesde la wiki de Unity .

Para obtener la propiedad "15m" de USD:

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

Para obtener la propiedad "15m" de ISK:

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

Para obtener la propiedad "15m" de NZD:

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

El resto de las propiedades de Json que no comienzan con un dígito numérico pueden ser manejadas por JsonUtility de Unity.


4.SOLUCIÓN DE PROBLEMAS JsonUtility:

¿Problemas al serializar con JsonUtility.ToJson?

¿Obteniendo cadena vacía o " {}" con JsonUtility.ToJson?

Una . Asegúrese de que la clase no sea una matriz. Si es así, use la clase auxiliar anterior con en JsonHelper.ToJsonlugar de JsonUtility.ToJson.

B . Agregue [Serializable]a la parte superior de la clase que está serializando.

C . Eliminar propiedad de la clase. Por ejemplo, en la variable, public string playerId { get; set; } elimine { get; set; } . Unity no puede serializar esto.

¿Problemas al deserializar con JsonUtility.FromJson?

Una . Si es así Null, asegúrese de que Json no sea una matriz Json. Si es así, use la clase auxiliar anterior con en JsonHelper.FromJsonlugar de JsonUtility.FromJson.

B . Si obtiene NullReferenceExceptionmientras deserializa, agregue [Serializable]a la parte superior de la clase.

C. Cualquier otro problema, verifique que su json sea válido. Vaya a este sitio aquí y pegue el archivo json. Debería mostrarte si el json es válido. También debería generar la clase adecuada con Json. Solo asegúrese de eliminar eliminar { get; set; } de cada variable y también agregar [Serializable]a la parte superior de cada clase generada.


Newtonsoft.Json:

Si por alguna razón se debe usar Newtonsoft.Json , consulte la versión bifurcada de Unity aquí . Tenga en cuenta que puede experimentar un bloqueo si se utiliza determinada función. Ten cuidado.


Para responder a su pregunta :

Tus datos originales son

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

Añadir {"Items": en la parte delantera de la misma a continuación, añadir } al final de la misma.

Código para hacer esto:

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

Ahora tu tienes:

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

Para serializar los múltiples datos de php como matrices , ahora puede hacer

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

playerInstance[0] son tus primeros datos

playerInstance[1] son tus segundos datos

playerInstance[2] es tu tercer dato

o datos dentro de la clase con playerInstance[0].playerLoc, playerInstance[1].playerLoc,playerInstance[2].playerLoc ......

Puedes usar playerInstance.Length para comprobar la longitud antes de acceder a él.

NOTA: Retirar { get; set; } de la playerclase. Si es { get; set; }así, no funcionará. Unidad de JsonUtilityqué NO trabajar con miembros de la clase que se definen como propiedades .

Programador
fuente
Estoy devolviendo una matriz de filas de una mysqlconsulta desde PHP usando json_encode($row). Entonces, la respuesta consta de múltiples JSONObjects en el formato [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. Probé JsonUtility, pero no pude deserializar los objetos y obtener objetos json individuales. Si puedes ayudarme con eso.
dil33pm
2
Mira el código que publiqué arriba. Le muestra tres formas de hacerlo con JsonUtility.FromJson. Olvidé decirte que te quites { get; set; }de la playerclase. Si es así { get; set; }, no funcionará. Compare su playerclase con la que publiqué anteriormente y comprenderá lo que estoy diciendo.
Programador
1
No hay problema. Editaré esto cuando Unity agregue soporte para arreglo (que será muy pronto) para que ya no necesite esa clase de ayuda.
Programador
1
No iría tan lejos como para decir "Olvídate de todas las bibliotecas de terceros". JsonUtility tiene limitaciones. No devuelve un objeto JSON en el que pueda realizar acciones. Por ejemplo, obtengo un archivo json y quiero comprobar si hay una clave de "éxito" disponible. No puedo. JsonUtility requiere que el consumidor conozca el contenido exacto del archivo json. Además, no hay convertidor de diccionario. Por lo tanto, hace algunas cosas buenas, pero aún se requiere el uso de terceros.
Everts
2
Utilice JsonHelper. Está bien. Si crea Json con él, también puede leer json con él sin pasos adicionales. La única vez que puede necesitar hacer cosas adicionales es si está recibiendo la matriz json del servidor y eso está incluido en la solución en mi respuesta. Otra forma JsonHelperes poner la clase en otra clase y luego convertirla en List. Esto ha funcionado para la mayoría de la gente. Si está buscando una forma de guardar y cargar datos del juego, consulte esto . Carga y guarda con una línea de código.
Programador
17

Suponga que tiene un JSON como este

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

Para analizar el JSON anterior en unidad, puede crear un modelo JSON como este.

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

Y luego simplemente analice de la siguiente manera ...

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

Ahora puede modificar el JSON / CODE según sus necesidades. https://docs.unity3d.com/Manual/JSONSerialization.html

Narottam Goyal
fuente
En realidad, esto funciona bastante bien, lo hizo funcionar con una clase como Symbol que tampoco es una matriz.
Gennon
4
Estoy intentando esto con unity 2018 pero esto no funciona: las matrices no se analizan
Jean-Michaël Celerier
Usado en la unidad 2018 y 2019. Funciona muy bien. Acceda a los datos de la matriz como: 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, su método no funciona en algunos casos, también es una solución muy difícil para los principiantes, consulte esta respuesta mía en este enlace de
Juned Khan Momin
@JunedKhanMomin su respuesta hace básicamente lo mismo, pero sin abordar el hecho de que esta pregunta aquí se trataba de una matriz de nivel raíz en los datos JSON en específico. En general, debería consultar la respuesta del programador, que es mucho más elaborada.
derHugo
2

tienes que agregar [System.Serializable]a la PlayerItemclase, así:

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

No recorte el []y debería estar bien. []identifique una matriz JSON que es exactamente lo que necesita para poder iterar sus elementos.

Thomas Hilbert
fuente
0

Como dijo @Maximiliangerhardt, MiniJson no tiene la capacidad de deserializar correctamente. Usé JsonFx y funciona como un encanto. Funciona con el[]

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
fuente
0

Para leer un archivo JSON, consulte este sencillo ejemplo

Su archivo JSON (StreamingAssets / Player.json)

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

Script de 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
fuente
1
¿Qué pasa con las matrices? ¿Y qué agrega esta respuesta que no se mencionó en la respuesta aceptada de hace más de 3 años?
derHugo
0

Puede usar Newtonsoft.Jsonsolo agregar Newtonsoft.dlla su proyecto y usar el siguiente script

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

    }
}

ingrese la descripción de la imagen aquí

otra solución está 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);

    }
}

ingrese la descripción de la imagen aquí

Seyed Morteza Kamali
fuente
0

SI estás usando Vector3 esto es lo que hice

1- creo una clase Name it Player

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

}

2- entonces lo llamo así

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- y este es el resultado

"Posición": [{"x": - 2.8567452430725099, "y": - 2.4323320388793947, "z": 0.0}]}

Gara
fuente
0

Unidad <= 2019

Narottam Goyal tuvo una buena idea de envolver la matriz en un objeto json y luego deserializar en una estructura. Lo siguiente usa Generics para resolver esto para arreglos de todo tipo, en lugar de crear una nueva clase cada vez.

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

Se puede utilizar de la siguiente manera:

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

Unidad 2020

En Unity 2020 hay un paquete oficial de newtonsoft que es una biblioteca json mucho mejor.

Justin Meiners
fuente