Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

ArgumentException: JSON must represent an object type.

Discussion in 'Scripting' started by mohsenz, Feb 10, 2022.

  1. mohsenz

    mohsenz

    Joined:
    Aug 10, 2016
    Posts:
    29
    I'm trying to get data from dictionaryapi.dev
    is there anything different with their Json that I keep getting ArgumentException: JSON must represent an object type.

    any solution to receive that data?

    JsonExample:
    Code (CSharp):
    1. [
    2.    {
    3.      "word": "hello",
    4.      "phonetics": [
    5.        {
    6.          "text": "/həˈloʊ/",
    7.          "audio": "https://lex-audio.useremarkable.com/mp3/hello_us_1_rr.mp3"
    8.        },
    9.        {
    10.          "text": "/hɛˈloʊ/",
    11.          "audio": "https://lex-audio.useremarkable.com/mp3/hello_us_2_rr.mp3"
    12.        }
    13.      ],
    14.      "meanings": [
    15.        {
    16.          "partOfSpeech": "exclamation",
    17.          "definitions": [
    18.            {
    19.              "definition": "Used as a greeting or to begin a phone conversation.",
    20.              "example": "hello there, Katie!"
    21.            }
    22.          ]
    23.        },
    24.        {
    25.          "partOfSpeech": "noun",
    26.          "definitions": [
    27.            {
    28.              "definition": "An utterance of “hello”; a greeting.",
    29.              "example": "she was getting polite nods and hellos from people",
    30.              "synonyms": [
    31.                "greeting",
    32.                "welcome",
    33.                "salutation",
    34.                "saluting",
    35.                "hailing",
    36.                "address",
    37.                "hello",
    38.                "hallo"
    39.              ]
    40.            }
    41.          ]
    42.        },
    43.        {
    44.          "partOfSpeech": "intransitive verb",
    45.          "definitions": [
    46.            {
    47.              "definition": "Say or shout “hello”; greet someone.",
    48.              "example": "I pressed the phone button and helloed"
    49.            }
    50.          ]
    51.        }
    52.      ]
    53.    }
    54.   ]
     
  2. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    Unity's JsonUtility only supports an object as root object. Your json has an array as the top most element. So you can not load this "directly" with JsonUtility. You have several options. Either use a different Json serializer like Json.NET (Newtonsoft) or maybe my SimpleJSON parser which is not an object mapper but simply a parser, or you could wrap your json artificially in an object and use Unity's JsonUtility. JsonUtility has several limitations. It does not support multidimensional arrays, however nested classes with arrays is no problem. So the rest of your json should load just fine.

    Try this

    Code (CSharp):
    1. [System.Serializable]
    2. public class Words
    3. {
    4.     public List<Word> words;
    5. }
    6.  
    7. [System.Serializable]
    8. public class Word
    9. {
    10.     public string word;
    11.     public List<Phonetic> phonetics;
    12.     public List<Meaning> meanings;
    13. }
    14.  
    15. [System.Serializable]
    16. public class Phonetic
    17. {
    18.     public string text;
    19.     public string audio;
    20. }
    21.  
    22. [System.Serializable]
    23. public class Meaning
    24. {
    25.     public string partOfSpeech;
    26.     public List<MeaningDefinition> definitions;
    27. }
    28.  
    29. [System.Serializable]
    30. public class MeaningDefinition
    31. {
    32.     public string definition;
    33.     public string example;
    34.     public List<string> synonyms;
    35. }
    36.  
    Those would be the necessary classes to map your json to. The root object would be "Words". However you have to wrap the object around your array when parsing. Like this

    Code (CSharp):
    1. string json; // this is your json text
    2. Words words = JsonUtility.FromJson<Words>("{\"words\":" + json + "}");
    3.  
    With my SimpleJSON you could directly parse an access any value inside your json

    Code (CSharp):
    1. var node = JSON.Parse(json);
    2. string firstWord = node[0]["word"];
    3. JSONNode firstMeaning = node[0]["meanings"][0];
    4. string typeOfMeaning = firstMeaning["partOfSpeech"];
    5. string definition = firstMeaning["definitions"][0]["definition"];
    6.  
    Of course it depends on what information you need and for what purpose.
     
    Last edited: Feb 10, 2022
    mohsenz likes this.
  3. mohsenz

    mohsenz

    Joined:
    Aug 10, 2016
    Posts:
    29
    Thank you so much,
    I see, and the method works, but something I noticed, is their outputs are quite different, Like for example in this output they have more than one synonym in different places of thefile, so by that method of splitting Json, will it work for different variations? do you think in this case, for example going with findIndexof and filtering the things by signs could also make sense?

    Code (CSharp):
    1. [{"word":"sky","phonetic":"skʌɪ","phonetics":[{"text":"skʌɪ","audio":"//ssl.gstatic.com/dictionary/static/sounds/20200429/sky--_gb_4.mp3"}],"origin":"Middle English (also in the plural denoting clouds), from Old Norse ský ‘cloud’. The verb dates from the early 19th century.","meanings":[{"partOfSpeech":"noun","definitions":[{"definition":"the region of the atmosphere and outer space seen from the earth.","example":"hundreds of stars were shining in the sky","synonyms":["the atmosphere","the stratosphere","the skies","airspace","the heavens","the firmament","the vault of heaven","the blue","the (wide) blue yonder","the welkin","the ether","the empyrean","the azure","the upper regions","the sphere"],"antonyms":[]}]},{"partOfSpeech":"verb","definitions":[{"definition":"hit (a ball) high into the air.","example":"he skied his tee shot","synonyms":[],"antonyms":[]}]}]}]
     
  4. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    I don't quite see the synonymes at different places. They are always inside a definition of a meaning of a word. Of course as we can see a word can have more than one meaning and each meaning can have more than one definition and not every definition has synonymes. Though missing information inside the structure will be just null or empty arrays when loading. For example your first json you shared a word only had 3 parts, the word, the phonetics and the meanings. However your recent example also has an "origin" entry. If you want to be able to read / access that as well, you would need to add it to the Word class. Of course that means in the first case where no origin information was given, the variable would be null or empty. So if you're using an API of some webservice, you may want to look up the documentation where the whole structure is usually explained in detail.
     
  5. mohsenz

    mohsenz

    Joined:
    Aug 10, 2016
    Posts:
    29
    Oh Yes! You're totally right! I thought if it cannot find any value it will give an error, then it seems it just does not get anything!

    I worked on the script a bit, but need more details,

    Code (CSharp):
    1.  
    2.         string json = tx.text; // this is your json text
    3.         Words words = JsonUtility.FromJson<Words>("{\"words\":" + json + "}");
    4.  
    5.         var node = JSON.Parse(json);
    6.         string firstWord = node[0]["word"];
    7.  
    8.  
    9.         string audiolinks = "AudioLinks: ";
    10.         for (int i = 0; i < 7; i++)
    11.         {
    12.             JSONNode phonetic = node[0]["phonetics"][i]["audio"];
    13.             string audiotemp =phonetic.ToString();
    14.             if(audiotemp == null)
    15.             {
    16.  
    17.             }
    18.             else
    19.             {
    20.                 audiolinks += audiotemp;
    21.             }
    22.         }
    23.        
    24.  
    25.         string Synonyms = "syns: ";
    26.         string definition = "def: ";
    27.         string Examples = "examples: ";
    28.         string tempe;
    29.         for (int i = 0; i < 7; i++)
    30.         {
    31.             JSONNode firstMeaning = node[0]["meanings"][i];
    32.             string tempm = firstMeaning.ToString();
    33.             if (tempm.Length > 0)
    34.             {
    35.                 definition += firstMeaning["definitions"][0]["definition"] + " and ";
    36.                 Examples += firstMeaning["definitions"][0]["example"] + " and ";
    37.                 for (int o = 0; o < 7; o++)
    38.                 {
    39.                     tempe = firstMeaning["definitions"][0]["synonyms"][o];
    40.                     if(tempe == null)
    41.                     {
    42.                      
    43.                     }
    44.                     else
    45.                     {
    46.                         Synonyms += tempe + " And ";
    47.                     }
    48.                 }
    49.             }
    50.             else
    51.             {
    52.             }
    53.         }
    54.  
    55.         Debug.Log(audiolinks);
    56.         Debug.Log(Synonyms);
    57.         Debug.Log(definition);
    58.         Debug.Log(Examples);
    59.    
    but I'm wondering why it changes the "//" in the links, it already prints the links like:

    https:\/\/lex-audio.useremarkable.com\/mp3\/hello_us_2_rr.mp3
     
  6. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    Don't use ToString on a JSONNode. It would convert the node back to json. To read a string value, either use an implicit or explicit string cast

    Code (CSharp):
    1. string audiotemp = phonetic; // implicit string conversion
    2. string audiotemp = (string)phonetic; // explicit string conversion
    3. string audiotemp = phonetic.Value; // use the Value property which read the node as a string value.
    Those are the 3 ways you can read the string value. The ToString method would transform a node back to the json representation. So a string value would be quoted and escaped.

    Note that you can iterate through the elements of an array. You can use

    Code (CSharp):
    1. foreach(JSONNode meaning in node[0]["meanings"])
    2. {
    3.     // use meaning here
    4. }
     
    mohsenz likes this.
  7. mohsenz

    mohsenz

    Joined:
    Aug 10, 2016
    Posts:
    29
    Thanks, A lot!
    Yess, getting value is working perfectly:
    Code (CSharp):
    1. string audiotemp =phonetic.Value.ToString();
    but seems it cannot recognize the JSONNodes through foreach
     

    Attached Files:

    • req.jpg
      req.jpg
      File size:
      53.6 KB
      Views:
      211
  8. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    Are you sure you use the latest version from Github? Currently I literally have this code in one of my little projects:

    Code (CSharp):
    1.     public Shape(JSONNode aNode)
    2.     {
    3.         foreach(JSONNode coord in aNode)
    4.         {
    5.             m_Positions.Add(coord.ReadVector3Int());
    6.         }
    7.     }
    8.  
    This is one of the constructors of my Shape class which expects an array of coordinates. (Note ReadVector3Int is a new extension that is not "yet" in the Unity extension file).