Serializuj i deserializuj Json i Json Array w Unity

98

Mam listę elementów wysłanych z pliku PHP do Unity za pomocą WWW.

Do WWW.textwygląda następująco:

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

Gdzie przycinam dodatek []z string. Kiedy próbuję przeanalizować go przy użyciu Boomlagoon.JSON, pobierany jest tylko pierwszy obiekt. Dowiedziałem się, że mam do deserialize()listy i zaimportowałem MiniJSON.

Ale jestem zdezorientowany, jak do deserialize()tej listy. Chcę przejrzeć każdy obiekt JSON i pobrać dane. Jak mogę to zrobić w Unity przy użyciu C #?

Klasa, której używam, to

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

Po przycięciu []jestem w stanie przeanalizować json za pomocą MiniJSON. Ale wraca tylko pierwszy 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));
}

Dzięki!

dil33pm
źródło
Dlaczego usunąłeś zewnętrzne [i ]? To właśnie sprawia, że ​​jest to lista. Po prostu przestań to usuwać i zdeserializuj jako tablicę lub listę, a spodziewałbym się, że wszystko będzie dobrze. Wpisz kod, który próbowałeś.
Jon Skeet
Pokaż nam klasę używaną do deserializacji. Format jest dziwny, dlaczego drugi odtwarzacz nie jest zawinięty w nawiasy klamrowe? Powinien zostać deserializowany na listę czegoś, na przykład List<PlayerLocation>, ponieważ jest to tablica.
Maximilian Gerhardt
@MaximilianGerhardt Przepraszam, że nawiasy klamrowe to literówka. Poprawiłem to w pytaniu i dodałem również kod. Dzięki.
dil33pm
1
Myślę, że jest coś nie tak w twoim rozumieniu tego, że ta biblioteka obsługuje deserializację. To nie jest zwykła deserializacja (jak być może widzieliście Newtonsoft.Json), ale Json.Deserialize()ZAWSZE zwraca IDictionary<string,object>do ciebie i działasz dalej List<object>. Spójrz na stackoverflow.com/a/22745634/5296568 . Najlepiej zdobądź lepszy deserializator JSON, który wykonuje deserializację, do której jesteś przyzwyczajony.
Maximilian Gerhardt
@MaximilianGerhardt Próbowałem z IDictionary<string,object>. Jestem w stanie wydobyć wartość, ale tylko pierwszą KeyValuePair<>.
dil33pm

Odpowiedzi:

250

Unity dodała JsonUtility do swojego API po aktualizacji 5.3.3 . Zapomnij o wszystkich bibliotekach innych firm, chyba że robisz coś bardziej skomplikowanego. JsonUtility jest szybsze niż inne biblioteki Json. Zaktualizuj do wersji Unity 5.3.3 lub nowszej, a następnie wypróbuj poniższe rozwiązanie.

JsonUtilityto lekki interfejs API. Obsługiwane są tylko proste typy. To nie nie obsługują kolekcji, takich jak hasła. Jedynym wyjątkiem jest List. Obsługuje Listi Listszykuje!

Jeśli chcesz serializować Dictionarylub zrobić coś innego niż po prostu serializować i deserializować proste typy danych, użyj interfejsu API innej firmy. W przeciwnym razie kontynuuj czytanie.

Przykładowa klasa do serializacji:

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

1. JEDEN OBIEKT DANYCH (NON-ARRAY JSON)

Serializacja części A :

Serializuj do Json za pomocą public static string ToJson(object obj);metody.

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

Wyjście :

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

Serializacja części B :

Serializuj do Json z public static string ToJson(object obj, bool prettyPrint);przeciążeniem metody. Zwykłe przekazanie truedo JsonUtility.ToJsonfunkcji spowoduje sformatowanie danych. Porównaj dane wyjściowe poniżej z wynikami powyżej.

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

Wyjście :

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

Deserializacja część A :

Deserializacja json przy użyciu public static T FromJson(string json);przeciążenia metody.

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

