14

I am parsing JSON and I get the following error:

I am using the Newtonsoft.Json.NET dll.

Error reading string. Unexpected token: StartObject. Path '[0]', line 1, position 2.

This is the code that I have:

public static List<string> GetPluginByCategory(string category)
    {
        var wc = new WebClient();
        var json = wc.DownloadString("http://api.bukget.org/api2/bukkit/category/" + category);
        var list = JsonConvert.DeserializeObject<List<string>>(json);
        return list;
    }

category can be one of the following strings:

["Admin Tools", "Anti-Griefing Tools", "Chat Related", "Developer Tools", "Economy", "Fixes", "Fun", "General", "Informational", "Mechanics", "Miscellaneous", "Role Playing", "Teleportation", "Website Administration", "World Editing and Management", "World Generators"]

EDIT: This is the response I get:

 [{"description": "Stop users swearing\n", "name": "a5h73y", "plugname": "NoSwear"}, {"description": "Be sure that your server rules are read and accepted!", "name": "acceptdarules", "plugname": "AcceptDaRules"}]

Does anybody know why it doesn't work? It used to work before :/.

Yuki Kutsuya
  • 3,968
  • 11
  • 46
  • 63
  • Please post the *exact JSON data* received from the server. Chances are it is not "an array of strings" for whatever reason. –  Sep 11 '12 at 19:26
  • 1
    (Actually, seeing the response is long, post a *short* but should-be-valid-per-expectations version of the response that shows the same error. The error is that JSON.NET is finding a `{` where it expects a string start. List maps to `["a", "b", "etc"]` whereas the data is `[{someobj1}, {someobj2}, {etc}]`.) –  Sep 11 '12 at 19:33
  • Here's a small piece of code I get: [{"description": "Stop users swearing\n", "name": "a5h73y", "plugname": "NoSwear"}, {"description": "Be sure that your server rules are read and accepted!", "name": "acceptdarules", "plugname": "AcceptDaRules"} – Yuki Kutsuya Sep 11 '12 at 19:38
  • Update that in the main post (don't forget to add a `]` at the end to make it a representative sample). –  Sep 11 '12 at 19:39
  • When it "used to work", was the data from the server the same? Maybe it changed? –  Sep 11 '12 at 19:40
  • They updated the API is what they said and I'm not really that awesome in JSON :(. – Yuki Kutsuya Sep 11 '12 at 19:41
  • Yeah, likely just need to change with the times. See LBs answer. –  Sep 11 '12 at 19:42
  • Thanks, yea I am testing that right now. It seems to work a lil bit :) – Yuki Kutsuya Sep 11 '12 at 19:43

1 Answers1

23

Your json is an array of complex object not an array of strings. Try this (TESTED):

WebClient wc = new WebClient();
string json = wc.DownloadString("http://api.bukget.org/api2/bukkit/category/Teleportation");

var items = JsonConvert.DeserializeObject<List<MyItem>>(json);

public class MyItem
{
    public string description;
    public string name;
    public string plugname;
}

EDIT

WebClient wc = new WebClient();
var json = wc.DownloadString("http://api.bukget.org/api2/bukkit/plugin/aboot");

dynamic dynObj = JsonConvert.DeserializeObject(json);
Console.WriteLine("{0} {1}", dynObj.plugname,dynObj.link);
foreach (var version in dynObj.versions)
{
    var dt = new DateTime(1970, 1, 1).AddSeconds((int)version.date);
    Console.WriteLine("\t{0} {1} {2}",version.version, version.download, dt);
}
L.B
  • 114,136
  • 19
  • 178
  • 224
  • 1
    The "used to work" in the post has been throwing me off; is there a way to get Json.NET to "stuff" complex values into strings (as JSON)? Perhaps a converter? –  Sep 11 '12 at 19:41
  • 1
    @pst you can use `List` type to deserialize and call a ToString() on every item in the list. This would return something like `{ "description": null, "name": "abitofrealism", "plugname": "AbitOfRealism" }` – L.B Sep 11 '12 at 19:46
  • Yeah, that's what I thought .. anyway, issue seems to be "API change" so no more wonder. –  Sep 11 '12 at 19:48
  • Umm... this might be a stupid question but, I can't use this code to retrieve data from one plugin., like this one: `http://api.bukget.org/api2/bukkit/plugin/aboot` – Yuki Kutsuya Sep 11 '12 at 19:49
  • @FoxyShadoww what error do you get? your comment is not much descriptive. – L.B Sep 11 '12 at 19:50
  • @L.B Sorry, this is the error I get: `Error reading string. Unexpected token: StartObject. Path 'authors[0]', line 1, position 4926.` – Yuki Kutsuya Sep 11 '12 at 19:51
  • 1
    @FoxyShadoww your *new* url returns a completely different json string. You should use a different class (or `dynamic`) to deserialize this response. – L.B Sep 11 '12 at 19:53
  • How could I make a dynamic class (This means I don't have to make multiple classes right?) Sorry for the many questions btw :(. – Yuki Kutsuya Sep 11 '12 at 19:54
  • Nvm, I'm trying to make this myself right now :), again thank you so much for this code I think I'm starting to get the hang of this now ^_^! – Yuki Kutsuya Sep 12 '12 at 16:32
  • @L.B OMG, it looks so simple, but still so hard to make! Btw, is it possible that I can get all the properties from the Json string? – Yuki Kutsuya Sep 14 '12 at 14:18
  • @FoxyShadoww Are you looking for something like [this](http://stackoverflow.com/questions/12402670/flatten-nested-dictionarystring-object/12403014#12403014) ? – L.B Sep 14 '12 at 14:39
  • @L.B I think it is what I search, but how would I use this code? Are there any 'simple' examples available? I hate it to not understand these codes yet :(. – Yuki Kutsuya Sep 14 '12 at 14:55
  • @FoxyShadoww How to deserialize the json is in the question. How to flatten the Dictionary is in the answer. – L.B Sep 14 '12 at 15:02
  • @L.B Hmm, I seem to get this error `Type 'System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Object, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]' is not supported for deserialization of an array.` – Yuki Kutsuya Sep 14 '12 at 15:13
  • @FoxyShadoww try with an url (as in edit) that does return an object not an array. JavaScriptSerializer has some problems with it. – L.B Sep 14 '12 at 15:29
  • @L.B Funny, it indeed works with that url, then why doesn't it work with this one: http://server.target4games.com/microcraft.php I just cant figure it out, would you mind explaining it to me? Sorry for the 'noob' questions :(. – Yuki Kutsuya Sep 14 '12 at 15:45
  • @FoxyShadoww json like `{...}` is an *object*, but json like `[...]` is an *array*. Deserialization to Dictionary only works for objects. For arrays a different code is needed.(or every item in array should be flattened separately.) – L.B Sep 14 '12 at 15:51
  • @L.B I see :D! This explains why it doesn't work, thanks!, now what I find strange is that there are arrays in the link in the EDIT part, how comes it doesn't crash? – Yuki Kutsuya Sep 14 '12 at 16:00
  • @FoxyShadoww It only creates problem when the array is the *root* object – L.B Sep 14 '12 at 16:06
  • @L.B I see, but to be able to read the arrays, do I need to like, rewrite the code completely or isn't it that hard? – Yuki Kutsuya Sep 14 '12 at 16:09