UnityでのJsonとJson配列のシリアライズとデシリアライズ


96

PHPファイルからUnityに送信するアイテムのリストがあります。 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; }
}

トリミング後、[]MiniJSONを使用してjsonを解析できます。しかし、それは最初のものだけを返してい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));
}

ありがとう!


なぜあなたは外を削除した[]?それがリストになっています。それを削除するのをやめて、配列またはリストとして逆シリアル化すれば、問題ないはずです。試したコードを投稿してください。
Jon Skeet

逆シリアル化に使用されるクラスを見せてください。形式が奇妙ですが、2番目のplayerIdが中括弧で囲まれていないのはなぜですか?これは配列なList<PlayerLocation>ので、などのリストに逆シリアル化する必要あります。
Maximilian Gerhardt

@MaximilianGerhardt申し訳ありませんが、中括弧はタイプミスでした。質問でそれを修正し、コードも追加しました。ありがとう。
dil33pm 2016年

1
このライブラリが逆シリアル化をどのように処理するかについての理解に問題があると思います。これは通常の逆シリアル化ではありませんが(おそらくで見たようにNewtonsoft.Json)、Json.Deserialize()常にa IDictionary<string,object>が返され、操作を行いList<object>ます。stackoverflow.com/a/22745634/5296568をご覧ください。できれば、使い慣れた逆シリアル化を行うより優れたJSONデシリアライザーを入手してください。
Maximilian Gerhardt 2016年

@MaximilianGerhardt私が試してみましたIDictionary<string,object>。私は価値を引き出すことができますが、最初のものだけKeyValuePair<>です。
dil33pm 2016年

回答:


244

Unityは5.3.3アップデート後にAPIにJsonUtilityを追加しました。より複雑なことをしているのでない限り、サードパーティのライブラリはすべて忘れてください。JsonUtilityは他のJsonライブラリよりも高速です。Unity 5.3.3に更新バージョン以上に、以下の解決策を試してください。

JsonUtility軽量APIです。単純型のみがサポートされています。辞書などのコレクションサポートしていませ。1つの例外はListです。対応ListList配列!

をシリアル化する必要がある場合、Dictionaryまたは単純なデータ型をシリアル化および逆シリアル化する以外の何かを行う必要がある場合は、サードパーティのAPIを使用します。それ以外の場合は、読み続けてください。

シリアル化するクラスの例:

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

1. 1つのデータオブジェクト(非アレイJSON)

パートAのシリアル化

public static string ToJson(object obj);メソッドを使用してJsonにシリアルします。

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のシリアル化

public static string ToJson(object obj, bool prettyPrint);メソッドオーバーロードでJsonにシリアルします。単純に渡すtrueJsonUtility.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のデシリアライズ

public static T FromJson(string json);メソッドオーバーロードでjsonをシリアライズします。

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

パートBのデシリアライズ

public static object FromJson(string json, Type type);メソッドオーバーロードでjsonをシリアライズします。

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

パートCの逆シリアル化

public static void FromJsonOverwrite(string json, object objectToOverwrite);メソッドでjsonをシリアライズします。ときに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複数登場しまし。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);

出力

ポワイ

ユーザー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」プロパティは数字で始まるため、Unity はこれをサポートしていません。クラス変数を整数で始めることはできません。

SimpleJSON.csUnityのwikiからダウンロード

USDの "15m"プロパティを取得するには:

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

ISKの「15m」プロパティを取得するには:

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ますか?

A。クラスが配列でないことを確認してください。もしそうなら、のJsonHelper.ToJson代わりに上記のヘルパークラスを使用してくださいJsonUtility.ToJson

B[Serializable]シリアル化するクラスの先頭に追加します。

C。クラスからプロパティを削除します。たとえば、変数でをpublic string playerId { get; set; } 削除し { get; set; }ます。Unityはこれをシリアル化できません。

問題とデシリアライズJsonUtility.FromJson

