Search Unity

Load Data from JSON Array with data structure constantly changing, How to implement dictionaries?

Discussion in 'Scripting' started by BooBi, Oct 16, 2019.

  1. BooBi

    BooBi

    Joined:
    Jan 18, 2010
    Posts:
    534
    Hi,

    I'm currently trying to load data from different JSON files and display it in the UI.

    Let's say I've got 15 buttons each linked with a loadfromJSON and a file attached to it, and a procedurally generated window (panel with texts) that will display the information showing in bold the name of the value and in italic the value itself once you click on a button.
    Each JSON is an array of items.

    I've written a reader with a wrapper etc to be able to read and display each data.
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using System.IO;
    5.  
    6. [System.Serializable]
    7. public class ObjDataSerializable
    8. {
    9.     public string json_featuretype;
    10.     public string Name;
    11.     public string unique_id;
    12. }
    13. /*
    14. *  Wrapper class for the SerializableItem class (into a List<>).
    15. */
    16. [System.Serializable]
    17. public class SerializableItemWrapper
    18. {
    19.     public List<ObjDataSerializable> Items;
    20. }
    and my JSON Structure is like this:
    Code (CSharp):
    1. [
    2.         {
    3.             "json_featuretype": "Data",
    4.             "Name": "16_SF_tpg_balk:400x400:2526996",
    5.             "unique_id": "3Qliei1WzDfBfhHXUG3F5O_25"
    6.         },
    7.         {
    8.             "json_featuretype": "Data",
    9.             "Name": "16_tpg_balk:400x400:2527074",
    10.             "unique_id": "3Qliei1WzDfBfhHXUG3F4k_26"
    11.         }
    12. ]
    In this example it's easy and currently working as the structure is the same between the two items in the JSON file. But in some cases, I won't have the name, or I'll get extra information.

    Therefore I can't work with this part as it should be generated based on the data from the JSON not from a predefined class.
    Code (CSharp):
    1. [System.Serializable]
    2. public class ObjDataSerializable
    3. {
    4.     public string json_featuretype;
    5.     public string Name;
    6.     public string unique_id;
    7. }
    The only var that will exist in all the items is the unique_id.
    Should I write a reader that reads the JSON, parse the items in strings and generate the UI based on that ? Therefore I would forget about making them usable variables and keep them as strings.
    How can I write an adaptable ObjDataSerializable ?

    Thanks in advance for your help !

    Boris
     
    Last edited: Oct 16, 2019
  2. csofranz

    csofranz

    Joined:
    Apr 29, 2017
    Posts:
    1,556
    I've found that in cases like this, you'd be much better off using Dictionaries instead of structs or classes. The code is slightly more messy, but usually orders of magnitute more flexible.
     
  3. BooBi

    BooBi

    Joined:
    Jan 18, 2010
    Posts:
    534
    I've found this example on the forum:
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4. using System.Collections.Generic;// this namespace is required to import dictionaries
    5. public class dictionaryExample : MonoBehaviour {
    6.     public Dictionary<string, bool> myDictionary = new Dictionary<string, bool>();// declair key type and value type : <string, bool>
    7.     public Dictionary<string, string> myDictionary2 = new Dictionary<string, string>();
    8.     // Use this for initialization
    9.     void Start () {
    10.         if (myDictionary.Count < 10) {// gets count on dictionary
    11.             string c = myDictionary.Count.ToString ();
    12.             myDictionary.Add (c, false); // adds to dictionary
    13.             myDictionary2.Add (c, c);
    14.         }
    15.         foreach (KeyValuePair<string, bool> i in myDictionary) { //you can use this  to return keys and values (key value pair)
    16.             Debug.Log (i.Key);// i.Key will rwtun the key for that KVP
    17.             Debug.Log(i.Value);// i.Value returns value fot the KVP
    18.         }
    19.         foreach (var i in myDictionary2) {// var can me used as a shortcut for many class types (in this case KeyValuePair <string, string>)
    20.             Debug.Log (i.Key);
    21.             Debug.Log(i.Value);
    22.         }
    23.         Debug.Log (myDictionary ["0"]);// this overload : myDictionary["0"]   will return the value associated to the Key : "0"
    24.         if (myDictionary.ContainsKey ("9")) {
    25.             myDictionary.Remove ("9"); // will remove a KVP
    26.             Debug.Log ("Has Removed");
    27.         }
    28.         myDictionary2.Clear ();// will clear the dictionary
    29.     }
    30. }
    I guess that I should write each item like this: KeyValuePair <string, string> then, that would be a lot easier indeed. Thanks a lot !

    How should I cut out the item ? Write my how parser ? Any idea ?
     
  4. BooBi

    BooBi

    Joined:
    Jan 18, 2010
    Posts:
    534
    From what I've tested, I need to split my Json Array each object being a dictionary of KeyValuePair.

    So with a JSON like this:
    Code (CSharp):
    1. [
    2.         {
    3.             "json_featuretype": "Data",
    4.             "Name": "16_SF_tpg_balk:400x400:2526996",
    5.             "unique_id": "3Qliei1WzDfBfhHXUG3F5O_25"
    6.         },
    7.         {
    8.             "json_featuretype": "Data",
    9.             "Name": "16_tpg_balk:400x400:2527074",
    10.             "unique_id": "3Qliei1WzDfBfhHXUG3F4k_26",
    11.             "Length": "400",
    12.             "Width": "400"
    13.         }
    14. ]
    I should get two dictionaries like this:

    Dictionary 1:
    - Key: "json_featuretype", Value: "Data"
    - Key: "Name", Value: "16_SF_tpg_balk:400x400:2526996"
    - Key: "unique_id", Value: "3Qliei1WzDfBfhHXUG3F5O_25"

    Dictionary 2:
    - Key: "json_featuretype", Value: "Data"
    - Key: "Name", Value: "16_tpg_balk:400x400:2527074"
    - Key: "unique_id", Value: "3Qliei1WzDfBfhHXUG3F4k_26"
    - Key: "Length", Value: "400"
    - Key: "Width", Value: "400"

    How should I setup my reader ? I don't get it ? I've managed to split each object ( { 1 } & { 2 }) into a list of string, using a wrapper. It does find the correct amount of object but I can't use them.

    Here is my code :

    Code (CSharp):
    1.     void LoadFromJSONFile(TextAsset jsonFileLoaded)
    2.     {
    3.         SerializableItemWrapper2 wrapper = new SerializableItemWrapper2();
    4.         wrapper = JsonUtility.FromJson<SerializableItemWrapper2>(JsonCleaner(jsonFileLoaded));
    5.  
    6.         Debug.Log(" WRAPPER ITEM COUNT : " + wrapper.Items.Count); // I GET THE CORRECT COUNT
    7.  
    8.         for (int i = 0; i < wrapper.Items.Count; i++)
    9.         {
    10.             Debug.Log(wrapper.Items[i]); // DOESN'T DISPLAY ANYTHING. I CAN'T ACCESS THE STORED STRING
    11.         }
    12.     }
    13.  
    14.     /*
    15. *  Wrapper class for the SerializableItem class (into a List<>).
    16. */
    17.     [System.Serializable]
    18.     public class SerializableItemWrapper2
    19.     {
    20.         public List<string> Items;
    21.     }
    22.  
    For the fact that Unity can't use top level arrays in JSON, I'm correcting it myself with the function JsonCleaner() when I'm loading the JSON file by including my JSON in { "Items": [ JSON ] }.

    Any idea on why my code doesn't work ? How can I implement dictionaries instead of the List<string> ? I need to convert/parse each string from my list into a new dictionary.

    EDIT: I could play with an hashtable instead of a dictionary, but same problem I don't get how to split first the array of object and then split each objects into a new hashtable/dictionary

    Thanks in advance for your help !
     
    Last edited: Oct 16, 2019
  5. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    Any reason you are not using a JSON library API? There are several, no need to reinvent the wheel.
     
  6. BooBi

    BooBi

    Joined:
    Jan 18, 2010
    Posts:
    534
    That's the files I'm continuously receiving and the app needs to manage (it's not game related but more AEC).
    I can ask if I could receive XML maybe, but there isn't much they can do to manipulate the files prior sending them to me/unity. (the full workflow will be automated).
    I'm using an editor script to extract the data from the different Json prior sending it with other information/gameobjects/scripts as assetbundles.

    EDIT: Sorry, early morning, I've completely misread your post.
    What would you recommend? I think I don't have the knowledge yet on how the whole thing (Json libraries etc) works and how to write what I want. I know there are limitations to the JsonUtility from Unity, I read that it can't handle top level arrays but it was on the roadmap (few years ago). I'm only starting to really understand the structure of the Json (in general, arrays, objects, key, value...).
    Do you have any recommendation on which api to choose ? Odin Serializer ? What should I look for in terms of features to be able to do what I want.
     
    Last edited: Oct 17, 2019