- Home /
Parsing Nested Arrays with JsonUtility
I'm trying to parse this Json file with JsonUtility, the only problem is I cannot get the array of coordinates.
{
"features": [
{ "type": "Feature", "properties": { "id": 1.000000, "osm_id": -60.255, "name": "test", "type": "test" }, "geometry": { "type": "Polygon", "coordinates": [ [ [ 11.363926, 3.544844 ], [ 11.363489, 3.398182 ] ] ] } } ]
}
This is my code:
[System.Serializable]
public class features{
public string type;
public properties properties;
public geometry geometry;
};
[System.Serializable]
public class PlayerStatsList {
public List <features> features;
};
[System.Serializable]
public class properties{
public int id;
public int osm_id;
public string name;
public string type;
}
[System.Serializable]
public class geometry{
public string type;
//some way to get coordinates
}
I have tried some ways of accessing coordinates from other solutions like class of float array in a nested class, but it doesn't work, any help would be appreciated.
Answer by Bunny83 · Mar 07, 2017 at 02:20 PM
That's not possible with Unity's JsonUtility. You have to understand that the JsonUtility is not a general purpose JSON serializer / parser. It is build on top of Unity's serialization logic. Nested / jagged arrays or multidimensional arrays aren't supported by Unity's serialization system, so they can't be deserialized.
You basically have two options:
either build your serializable classes in a way that Unity can serialize and derive your JSON structure from that.
or if you want to use your own JSON structure, don't use JsonUtility and use a general purpose JSON parser.
One example would be my SimpleJSON parser. It's far from being perfect and doesn't deserialize to actual classes, but allow easy access to any information stored in a JSON file.
You can also easily add extension method to simplify the usage of certain Unity types. For example:
public static class JSONNodeUnityExt
{
public static Vector4 ToVector4(this JSONNode aNode)
{
if (aNode is JSONArray)
return new Vector4(aNode[0].AsFloat, aNode[1].AsFloat, aNode[2].AsFloat, aNode[3].AsFloat);
else if (aNode is JSONClass)
return new Vector4(aNode["x"].AsFloat, aNode["y"].AsFloat, aNode["z"].AsFloat, aNode["w"].AsFloat);
return Vector4.zero;
}
public static Vector3 ToVector3(this JSONNode aNode)
{
if (aNode is JSONArray)
return new Vector3(aNode[0].AsFloat, aNode[1].AsFloat, aNode[2].AsFloat);
else if (aNode is JSONClass)
return new Vector3(aNode["x"].AsFloat, aNode["y"].AsFloat, aNode["z"].AsFloat);
return Vector3.zero;
}
public static Vector2 ToVector2(this JSONNode aNode)
{
if (aNode is JSONArray)
return new Vector2(aNode[0].AsFloat, aNode[1].AsFloat);
else if (aNode is JSONClass)
return new Vector2(aNode["x"].AsFloat, aNode["y"].AsFloat);
return Vector2.zero;
}
}
This allows easy conversion of a JSONNode into a Vector2/3/4. In your specific case you could do:
var v1 = rootNode["features"][0]["geometry"]["coordinates"][0][0].ToVector2();
var v2 = rootNode["features"][0]["geometry"]["coordinates"][0][1].ToVector2();
Of course you usually don't use the full path every time:
var coords = rootNode["features"][0]["geometry"]["coordinates"][0];
for(int i = 0; i < coords.Count; i++)
{
var v = coords[i].ToVector2();
...
}
Of course you can also make an extension method that converts a JSONNode into a list of coordinates:
public static List<Vector2> ToVector2List(this JSONNode aNode)
{
if (aNode == null || !(aNode is JSONArray))
return null; // or new List<Vector2>();
var list = new List<Vector2>(aNode.Count);
for(int i = 0; i < aNode.Count; i++)
{
var v = aNode[i].ToVector2();
list.Add(v);
}
return list;
}
Now you could simply do:
List<Vector2> coords = rootNode["features"][0]["geometry"]["coordinates"][0].ToVector2List();
If you prefer arrays, just create an extension for that ^^.
Of course there are other JSON parsing solutions out there. LitJson is quite popular but has it's own restrictions.
I'm glad you have replied to my post, Bunny83. SimpleJSON parser that you have written was the first thing I tried, but unfortunately I kept getting this error "NotImplementedException: null".
The files I am using are between 3-10$$anonymous$$B, and when I truncated one of the JSON files I was able to use your parser, but I need to parse the complete data, but it gives me the above error. Thanks a lot for your input.
I'll just divide my files into smaller files to be able to access it like this, SimpleJSON keeps throwing exceptions for large files. Thanks Bunny83.
No, it doesn't throw exceptions for large files ^^. The problem here is actually not my code but code that has been added by someone else (it's a wiki, you know ^^). Initially i did not "remember" the type of each json type and simply store it as string in a JSONData node. Of course when generating json back out of the node tree all values would have been strings, even when they were numbers, true, false or null.
The NotImplemented exception is thrown by the "Numberize" method that this guy added. He simply assumed everything that is not a string is either a number or a boolean value. Though he forget about the special value null
. This null value is causing the exception. So your JSON file probably contains a null value.
$$anonymous$$y original version on github shouldn't have that problem. A quick in-place fix would be to add a case for null inside "Numberize"
static JSONData Numberize(string token)
{
// [ .... ]
if (token == "null")
return new JSONData("null");
throw new NotImplementedException(token);
}
I have actually changed a lot to my "personal" version. (I also finally renamed JSONClass to JSONObject ^^). Since it's not that hard to parse the different values up front i created seperate data nodes for the various types. If you want my latest version i can upload it after polishing it a bit ^^
I'll patch the SimpleJSON.cs and test it now. I'd be glad to use your latest version. Thank you very much Bunny83, much appreciated ^^
I feel the need to express how outrageous this failing is. A multidimensional array is very common, and this problem wastes a lot of a user's time.
It is not very common in the serialization domain of Unity since it's not supported by the serializer at all. As i said in this answer the JsonUtility is just a json equivalent of Unity's serializer. It is not meant to be a general purpose json parser. You simply expect that it can do things it wasn't designed for. The documentaion does mention those limitations
JSON on it's own doesn't have support for multidimensional arrays but only jagged / nested arrays. So even when you have a serializer that supports jagged arrays it probably won't support multidimensional arrays as they have to be rectangular. Jagged arrays are not required to be rectangular and therefore a proper mapping might not be possible.
I've actually written SimpleJSON before Unity implemented the JsonUtility. Personally i don't like the fact that i have to create a seperate class to read or write data. $$anonymous$$ost object mapper can easily be tripped over when anything changes on the structure. Reading the data into an dynamic tree structure is much more flexible imo.
Answer by gjf · Mar 07, 2017 at 01:20 PM
something like:
public Vector2[] coordinates;
The Vector2 array returns some random values, I think the parser isn't functioning properly.
Your answer