A。を取得した場合Nullは、JsonがJson配列でないことを確認してください。もしそうなら、のJsonHelper.FromJson代わりに上記のヘルパークラスを使用してくださいJsonUtility.FromJson

BNullReferenceException逆シリアル化中に取得した場合[Serializable]は、クラスの先頭に追加します。

C .ANY他の問題は、あなたの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] あなたの2番目のデータです

playerInstance[2] あなたの3番目のデータです

またはを持つクラス内のデータplayerInstance[0].playerLocplayerInstance[1].playerLocplayerInstance[2].playerLoc......

playerInstance.Lengthアクセスする前に長さを確認するために使用できます。

注: クラスから削除 { get; set; }playerます。あなたが持っている場合{ get; set; }、それは動作しません。Unity は、プロパティとして定義されているクラスメンバーではJsonUtility機能しません


mysql使用してPHPからクエリの行の配列を返していますjson_encode($row)。したがって、応答は、形式の複数のJSONObjectで構成されます[{"playerId":"1","playerLoc":"Powai"},{"playerId":"2","playerLoc":"Andheri"},{"playerId":"3","playerLoc":"Churchgate"}]。JsonUtilityを試しましたが、オブジェクトを逆シリアル化して個々のjsonオブジェクトを取得できませんでした。あなたがそれを手伝ってくれるなら。
dil33pm 2016年

2
上記で投稿したコードを見てください。これは、でそれを行う3つの方法を示していますJsonUtility.FromJson。私は削除するように伝えるのを忘れて{ get; set; }からplayerクラス。あなたが持っている場合{ get; set; }、それは動作しません。あなたのplayerクラスを上記で投稿したクラスと比較すると、私の言っていることが理解できます。
プログラマー

1
問題ない。Unityが配列のサポートを追加するときに(これは間もなく)、これを編集するので、ヘルパークラスはもう必要ありません。
プログラマ

1
「サードパーティのライブラリをすべて忘れる」とまでは言いません。JsonUtilityには制限があります。アクションを実行できるJSONオブジェクトは返しません。たとえば、jsonファイルを取得し、「成功」キーが使用可能かどうかを確認したいとします。できません。JsonUtilityでは、コンシューマがjsonファイルの正確な内容を知っている必要があります。また、辞書コンバータはありません。だからそれはいくつかの良いことをしますが、サードパーティの使用はまだ必要です。
Everts

2
を使用しJsonHelperます。大丈夫だよ。それを使用してJsonを作成すると、追加の手順を実行しなくても、Jsonを読み取ることができます。サーバーからjson配列を受信して​​いて、ソリューションに含まれている場合にのみ、追加の作業が必要になる場合があります。せずに別の方法JsonHelperは、クラスを別のクラスに配置し、それをにすることListです。これはほとんどの人のために働いています。あなたがゲームデータを保存およびロードする方法を探しているなら、参照これを1行のコードでロードして保存します。
プログラマ

17

このようなJSONがあると仮定します

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

上記のJSONを1つに解析するには、次のような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
私は団結2018でこれをしようとしているが、これは動作しません:配列が解析されません
ジャン-マイケルCelerier

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 '29

@Narottam Goyal氏は、あなたのメソッドは、このスレッドで私がこの答えを参照してください、また場合によっては、初心者のための非常に困難な溶液中で動作していないリンク
JunedカーンMomin

@JunedKhanMominあなたの答えは基本的に同じですが、ここでの質問は具体的にはJSONデータのルートレベルの配列に関するものであるという事実に対処するものではありません。一般的には、プログラマーの回答を参考にする必要があります。
derHugo

2

あなたはこのよう[System.Serializable]PlayerItemクラスに追加する必要があります:

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

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

0

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

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-プレイヤーにクラスという名前のクラスを作成します

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

Unity <= 2019

Narottam Goyalは、配列を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);

Unity 2020

Unity 2020には、はるかに優れたjsonライブラリである公式のnewtonsoftパッケージがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.