Serialisasi dan Deserialisasi Json dan Json Array di Unity

99

Saya memiliki daftar item yang dikirim dari file PHP ke unity WWW.

The WWW.textterlihat seperti:

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

Di mana saya memangkas ekstra []dari string. Ketika saya mencoba mengurai menggunakan Boomlagoon.JSON, hanya objek pertama yang diambil. Saya menemukan bahwa saya harus deserialize()daftar dan telah mengimpor MiniJSON.

Tapi saya bingung bagaimana cara deserialize()daftar ini. Saya ingin mengulang setiap objek JSON dan mengambil data. Bagaimana saya bisa melakukan ini di Unity menggunakan C #?

Kelas yang saya gunakan adalah

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

Setelah pemangkasan, []saya dapat mengurai json menggunakan MiniJSON. Tapi itu hanya kembali yang pertama 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));
}

Terima kasih!

dil33pm
sumber
Mengapa Anda menghapus bagian luar [dan ]? Itulah yang membuatnya menjadi sebuah daftar. Berhenti saja menghapusnya, dan deserialize sebagai array atau daftar dan saya berharap itu baik-baik saja. Silakan posting kode yang Anda coba.
Jon Skeet
Tunjukkan kelas yang digunakan untuk deserialisasi. Formatnya aneh, mengapa playerId kedua tidak dibungkus dengan kurung kurawal? Ini harus deserialize ke daftar sesuatu, seperti List<PlayerLocation>, karena ini adalah array.
Maximilian Gerhardt
@MaximilianGerhardt Maaf, kurung kurawal buka salah ketik. Memperbaiki itu dalam pertanyaan dan menambahkan kode juga. Terima kasih.
dil33pm
1
Saya pikir ada yang salah dengan pemahaman Anda tentang bagaimana perpustakaan ini menangani deserializiation. Ini bukan deserialisasi biasa (seperti yang mungkin Anda lihat di dalamnya Newtonsoft.Json), tetapi Json.Deserialize()SELALU mengembalikan a IDictionary<string,object>kepada Anda dan Anda beroperasi List<object>. Lihat stackoverflow.com/a/22745634/5296568 . Lebih disukai, dapatkan deserializer JSON yang lebih baik yang melakukan deserialisasi yang biasa Anda lakukan.
Maximilian Gerhardt
@MaximilianGerhardt saya coba dengan IDictionary<string,object>. Saya bisa mengeluarkan nilainya, tetapi hanya yang pertama KeyValuePair<>.
dil33pm

Jawaban:

251

Unity menambahkan JsonUtility ke API mereka setelah Pembaruan 5.3.3 . Lupakan semua pustaka pihak ketiga kecuali Anda melakukan sesuatu yang lebih rumit. JsonUtility lebih cepat daripada perpustakaan Json lainnya. Perbarui ke versi Unity 5.3.3 atau lebih tinggi, lalu coba solusi di bawah ini.

JsonUtilityadalah API ringan. Hanya tipe sederhana yang didukung. Itu tidak mendukung koleksi seperti Kamus. Satu pengecualian adalah List. Ini mendukung Listdan Listarray!

Jika Anda perlu membuat serial Dictionaryatau melakukan sesuatu selain hanya membuat serial dan deserialisasi tipe data sederhana, gunakan API pihak ketiga. Jika tidak, lanjutkan membaca.

Contoh kelas untuk membuat serial:

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

1. SATU OBYEK DATA (NON-ARRAY JSON)

Serialisasi Bagian A :

Serialisasi ke Json dengan public static string ToJson(object obj);metode.

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

Keluaran :

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

Serialisasi Bagian B :

Serialisasi ke Json dengan public static string ToJson(object obj, bool prettyPrint);metode overload. Hanya meneruskan trueke JsonUtility.ToJsonfungsi tersebut akan memformat data. Bandingkan keluaran di bawah dengan keluaran di atas.

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

Keluaran :

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

Deserialisasi Bagian A :