Deserializacja części B :

Deserializacja json przy użyciu public static object FromJson(string json, Type type);przeciążenia metody.

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

Deserializacja część C :

Deserializacja json za pomocą public static void FromJsonOverwrite(string json, object objectToOverwrite);metody. Gdy JsonUtility.FromJsonOverwritejest używany, nie zostanie utworzone żadne nowe wystąpienie tego obiektu, do którego deserializujesz. Po prostu ponownie wykorzysta przekazaną instancję i nadpisze jej wartości.

Jest to wydajne i powinno być używane, jeśli to możliwe.

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. WIELE DANYCH (ARRAY JSON)

Twoja Json zawiera wiele obiektów danych. Na przykład playerIdpojawił się więcej niż raz . Jedności JsonUtilitynie obsługuje tablicę, ponieważ jest jeszcze nowy, ale można użyć pomocnika klasy od tej osoby, aby uzyskać macierz pracuje z JsonUtility.

Utwórz klasę o nazwie JsonHelper. Skopiuj JsonHelper bezpośrednio od dołu.

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

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

Wyjście :

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

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

Wyjście :

Powai

Użytkownik2


Jeśli to jest tablica Json z serwera i nie utworzyłeś jej ręcznie :

Być może trzeba będzie dodać {"Items":przed otrzymanym ciągiem, a następnie dodać }na końcu.

Zrobiłem w tym celu prostą funkcję:

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

wtedy możesz go użyć:

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

3. Deserializuj ciąg JSON bez klasy && De-serializacji Json z właściwościami numerycznymi

To jest Json, który zaczyna się od liczby lub właściwości numerycznych.

Na przykład:

