LoginSignup
13
9

More than 5 years have passed since last update.

UnityでJSONの構造を確認して、構造に応じた型へ変換する

Last updated at Posted at 2016-09-01

すごい広島 172のメモ
以下のJSONをUnityで読み込みたい。

{
    "type": "Point",
    "value": {
        "x": 1,
        "y": 2,
        "z": 3,
    }
}
{
    "type": "Press",
    "value": {
        "code": "a",
    }
}

typeによってvalueの中身が違うようなJSONです。
JsonUtilityではDictionary型への変換はできなくて、変換する先の型を用意する必要がある。
こういったタイプの読み込み型の方針については公式にもちゃんとかいてある。

型が未知の場合の FromJson() の使用

JSON を「共通」のフィールドを持つクラスか構造体にデシリアライズします。それから、そのフィールドの値を利用して、2 度目のデシリアライズで実際に求める型にします。

http://docs.unity3d.com/jp/current/Manual/JSONSerialization.html

ということで以下のような4つのクラスを用意する。

// typeを読むためのクラス
[Serializable]
class SeekJSONType {
    public string type;
}

// typeがわかった後に使うルート要素のクラス
[Serializable]
class Envelope<Value> {
    public string type;
    public Value value;
}

[Serializable]
class PointMessage {
    public float x;
    public float y;
    public float z;
}

[Serializable]
class PressMessage {
    public string code;
}

以下のように使う

var seekType = JsonUtility.FromJson<SeekJSONType>(str);
switch (seekType.type) {
    case "Point":
        var point = JsonUtility.FromJson<Envelope<PointMessage>>(str);
        // pointを使った処理
        break;
    case "Press": {
        var press = JsonUtility.FromJson<Envelope<PressMessage>>(str);
        // pressを使った処理
        break;
    }
}

実行例

コード。

using UnityEngine;
using System.Collections;

using System;

// typeを読むためのクラス
[Serializable]
class SeekJSONType {
    public string type;
}

// typeがわかった用のルート要素のクラス
[Serializable]
class Envelope<Value> {
    public string type;
    public Value value;
}

[Serializable]
class PointMessage {
    public double x;
    public double y;
    public double z;
}

[Serializable]
class PressMessage {
    public string code;
}


public class JsonFromSample : MonoBehaviour {

    // Use this for initialization
    void Start () {
        read ("{\"type\":\"Point\",\"value\":{\"x\":1,\"y\": 2,\"z\":3}}");
        read ("{\"type\":\"Press\",\"value\":{\"code\":\"a\"}}");
    }

    void read (string jsonString) {
        var seekType = JsonUtility.FromJson<SeekJSONType>(jsonString);
        switch (seekType.type) {
        case "Point":
            var point = JsonUtility.FromJson<Envelope<PointMessage>> (jsonString).value;
            Debug.Log (String.Format("Point<{0},{1},{2}>", point.x, point.y, point.z));
            break;
        case "Press":
            var press = JsonUtility.FromJson<Envelope<PressMessage>>(jsonString).value;
            Debug.Log (String.Format("Press<{0}>", press.code));
            break;
        }
    }

    // Update is called once per frame
    void Update () {

    }
}

実行結果。

Kobito.BWSJaU.png

感想

ジェネリクスが使えてちょっと楽ができた。
switchが文字列でも使えてちょっと楽ができた。
C#細かいところわからないので、Scalaでかけたらいいなって個人的には思った。

参考

13
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
9