Deserialisasi json dengan public static T FromJson(string json);metode overload.

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

Deserialisasi Bagian B :

Deserialisasi json dengan public static object FromJson(string json, Type type);metode overload.

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

Deserialisasi Bagian C :

Deserialisasi json dengan public static void FromJsonOverwrite(string json, object objectToOverwrite);metode. Saat JsonUtility.FromJsonOverwritedigunakan, tidak ada instance baru dari Objek yang Anda deserialisasi akan dibuat. Ini hanya akan menggunakan kembali contoh yang Anda berikan dan menimpa nilainya.

Ini efisien dan harus digunakan jika memungkinkan.

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. GANDA DATA (ARRAY JSON)

Json Anda berisi beberapa objek data. Misalnya playerIdmuncul lebih dari sekali . Unity JsonUtilitytidak mendukung array yang karena masih baru tapi Anda dapat menggunakan penolong kelas dari orang ini untuk mendapatkan berbagai bekerja dengan JsonUtility.

Buat kelas bernama JsonHelper. Salin JsonHelper langsung dari bawah.

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

Serialisasi Json Array :

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

Keluaran :

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

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

Keluaran :

Powai

Pengguna2


Jika ini adalah array Json dari server dan Anda tidak membuatnya dengan tangan :

Anda mungkin harus menambahkan {"Items":di depan string yang diterima lalu menambahkan }di akhir.

Saya membuat fungsi sederhana untuk ini:

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

maka Anda dapat menggunakannya:

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

3. Deserialisasi string json tanpa class && De-serializing Json dengan properti numerik

Ini adalah Json yang dimulai dengan angka atau properti numerik.

Sebagai contoh:

{ 
"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 JsonUtilitytidak mendukung ini karena properti "15m" dimulai dengan angka. Variabel kelas tidak dapat dimulai dengan bilangan bulat.

Unduh SimpleJSON.csdari wiki Unity .

Untuk mendapatkan properti "15 juta" dari USD:

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

Untuk mendapatkan properti "15m" dari ISK:

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

Untuk mendapatkan properti "15m" dari NZD:

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

Properti Json lainnya yang tidak dimulai dengan digit numerik dapat ditangani oleh JsonUtility Unity.


4. PEMECAHAN MASALAH JsonUtility:

Masalah saat membuat serial dengan JsonUtility.ToJson?

Mendapatkan string kosong atau " {}" dengan JsonUtility.ToJson?

A . Pastikan bahwa kelas tersebut bukan array. Jika ya, gunakan kelas helper di atas dengan JsonHelper.ToJsonsebagai ganti JsonUtility.ToJson.

B . Tambahkan [Serializable]ke atas kelas Anda membuat serial.

C . Hapus properti dari kelas. Misalnya, di variabel, public string playerId { get; set; } hapus { get; set; } . Unity tidak dapat membuat serial ini.

Masalah saat melakukan deserialisasi JsonUtility.FromJson?

A . Jika Anda mendapatkan Null, pastikan bahwa Json bukan array Json. Jika ya, gunakan kelas helper di atas dengan JsonHelper.FromJsonsebagai ganti JsonUtility.FromJson.

B . Jika Anda mendapatkan NullReferenceExceptionwaktu deserialisasi, tambahkan [Serializable]ke bagian atas kelas.

C. Masalah lainnya, pastikan json Anda valid. Buka situs ini di sini dan tempel json. Ini akan menunjukkan kepada Anda apakah json valid. Itu juga harus menghasilkan kelas yang tepat dengan Json. Pastikan untuk menghapus remove { get; set; } dari setiap variabel dan juga tambahkan [Serializable]ke bagian atas setiap kelas yang dihasilkan.


Newtonsoft.Json:

Jika karena alasan tertentu Newtonsoft.Json harus digunakan, periksa versi fork untuk Unity di sini . Perhatikan bahwa Anda mungkin mengalami crash jika fitur tertentu digunakan. Hati-hati.


Untuk menjawab pertanyaan Anda :

Data asli Anda adalah

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

Tambahkan {"Items": di depannya lalu tambahkan } di ujungnya .

Kode untuk melakukan ini:

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

Sekarang kamu punya:

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

Untuk cerita bersambung yang beberapa data dari php sebagai array , Anda sekarang dapat melakukan

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

playerInstance[0] adalah data pertamamu

playerInstance[1] adalah data kedua Anda

playerInstance[2] adalah data ketiga Anda

atau data di dalam kelas dengan playerInstance[0].playerLoc, playerInstance[1].playerLoc, playerInstance[2].playerLoc......

Anda dapat menggunakan playerInstance.Lengthuntuk memeriksa panjangnya sebelum mengaksesnya.

CATATAN: Hapus { get; set; } dari playerkelas. Jika sudah { get; set; }, itu tidak akan berhasil. Unity JsonUtilitytidak TIDAK bekerja dengan anggota kelas yang didefinisikan sebagai sifat .

Programmer
sumber
Saya mengembalikan array baris mysqlkueri dari PHP menggunakan json_encode($row). Jadi responsnya terdiri dari beberapa JSONObject dalam format [{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]. Saya mencoba JsonUtility, tetapi saya tidak bisa menghilangkan nama objek dan mendapatkan objek json individual. Jika Anda dapat membantu saya dengan itu.
dil33pm
2
Lihat kode yang saya posting di atas. Ini menunjukkan tiga cara untuk melakukannya dengan JsonUtility.FromJson. Saya lupa memberitahu Anda untuk keluar { get; set; }dari playerkelas. Jika sudah { get; set; }, itu tidak akan berhasil. Bandingkan playerkelas Anda dengan kelas yang saya posting di atas dan Anda akan mengerti apa yang saya katakan.
Programmer
1
Tidak masalah. Saya akan mengedit ini ketika Unity menambahkan dukungan untuk array (yang segera) sehingga Anda tidak membutuhkan kelas Helper itu lagi.
Programmer
1
Saya tidak akan mengatakan lebih jauh tentang "Lupakan semua perpustakaan pihak ke-3". JsonUtility memiliki batasan. Itu tidak mengembalikan objek JSON tempat Anda dapat melakukan tindakan. Misalnya, saya mendapatkan file json dan ingin memeriksa apakah kunci "sukses" tersedia. Tidak bisa. JsonUtility mengharuskan konsumen mengetahui konten yang tepat dari file json. Juga, tidak ada konverter kamus. Jadi itu melakukan beberapa hal baik tetapi penggunaan pihak ke-3 masih diperlukan.
Everts
2
Gunakan JsonHelper. Tidak apa-apa. Jika Anda membuat Json dengannya, Anda juga dapat membaca json dengannya tanpa langkah tambahan. Satu-satunya saat Anda mungkin perlu melakukan hal-hal tambahan adalah jika Anda menerima array json dari server dan yang termasuk dalam solusi ada di jawaban saya. Cara lain tanpanya JsonHelperadalah dengan menempatkan kelas di kelas lain kemudian menjadikannya a List. Ini telah berhasil bagi kebanyakan orang. Jika Anda mencari cara untuk menyimpan dan memuat data game, lihat ini . Anda memuat dan menyimpan dengan satu baris kode.
Programmer
17

Asumsikan Anda mendapatkan JSON seperti ini

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

Untuk mengurai JSON di atas menjadi satu, Anda dapat membuat model JSON seperti ini.

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

Dan kemudian cukup parsing dengan cara berikut ...

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

Sekarang Anda dapat memodifikasi JSON / CODE sesuai kebutuhan Anda. https://docs.unity3d.com/Manual/JSONSerialization.html

Narottam Goyal
sumber
Ini sebenarnya bekerja dengan cukup baik, membuatnya berfungsi dengan kelas seperti Symbol yang juga bukan array.
Gennon
4
Saya mencoba ini dengan unity 2018 tetapi ini tidak berhasil: array tidak diurai
Jean-Michaël Celerier
Digunakan dalam kesatuan 2018 dan 2019. Berfungsi dengan baik. Mengakses data array seperti: Debug.Log(myObject.result[0].symbol[0].data);atau for(var i = 0; i <= myObject.result.Length - 1; i ++) { Debug.Log(myObject.result[i].type); }atauforeach (var item in myObject.result) { Debug.Log(item.type); }
Towerss
@Narottam Goyal, metode Anda tidak berfungsi dalam beberapa kasus, juga merupakan solusi yang sangat sulit untuk pemula, lihat jawaban saya ini di tautan
Juned Khan Momin
@JunedKhanMomin jawaban Anda pada dasarnya sama tetapi tanpa mengatasi fakta bahwa pertanyaan di sini adalah tentang larik tingkat akar dalam data JSON secara spesifik. Secara umum, Anda sebaiknya merujuk pada jawaban Programmer yang jauh lebih rumit.
derHugo
2

Anda harus menambahkan [System.Serializable]ke PlayerItemkelas, seperti ini:

using System;
[System.Serializable]
public class PlayerItem   {
    public string playerId;
    public string playerLoc;
    public string playerNick;
}
Myan
sumber
1

Untuk Membaca File JSON, lihat contoh sederhana ini

File JSON Anda (StreamingAssets / Player.json)

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

C # Script

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
sumber
1
Bagaimana dengan array? Dan apakah jawaban ini menambahkan yang belum disebutkan dalam jawaban yang diterima lebih dari 3 tahun yang lalu?
derHugo
@derHugo itu termasuk panggilan File.ReadAllTextyang menurut saya membantu dan tidak ada jawaban lain yang menyebutkan :)
Ruzihm
@Ruzihm yah, alasan mengapa tidak ada jawaban lain yang disebutkan karena ruang lingkup pertanyaan ini adalah bagaimana (de) membuat serialisasi .. bukan bagaimana melakukan FileIO;)
derHugo
0

