Сериализация и десериализация Json и Json Array в Unity

99

У меня есть список элементов, отправленных из файла PHP в единство с использованием WWW.

В WWW.textвыглядит следующим образом :

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

Где я обрезаю лишнее []из string. Когда я пытаюсь разобрать его с помощью Boomlagoon.JSON, извлекается только первый объект. Я обнаружил, что у меня есть deserialize()список, и импортировал MiniJSON.

Но я не понимаю, как deserialize()этот список. Я хочу перебрать каждый объект JSON и получить данные. Как я могу сделать это в Unity с помощью C #?

Я использую класс

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

После обрезки []я могу проанализировать json с помощью MiniJSON. Но возвращается только первая 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));
}

Благодарность!

dil33pm
источник
Зачем убрали внешнее [и ]? Вот что делает его списком. Просто прекратите удалять это и десериализуйте его как массив или список, и я ожидаю, что все будет в порядке. Пожалуйста, опубликуйте код, который вы пробовали.
Джон Скит,
Покажите нам класс, используемый для десериализации. Формат странный, почему второй playerId не заключен в фигурные скобки? Он должен десериализации в список чего - то, как List<PlayerLocation>, потому что это является массивом.
Максимилиан Герхардт,
@MaximilianGerhardt Извините, фигурные скобки были опечаткой. Исправил это в вопросе и также добавил код. Спасибо.
dil33pm
1
Я думаю, что что-то не так с вашим пониманием того, как эта библиотека обрабатывает десериализацию. Это не обычная десериализация (как вы, возможно, видели Newtonsoft.Json), но Json.Deserialize()ВСЕГДА возвращает IDictionary<string,object>вам, и вы выполняете операции List<object>. Посмотрите stackoverflow.com/a/22745634/5296568 . Желательно получить лучший десериализатор JSON, который выполняет десериализацию, к которой вы привыкли.
Максимилиан Герхардт
@MaximilianGerhardt Я пробовал IDictionary<string,object>. Я могу получить ценность, но только первую KeyValuePair<>.
dil33pm

Ответы:

251

Unity добавила JsonUtility в свой API после обновления 5.3.3 . Забудьте обо всех сторонних библиотеках, если вы не делаете что-то более сложное. JsonUtility быстрее, чем другие библиотеки Json. Обновите Unity до версии 5.3.3 или выше и попробуйте решение, указанное ниже.

JsonUtilityэто легкий API. Поддерживаются только простые типы. Он не поддерживает такие коллекции, как Dictionary. Одно исключение List. Он поддерживает Listи Listмассив!

Если вам нужно сериализовать Dictionaryили сделать что-то иное, кроме простой сериализации и десериализации простых типов данных, используйте сторонний API. В противном случае продолжайте чтение.

Пример класса для сериализации:

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

1. ОДИН ОБЪЕКТ ДАННЫХ (НЕ МАССИВНЫЙ JSON)

Сериализация части A :

Выполните сериализацию в Json с помощью public static string ToJson(object obj);метода.

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

Выход :

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

Сериализация части B :

Выполните сериализацию в Json с помощью public static string ToJson(object obj, bool prettyPrint);перегрузки метода. Простой переход trueк JsonUtility.ToJsonфункции отформатирует данные. Сравните вывод ниже с выводом выше.

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

Выход :

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

Десериализация части A :

Десериализуйте json с помощью public static T FromJson(string json);перегрузки метода.

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

Десериализация части B :

Десериализуйте json с помощью public static object FromJson(string json, Type type);перегрузки метода.

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

Десериализация части C :

Десериализуйте json с помощью public static void FromJsonOverwrite(string json, object objectToOverwrite);метода. Когда JsonUtility.FromJsonOverwriteиспользуется, новый экземпляр этого объекта, который вы десериализуете, создаваться не будет. Он просто повторно использует переданный вами экземпляр и перезапишет его значения.

Это эффективно, и по возможности его следует использовать.

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. НЕСКОЛЬКО ДАННЫХ (МАССИВ JSON)

Ваш Json содержит несколько объектов данных. Например playerIdпоявлялся не раз . Unity JsonUtilityне поддерживает массив, поскольку он все еще новый, но вы можете использовать вспомогательный класс от этого человека, чтобы заставить работать массивJsonUtility .

Создайте класс с именем JsonHelper. Скопируйте JsonHelper прямо снизу.

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 :

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

Выход :

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

Десериализация массива 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);

Выход :

Powai

Пользователь2


