Сериализация и десериализация Json и Json Array в Unity
У меня есть список элементов, отправленных из файла PHP в Unity, используя WWW
, WWW.text
похоже [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]
где я обрезать лишнее []
из строки. Когда я пытаюсь разобрать его с помощью Boomlagoon.JSON
только первый объект извлекается. Я узнал, что я должен deserialize()
список и импортировали MiniJSON.
Но я запутался, как десериализовать () этот список. Я хочу пройтись по каждому объекту 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> s = Json.Deserialize(serviceData) as IDictionary<string,object>;
foreach (KeyValuePair<string, object> kvp in s)
{
Debug.Log(string.Format("Key = {0}, Value = {1}", kvp.Key, kvp.Value));
}
Спасибо!
11 ответов
Unity добавил JsonUtility в их API после обновления 5.3.3. Забудьте обо всех сторонних библиотеках, если вы не делаете что-то более сложное. JsonUtility работает быстрее, чем другие библиотеки Json. Обновите до версии Unity 5.3.3 или выше, затем попробуйте решение ниже.
JsonUtility
это легкий API. Поддерживаются только простые типы. Он не поддерживает коллекции, такие как словарь. Одно исключение 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 Jason
string playerToJason = JsonUtility.ToJson(playerInstance);
Debug.Log(playerToJason);
Выход:
{"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 Jason
string playerToJason = JsonUtility.ToJson(playerInstance, true);
Debug.Log(playerToJason);
Выход:
{
"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. НЕСКОЛЬКО ДАННЫХ (ARRAY JSON)
Ваш Json содержит несколько объектов данных. Например playerId
появился не раз. Юнити 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 Jason
string playerToJason = JsonHelper.ToJson(playerInstance, true);
Debug.Log(playerToJason);
Выход:
{
"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" : "$"}
}
Юнити JsonUtility
не поддерживает это, потому что свойство "15m" начинается с числа. Переменная класса не может начинаться с целого числа.
Скачать SimpleJSON.cs
из вики Unity.
Чтобы получить собственность "15 миллионов долларов США":
var N = JSON.Parse(yourJsonString);
string price = N["USD"]["15m"].Value;
Debug.Log(price);
Чтобы получить свойство "15м" ИСК:
var N = JSON.Parse(yourJsonString);
string price = N["ISK"]["15m"].Value;
Debug.Log(price);
Чтобы получить собственность "15м" от NZD:
var N = JSON.Parse(yourJsonString);
string price = N["NZD"]["15m"].Value;
Debug.Log(price);
Остальные свойства Json, которые не начинаются с цифры, могут обрабатываться утилитой JsonUtility от Unity.
4. УСТРАНЕНИЕ НЕИСПРАВНОСТЕЙ JsonUtility:
Проблемы при сериализации с JsonUtility.ToJson
?
Получение пустой строки или {}
" с JsonUtility.ToJson
?
А. Убедитесь, что класс не является массивом. Если это так, используйте вспомогательный класс выше с JsonHelper.ToJson
вместо JsonUtility.ToJson
,
Б. добавлять [Serializable]
к вершине класса, который вы сериализуете.
C. Удалить свойство из класса. Например, в переменной public string playerId { get; set; }
Удалить { get; set; }
, Единство не может сериализовать это.
Проблемы при десериализации с JsonUtility.FromJson
?
А. Если вы получаете Null
, убедитесь, что Json не является массивом Json. Если это так, используйте вспомогательный класс выше с JsonHelper.FromJson
вместо JsonUtility.FromJson
,
Б. Если вы получаете NullReferenceException
при десериализации добавить [Serializable]
на вершину класса.
C. Любые другие проблемы, убедитесь, что ваш JSON действителен. Зайдите на этот сайт и вставьте JSON. Он должен показать вам, если JSON действителен. Он также должен генерировать правильный класс с Json. Просто убедитесь, что удалить удалить { 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
НЕ работает с членами класса, которые определены как свойства.
Предположим, вы получили 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
Единство <= 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.
Ты должен добавить [System.Serializable]
в PlayerItem
класс, как это:
using System;
[System.Serializable]
public class PlayerItem {
public string playerId;
public string playerLoc;
public string playerNick;
}
Чтобы прочитать файл 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;
}
Если вы пришли сюда в поисках сериализации списка с помощью JsonUtility без каких-либо дополнительных пакетов, читайте дальше.
[System.Serializable]
public class JsonableListWrapper<T>
{
public List<T> list;
public JsonableListWrapper(List<T> list) => this.list = list;
}
Пример использования:
List<string> stringList = new List<string>(){"one","two","three"};
// To Json
string stringListAsJson = JsonUtility.ToJson(new JsonListWrapper<string>(stringList));
// From Json
List<string> stringListFromJson = JsonUtility.FromJson<JsonListWrapper<string>>(stringListAsJson).list;
Благодарим theonlysake из этой темы: https://forum.unity.com/threads/jsonutilities-tojson-with-list-string-not-working-as-expected.722783/
Кажется, вы не можете сериализовать/десериализовать список напрямую, но если это свойство класса, вы можете. В моем личном случае я заменил строковый тип типом пользовательского класса, и это сработало отлично.
Добавив ответ, получивший наибольшее количество голосов, потребовалась дополнительная очистка входных данных JSON, которые я получал из базы данных. Я получал дополнительные цитаты, обратную косую черту и ключевое слово Items. Итак, вот что я добавил в код, и это работает для меня как шарм (я использую mysql 5.7 и PHP 7.4).
public class JsonHelper
{
public static T FromJson<T>(string json, bool sanitize = true)
{
if (sanitize) json = CleanJSON(json, false);
return UnityEngine.JsonUtility.FromJson<T>(json);
}
public static T[] FromJsonToArray<T>(string json, bool sanitize = true)
{
if (sanitize) json = CleanJSON(json, true);
Wrapper<T> wrapper = UnityEngine.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 UnityEngine.JsonUtility.ToJson(wrapper);
}
static string CleanJSON(string json, bool isArray)
{
json = json.Replace("\\", "");
json = json.Replace("\"[", "[");
json = json.Replace("]\"", "]");
json = json.Replace("\"{", "{");
json = json.Replace("}\"", "}");
string ItemsString = "{\"Items\":";
int itemsStringLength = ItemsString.Length;
int indexOfItems = json.IndexOf(ItemsString);
int skipCurlyBracketsCount = 0;
bool remove = false;
if (indexOfItems != -1)
for (int i = indexOfItems; i < json.Length; i++)
{
if (!remove)
{
json = json.Remove(i, itemsStringLength);
remove = true;
}
if (json[i] == '}')
{
if (skipCurlyBracketsCount == 0)
{
json = json.Remove(i, 1);
i = json.IndexOf(ItemsString);
if (i == -1)
break;
else
{
remove = false;
i--;
skipCurlyBracketsCount = 1;
continue;
}
}
else if (skipCurlyBracketsCount > 0)
skipCurlyBracketsCount--;
}
else if (json[i] == '{')
skipCurlyBracketsCount++;
}
if (isArray)
if (!json.StartsWith(ItemsString))
json = ItemsString + json + "}";
return json;
}
[System.Serializable]
private class Wrapper<T>
{
public T[] Items;
}
}
Ты можешь использовать 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);
}
}
https://st ackru.com/images/652f588f9f165ec5ae4aa70e14b5ab04250293bf.png
другое решение использует 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);
}
}
https://st ackru.com/images/c1378ba79b01ce7c9e8f3ef0ccf7421680b10172.png
Как сказал @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);
Не обрезать []
и ты должен быть в порядке. []
идентифицируйте массив JSON, который является именно тем, что вам нужно, чтобы иметь возможность перебирать его элементы.
ЕСЛИ вы используете 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}]}