Jangan memangkasnya []dan Anda akan baik-baik saja. []mengidentifikasi larik JSON yang persis seperti yang Anda perlukan untuk dapat mengulang elemennya.

Thomas Hilbert
sumber
0

Seperti yang dikatakan @Maximiliangerhardt, MiniJson tidak memiliki kemampuan untuk melakukan deserialisasi dengan benar. Saya menggunakan JsonFx dan bekerja dengan sangat baik. Bekerja dengan[]

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

Anda dapat menggunakan Newtonsoft.Jsoncukup tambahkan Newtonsoft.dllke proyek Anda dan gunakan skrip di bawah ini

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

    }
}

masukkan deskripsi gambar di sini

solusi lain adalah menggunakan 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);

    }
}

masukkan deskripsi gambar di sini

Seyed Morteza Kamali
sumber
0

JIKA Anda menggunakan Vector3, inilah yang saya lakukan

1- Saya membuat kelas Beri nama Player

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

}

2- lalu saya menyebutnya seperti ini

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- dan inilah hasilnya

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

Gara
sumber
0

Unity <= 2019

Narottam Goyal memiliki ide yang bagus untuk membungkus array dalam objek json, dan kemudian melakukan deserialisasi menjadi struct. Berikut ini menggunakan Generik untuk memecahkan masalah ini untuk semua tipe array, sebagai lawan untuk membuat kelas baru setiap saat.

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

Ini dapat digunakan dengan cara berikut:

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

Unity 2020

Di Unity 2020 ada paket newtonsoft resmi yang merupakan perpustakaan json yang jauh lebih baik.

Justin Meiners
sumber
1
Tautan yang Anda berikan sudah mati, tetapi tautan ini terdaftar sebagai artikel terkait: docs.unity3d.com/Packages/[email protected]/… dengan catatan: "Ini adalah paket yang ditujukan untuk Pengembangan Unity internal Proyek dan dengan demikian paket ini tidak didukung. Gunakan dengan risiko Anda sendiri. "
R2RT