Если это массив Json с сервера, и вы не создали его вручную :

Возможно, вам придется добавить {"Items":перед полученной строкой, а затем добавить }в ее конец.

Я сделал для этого простую функцию:

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

тогда вы можете использовать его:

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

3. десериализация строки json без класса && десериализация Json с числовыми свойствами

Это Json, который начинается с числа или числовых свойств.

Например:

{ 
"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 JsonUtilityне поддерживает это, потому что свойство «15m» начинается с числа. Переменная класса не может начинаться с целого числа.

Загрузите SimpleJSON.csиз вики Unity .

Чтобы получить недвижимость «15 миллионов долларов»:

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

Чтобы получить собственность "15m" в ISK:

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

Чтобы получить недвижимость NZD "15m":

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

Остальные свойства Json, которые не начинаются с числовой цифры, могут обрабатываться Unity JsonUtility.


4.УСТРАНЕНИЕ НЕПОЛАДОК JsonUtility:

Проблемы при сериализации с помощью JsonUtility.ToJson?

Получение пустой строки или " {}" с помощью JsonUtility.ToJson?

. Убедитесь, что класс не является массивом. Если это так, используйте приведенный выше вспомогательный класс JsonHelper.ToJsonвместо JsonUtility.ToJson.

B . Добавьте [Serializable]в начало сериализуемого класса.

C . Удалите свойство из класса. Например, в переменной public string playerId { get; set; } удалить { get; set; } . Unity не может сериализовать это.

Проблемы при десериализации с помощью JsonUtility.FromJson?

. Если вы получили Null, убедитесь, что Json не является массивом Json. Если это так, используйте приведенный выше вспомогательный класс JsonHelper.FromJsonвместо JsonUtility.FromJson.

B . Если NullReferenceExceptionпри десериализации у вас получится , добавьте [Serializable]в начало класса.

C. Любые другие проблемы, убедитесь, что ваш json действителен. Перейти на этот сайт здесь и вставьте JSON. Он должен показать вам, действителен ли json. Он также должен сгенерировать правильный класс с Json. Просто не забудьте удалить remove { get; set; } из каждой переменной, а также добавить [Serializable]в начало каждого сгенерированного класса.


Newtonsoft.Json:

Если по какой-то причине необходимо использовать Newtonsoft.Json, ознакомьтесь с разветвленной версией для Unity здесь . Обратите внимание, что при использовании определенной функции может возникнуть сбой. Быть осторожен.


Чтобы ответить на ваш вопрос :

Ваши исходные данные

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

Добавить {"Items": в передней области , затем добавить } в конце этого.

Код для этого:

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

Теперь у вас есть:

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

Для сериализации в несколько данных из PHP как массивы , теперь вы можете сделать

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

playerInstance[0] ваши первые данные

playerInstance[1] ваши вторые данные

playerInstance[2] это ваши третьи данные

или данные внутри класса с playerInstance[0].playerLoc, playerInstance[1].playerLoc, playerInstance[2].playerLoc......

Вы можете использовать, playerInstance.Lengthчтобы проверить длину, прежде чем получить к ней доступ.

ПРИМЕЧАНИЕ: Удалите { get; set; } из playerкласса. Если да { get; set; }, то не пойдет. Юнити JsonUtilityэто НЕ работать с членами класса , которые определяются как свойства .

Программист
источник
Я возвращаю массив строк mysqlзапроса из PHP, используя json_encode($row). Таким образом, ответ состоит из нескольких объектов JSONObject в формате [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. Я попробовал JsonUtility, но не смог десериализовать объекты и получить отдельные объекты json. Если вы можете мне с этим помочь.
dil33pm
2
Посмотрите на код, который я разместил выше. Он показывает вам три способа сделать это с помощью JsonUtility.FromJson. Я забыл сказать тебе, чтобы ты удалился { get; set; }из playerкласса. Если да { get; set; }, это не сработает. Сравните ваш playerкласс с тем, что я опубликовал выше, и вы поймете, о чем я говорю.
Программист,
1
Нет проблем. Я отредактирую это, когда Unity добавит поддержку массива (что очень скоро), поэтому вам больше не понадобится этот класс Helper.
Программист
1
Я бы не стал говорить: «Забудьте обо всех сторонних библиотеках». У JsonUtility есть ограничения. Он не возвращает объект JSON, с которым вы можете выполнять действия. Например, я получаю файл json и хочу проверить, доступен ли ключ «успеха». Не могу. JsonUtility требует, чтобы потребитель знал точное содержимое файла json. Также нет конвертера словарей. Таким образом, он делает некоторые хорошие вещи, но использование сторонних разработчиков все еще требуется.
Everts
2
Используйте JsonHelper. Это замечательно. Если вы создаете с ним Json, вы также можете читать с ним json без дополнительных действий. Единственный раз, когда вам может потребоваться дополнительная работа, - это если вы получаете массив json с сервера, и это включено в решение, в моем ответе. Другой способ JsonHelper- поместить класс в другой класс, а затем сделать его классом List. Это работает для большинства людей. Если вы ищете способ сохранить и загрузить данные игры, посмотрите это . Вы загружаете и сохраняете с помощью одной строчки кода.
Программист
17

Предположим, у вас есть такой JSON

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

Чтобы проанализировать приведенный выше JSON в единстве, вы можете создать такую ​​модель JSON.

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

А затем просто проанализируйте следующим образом ...

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

Теперь вы можете изменить JSON / CODE в соответствии с вашими потребностями. https://docs.unity3d.com/Manual/JSONSerialization.html

Нароттам Гоял
источник
На самом деле это работает довольно хорошо, если он работает с таким классом, как Symbol, который также не является массивом.
Геннон
4
Я пытаюсь сделать это с помощью unity 2018, но это не работает: массивы не анализируются,
Жан-Микаэль Селерье,
Используется в Unity 2018 и 2019. Отлично работает. Доступ к данным массива, например: 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); }
Towerss
@Narottam Goyal, ваш метод не работает в некоторых случаях, также очень сложное решение для новичков,
отсылайте
@JunedKhanMomin ваш ответ в основном такой же, но без учета того факта, что этот вопрос здесь касался массива корневого уровня в данных JSON, в частности. В общем, вам лучше обратиться к ответу программиста, который более подробен.
derHugo 07
2