{ 
"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 JsonUtilitytego nie obsługuje, ponieważ właściwość „15m” zaczyna się od liczby. Zmienna klasy nie może zaczynać się od liczby całkowitej.

Pobierz SimpleJSON.csz wiki Unity .

Aby uzyskać właściwość „15m” w USD:

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

Aby uzyskać własność ISK „15m”:

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

Aby uzyskać własność „15 m” NZD:

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

Pozostałe właściwości Json, które nie zaczynają się od cyfry, mogą być obsługiwane przez JsonUtility Unity.


4. ROZWIĄZYWANIE PROBLEMÓW JsonUtility:

Problemy podczas serializacji z JsonUtility.ToJson?

Otrzymujesz pusty ciąg lub „ {}” z JsonUtility.ToJson?

. Upewnij się, że klasa nie jest tablicą. Jeśli tak, użyj powyższej klasy pomocniczej z JsonHelper.ToJsonzamiast JsonUtility.ToJson.

B . Dodaj [Serializable]na początku klasy, którą serializujesz.

C . Usuń właściwość z klasy. Na przykład w zmiennej public string playerId { get; set; } remove { get; set; } . Unity nie może tego serializować.

Problemy podczas deserializacji z JsonUtility.FromJson?

. Jeśli otrzymasz Null, upewnij się, że Json nie jest tablicą Json. Jeśli tak, użyj powyższej klasy pomocniczej z JsonHelper.FromJsonzamiast JsonUtility.FromJson.

B . Jeśli otrzymasz NullReferenceExceptionpodczas deserializacji, dodaj [Serializable]do początku klasy.

C .Wszelkie inne problemy, sprawdź, czy plik json jest prawidłowy. Przejdź do tej witryny tutaj i wklej plik json. Powinien pokazać, czy plik json jest prawidłowy. Powinien również wygenerować odpowiednią klasę z Json. Po prostu pamiętaj, aby usunąć usuń { get; set; } z każdej zmiennej, a także dodaj [Serializable]na początku każdej wygenerowanej klasy.


Newtonsoft.Json:

Jeśli z jakiegoś powodu Newtonsoft.Json należy stosować wtedy sprawdzić wersję rozdwojony Jedności tutaj . Pamiętaj, że może wystąpić awaria, jeśli używana jest określona funkcja. Bądź ostrożny.


Aby odpowiedzieć na Twoje pytanie :

Twoje oryginalne dane to

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

Dodaj {"Items": do przodu o to następnie dodać } na końcu tego.

Kod, aby to zrobić:

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

Teraz masz:

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

Do serializacji do wielu danych z PHP jako tablic , można teraz zrobić

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

playerInstance[0] to twoje pierwsze dane

playerInstance[1] to twoje drugie dane

playerInstance[2] to Twoje trzecie dane

lub danych wewnątrz klasy z playerInstance[0].playerLoc, playerInstance[1].playerLoc, playerInstance[2].playerLoc......

Możesz użyć, playerInstance.Lengthaby sprawdzić długość przed uzyskaniem do niego dostępu.

UWAGA: Usuń { get; set; } z playerzajęć. Jeśli tak { get; set; }, to nie zadziała. Unity JsonUtilityma NIE pracować z członków klasy, które są zdefiniowane jako właściwości .

Programista
źródło
Zwracam tablicę wierszy mysqlzapytania z PHP przy użyciu json_encode($row). Zatem odpowiedź składa się z wielu obiektów JSONObject w formacie [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. Próbowałem JsonUtility, ale nie mogłem deserializować obiektów i uzyskiwać pojedynczych obiektów json. Jeśli możesz mi w tym pomóc.
dil33pm
2
Spójrz na kod, który zamieściłem powyżej. Pokazuje trzy sposoby, aby to zrobić JsonUtility.FromJson. Zapomniałem ci powiedzieć, żebyś usunął się { get; set; }z playerklasy. Jeśli tak { get; set; }, to nie zadziała. Porównaj swoją playerklasę z tą, którą zamieściłem powyżej, a zrozumiesz, o czym mówię.
Programmer
1
Nie ma problemu. Zmienię to, gdy Unity doda obsługę tablic (co nastąpi bardzo szybko), więc nie będziesz już potrzebować tej klasy pomocnika.
Programista
1
Nie posunąłbym się nawet do stwierdzenia „Zapomnij o wszystkich bibliotekach innych firm”. JsonUtility ma ograniczenia. Nie zwraca obiektu JSON, na którym można wykonywać akcje. Na przykład otrzymuję plik json i chcę sprawdzić, czy jest dostępny klucz „sukcesu”. Nie mogę. JsonUtility wymaga od konsumenta znajomości dokładnej zawartości pliku json. Brak konwertera słowników. Robi więc dobre rzeczy, ale nadal wymagane jest korzystanie z oprogramowania zewnętrznego.
Everts
2
Użyj JsonHelper. W porządku. Jeśli utworzysz z nim Json, możesz również czytać json z nim bez dodatkowych kroków. Jedyny przypadek, w którym będziesz musiał zrobić dodatkowe rzeczy, to jeśli otrzymujesz tablicę json z serwera i to jest zawarte w rozwiązaniu, jest w mojej odpowiedzi. Innym sposobem JsonHelperjest umieszczenie klasy w innej klasie, a następnie nadanie jej List. To działa dla większości ludzi. Jeśli szukasz sposobu na zapisywanie i ładowanie danych gry, zobacz to . Ładujesz i zapisujesz za pomocą jednej linii kodu.
Programmer
17

Załóżmy, że masz taki JSON

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

Aby przeanalizować powyższy JSON w jedności, możesz utworzyć model JSON w ten sposób.

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

A następnie po prostu przeanalizuj w następujący sposób ...

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

Teraz możesz zmodyfikować JSON / CODE zgodnie ze swoimi potrzebami. https://docs.unity3d.com/Manual/JSONSerialization.html

Narottam Goyal
źródło
To faktycznie działa całkiem nieźle, działając z klasą taką jak Symbol, która również nie jest tablicą.
Gennon
4
Próbuję tego z Unity 2018, ale to nie działa: tablice nie są analizowane
Jean-Michaël Celerier
Używany w Unity 2018 i 2019. Działa świetnie. Uzyskaj dostęp do danych tablicy, takich jak: Debug.Log(myObject.result[0].symbol[0].data);lub for(var i = 0; i <= myObject.result.Length - 1; i ++) { Debug.Log(myObject.result[i].type); }lubforeach (var item in myObject.result) { Debug.Log(item.type); }
Towerss
@Narottam Goyal, twoja metoda nie działa w niektórych przypadkach, również bardzo trudne rozwiązanie dla początkujących,
skieruj
@JunedKhanMomin twoja odpowiedź robi w zasadzie to samo, ale bez uwzględnienia faktu, że to pytanie dotyczyło konkretnie tablicy poziomu głównego w danych JSON. Ogólnie powinieneś raczej odnieść się do odpowiedzi Programisty, która jest o wiele bardziej rozbudowana.
derHugo
2

musisz dodać [System.Serializable]do PlayerItemklasy, w ten sposób:

using System;
[System.Serializable]
public class PlayerItem   {
    public string playerId;
    public string playerLoc;
    public string playerNick;
}
Myan
źródło
1

Aby przeczytać plik JSON, zapoznaj się z tym prostym przykładem

Twój plik JSON (StreamingAssets / Player.json)

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

Skrypt 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
źródło
1
A co z tablicami? A co dodaje ta odpowiedź, która nie znalazła się już w zaakceptowanej odpowiedzi sprzed ponad 3 lat?
derHugo
@derHugo zawiera wezwanie, File.ReadAllTextktóre moim zdaniem jest pomocne i żadna inna odpowiedź nie wspomina :)
Ruzihm
@Ruzihm No cóż, powodem, dla którego żadna inna odpowiedź nie wspomniała o tym, jest to, że zakres tego pytania polega na tym, jak (de) serializować, a nie jak zrobić FileIO;)
derHugo
0