вам нужно добавить [System.Serializable]в PlayerItemкласс, например:

using System;
[System.Serializable]
public class PlayerItem   {
    public string playerId;
    public string playerLoc;
    public string playerNick;
}
Мьян
источник
1

Чтобы прочитать файл JSON, обратитесь к этому простому примеру

Ваш файл JSON (StreamingAssets / Player.json)

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

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
А как насчет массивов? И что добавляет этот ответ, чего еще не было в принятом ответе более 3 лет назад?
derHugo 01
@derHugo, он включает звонок, File.ReadAllTextкоторый, на мой взгляд, полезен, и ни в одном другом ответе не упоминается :)
Рузим,
@Ruzihm ну, причина, по которой не упоминается ни один другой ответ, заключается в том, что объем этого вопроса заключается в том, как (де) сериализовать ... а не как сделать FileIO;)
derHugo
0

Не обрезайте, []и все будет в порядке. []идентифицировать массив JSON, который является именно тем, что вам нужно, чтобы иметь возможность перебирать его элементы.

Томас Гильберт
источник
0

Как сказал @Maximiliangerhardt, MiniJson не имеет возможности правильно десериализоваться. Я использовал JsonFx и работает как шарм. Работает с[]

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
источник
0

Вы можете Newtonsoft.Jsonпросто добавить Newtonsoft.dllв свой проект и использовать сценарий ниже

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

    }
}

введите описание изображения здесь

другое решение использует 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);

    }
}

введите описание изображения здесь

Сейед Мортеза Камали
источник
0

ЕСЛИ вы используете Vector3, это то, что я сделал

1- Я создаю класс, назовите его Player

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

}

2- тогда я называю это так

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- и это результат

"Позиция": [{"x": - 2,8567452430725099, «y»: - 2,4323320388793947, «z»: 0,0}]}

Гара
источник
0

Единство <= 2019

У Нароттама Гояла была хорошая идея обернуть массив в json-объект, а затем десериализовать его в структуру. Далее для решения этой проблемы для массивов всех типов используются Generics, в отличие от создания нового класса каждый раз.

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

Его можно использовать следующим образом:

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

Единство 2020

В Unity 2020 есть официальный пакет newtonsoft , который представляет собой гораздо лучшую библиотеку json.

Джастин Майнерс
источник
1
Ссылка, которую вы предоставили, мертва, но эта ссылка указана как соответствующая статья: docs.unity3d.com/Packages/com.unity.nuget.newtonsoft-json@2.0/… с примечанием: «Это пакет, предназначенный для внутренней разработки Unity. Проекты и как таковой этот пакет не поддерживаются. Используйте на свой страх и риск ».
R2RT