Nie przycinaj []i powinno być dobrze. []zidentyfikuj tablicę JSON, która jest dokładnie tym, czego potrzebujesz, aby móc iterować jej elementy.

Thomas Hilbert
źródło
0

Jak powiedział @Maximiliangerhardt, MiniJson nie ma możliwości prawidłowej deserializacji. Użyłem JsonFx i działa jak urok. Działa z[]

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
źródło
0

Możesz użyć Newtonsoft.Jsonpo prostu dodaj Newtonsoft.dlldo swojego projektu i użyj poniższego skryptu

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

    }
}

wprowadź opis obrazu tutaj

innym rozwiązaniem jest użycie 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);

    }
}

wprowadź opis obrazu tutaj

Seyed Morteza Kamali
źródło
0

JEŚLI używasz Vector3, to właśnie zrobiłem

1- Tworzę klasę Nazwij ją Gracz

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

}

2 - wtedy nazywam to tak

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- i to jest wynik

„Pozycja”: [{"x": - 2.8567452430725099, "y": - 2,4323320388793947, "z": 0,0}]}

Gara
źródło
0

Jedność <= 2019

Narottam Goyal miał dobry pomysł na zawinięcie tablicy w obiekt json, a następnie deserializację do struktury. W poniższym przykładzie zastosowano Generics do rozwiązania tego problemu dla tablic wszystkich typów, w przeciwieństwie do tworzenia nowej klasy za każdym razem.

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

Można go używać w następujący sposób:

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

Jedność 2020

W Unity 2020 jest oficjalny pakiet Newtonsoft , który jest znacznie lepszą biblioteką json.

Justin Meiners
źródło
1
Podane łącze jest martwe, ale to łącze jest wymienione jako artykuł pokrewny: docs.unity3d.com/Packages/[email protected]/ ... z uwagą: „To jest pakiet przeznaczony do wewnętrznego programowania w Unity Projekty i jako taki ten pakiet nie jest obsługiwany. Używaj na własne ryzyko. "
R2RT