so I'm fairly new to programming but am looking to go much deeper with it. I recently started to get involved in a project to create a WinForm program for a website that uses an API system in JSON.
I've never used an API before so I'm not quite sure how it works but after looking at it for a few minutes I seem to have the gist of it. What I don't get is how exactly parsing JSON in C# works.
I found
this link after a little google searching. And I got it working (somewhat) with this code.
static void Main(string[] args)
{
WebClient c = new WebClient();
var vLogin = c.DownloadString("https://www.openraid.us/index.php/api/login/username/password");
//Returns string
//{"status":1,"error":null,"token":"250-1336515541-c48d354d96e06d488d1a2530071ef07c9532da26"}
//Token = random, no decisive length*/
JObject o = JObject.Parse(vLogin);
Console.WriteLine("Login Status: " + o["status"]);
String sToken = "" + o["token"];
Console.WriteLine(sToken);
Console.WriteLine("");
//Breaks after this
var myRaids = c.DownloadString("https://www.openraid.us/index.php/api/myraids/"+sToken);
JObject r = JObject.Parse(myRaids); //error occurs here
String sEventId = "" + r["event_id"];
Console.WriteLine("Event ID: " + sEventId);
Console.ReadLine();
}
So to me it looks like I have parsing 1 page done and handled, but when I move onto the second I get this error.
Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray. Path '', line 1, position 1.
So I guess my question is, how do I parse more than 1 page or call of JSON and what would be the easiest way to break up each section of the JSON object (Such as status, error, and token, into C# strings?
Did you try to JArray instead? Depending on what kind of object you are trying to return
WebClient client = new WebClient();
var data = client.DownloadString("");
var jArray = JArray.Parse(data);
JSON requires brackets for arrays and commas between multiple objects.
This is per the JSON standard. I also recommend using JSON.net via NuGet instead of the native JSON parser unless it is overkill and you cannot have the extra bloat.
For example, your parsing a file with two seperate JSON objects - the following does not work per the JSON standard (lacks a comma between the 2 objects and the two objects are not encapsulated by brackets):
{"status":1,"error":null}
{"status":2,"error":null}
The following 3 JSON objects parsed from a file does work (has brackets for multiple objects and commas between objects):
[{"glossary": {"title": "fun glossary","SeeAlso": ["GML", "XML"]},
{"glossary": {"title": "grey glossary","SeeAlso": ["GML", "XML"]},
{"glossary": {"title": "blue glossary","SeeAlso": ["GML", "XML"]}]
You can cut every JSON object(Array) into more object using for loops
the C# API is System.Json
var jsonArray = JsonArray.Parse(st);//st is the string which contain the JSON objects
foreach (var item in jsonArray) {
JsonObject ob = new JsonObject(item);
foreach (var t in ob.Values) {
JsonObject oo = new JsonObject(t);
foreach (var x in oo) {
textBox1.AppendText(x.Key + ā : ā + x.Value + ā\nā);
}
}
}
Related
How would i keep appending data?
I have this:
{
"13232": [
"2012952"
]
}
And i want to add an another object to it, example:
{
"13232": [
"2012952"
],
"19213": [
"2016086"
]
}
This is the code i use:
JArray array = new JArray();
array.Add(Itemid);
JObject o = new JObject();
o[Userid] = array;
string json = o.ToString(Formatting.Indented);
//i know this keeps appending text but how would i append it inside the { and }?
File.AppendAllText("E:/media.json", json);
I literally have no idea how to keep adding it, but maybe someone else has?
You won't be able to use file append operations to do this. File append operations can only add text to the end, they can't insert text at some point in the middle. This makes it impossible to use file-append to keep the JSON valid.
You have two choices that I can think of:
Read the entire file into an object, add your object, and then
rewrite the entire file (poor performance)
Open the file read/write, parse through
until you get to the closing curly brace, then write the remaining
data, then write the close curly brace (not trivial)
The safest approach is read-update-rewrite (applies to JSON and XML format as they don't support appending).
Next option if you can live with invalid JSON is to simply concatenate JSON fragments with code you have and than use SupportMultipleContent in JsonReader to read fragments Read Multiple Fragments With JsonReader
If those approaches don't work and your format is fixed - find position of last ] in the file, seek stream there and write new array elements and append ]}.
I recommand you use Newtonsoft Json lib, available as a nuget package.
You can the make a model class to represent on of the json node then you can de-serialize you Json to that model and build an array containing the new element at the end to then re-serialize it to json after.
Look at this MSDN page about it: https://msdn.microsoft.com/en-us/library/bb412179(v=vs.110).aspx
Edit: Actual NewtonSoft Documentation
In steps: 1 Deserialize the collection
2: And a new class instance with listName.Add(className);
3: Reserialize the collection
My approach was to add an additional step to my string handling.
public void WriteObjectToFile(object objectToInsert)
{
var stringToSaveToFile = JsonConvert.SerializeObject(objectToInsert) + ",";
File.AppendAllText(this.path, stringToSaveToFile);
}
public List<objects> GetListFromFile()
{
var notQuiteJSONstring = File.ReadAllTest(this.path);
var treatment1 = notQuiteJSONstring.Substring(0, notQuiteJSONstring.Length -1); //remove the trailing comma
var treatment2 = "[" + treatment1 + "]"; // wrap string with brackets to deserialize as list
var list = JsonConvert.DeserializeObject<List<object>>(treatment2);
return list;
}
t fails to deserialize/prase this json, ive tried multiple combinations with different methods to try and make this work but nothing seems to do it...
The code im using
WebClient wc = new WebClient();
var json = (JObject)JsonConvert.DeserializeObject(wc.DownloadString("http://services.runescape.com/m=website-data/playerDetails.ws?names=[%22" + Username.Replace(" ", "%20") + "%22]&callback=jQuery000000000000000_0000000000&_=0"));
the json its trying to deserialize...
jQuery000000000000000_0000000000([{"isSuffix":true,"recruiting":false,"name":"Sudo Bash","clan":"Linux Overlord","title":"the Troublesome"}]);
In Json specification you can see that [ indicates the begining array of json objects while { indicates beginning of new json object.
Your json string starts with [ so it can contains more json objects ( because it's an array and it contains jQuery000000000000000_0000000000( which is your query string parameter. To get rid of the query string garbage you should find out the scheme of that garbage and then to process json object I would recommend you to deserialize your json string into List<JObject> using JsonConvert.DeserializeObject<T>() method if your json string starts with [ ( use standard type if it is starting with { );
Example :
string url = // url from #Darin Dimitrov answer
string response = wc.DownloadString(url);
// getting rid of the garbage
response = response.Substring(response.IndexOf('(') + 1);
response = response.Substring(0, response.Length - 1);
// should get rid of "jQuery000000000000000_0000000000(" and last occurence of ")"
JObject result = null;
if(response.StartsWith('['))
{
result = JsonConvert.DeserializeObject<List<JObject>>(response)[0];
}
else
{
result = JsonConvert.DeserializeObject<JObject>(response);
}
What you are trying to deserialize is not JSON but rather JSONP (which is JSON wrapped in a function call).
Remove this parameter from your query string:
&callback=jQuery000000000000000_0000000000
and you should be good to go with a properly formatted JSON:
var url = "http://services.runescape.com/m=website-data/playerDetails.ws?names=[%22" + Username.Replace(" ", "%20") + "%22]&_=0";
var json = (JObject)JsonConvert.DeserializeObject(wc.DownloadString(url));
I have gotten a Json string to parse before that was an array of objects much longer than just a simple string, which makes me think that I'm doing something wrong with the formatting.
Here is word for word what our webservice is outputting as the json string:
{"news":"What is Legal/Awesome Dre"}
the first part is simply what I named the string in the application (news) and the second part is the string that will be changing as the song does which is why I would like to pull in a simple string of it.
When I run the app I'm getting a parse error at these lines:
Console.Out.Writeline (content);
news = JsonConvert.DeserializeObject(content);
The application output will show the Json string as it is on the website, but I get an error right after that's telling me Invalid Token: startPath... which last time meant that my Json string was formatted wrong for how I need to grab the data.
Anyone can help me with this?
(P.S. I am working in Xamarin Studio (mono for android) using C#, if that makes any difference)
The problem is that your serialized JSON object isn't a string, it's an object with the string value you want at the "news" property/key/name. This is a simple way to get the string:
dynamic jsonObj = JsonConvert.DeserializeObject(content);
string news = jsonObj.news;
Or you can use an anonymous type:
var jsonObj = JsonConvert.DeserializeAnonymousType(content, new { news = "" });
string news = jsonObj.news;
Or create a type with a string News property:
MyNewsType jsonObj = JsonConvert.DeserializeObject<MyNewsType>(content);
string news = jsonObj.News;
These all work in the following way:
var content = #"{""news"":""What is Legal/Awesome Dre""}";
// above code
Console.WriteLine(news); // prints "What is Legal/Awesome Dre"
Try to put square bracket in your JSON:
[{"news":"What is Legal/Awesome Dre"}]
I have been using json.NET successfully in projects for some time now without any problems. Last night I ran into my first case where json.NET crashed trying to parse json data returned from what should be a reliable source: the twitter API.
Specifically, this code causes the error:
string sCmdStr = String.Format("https://api.twitter.com/1/users/lookup.json?screen_name={0}", sParam);
string strJson = _oauth.APIWebRequest("GET", sCmdStr, null);
JObject jsonDat = JObject.Parse(strJson);
In my case the sParam string contained about 25 twitter numeric Ids. The twitter API call succeeded, but the json.NET Parse call failed with the following error:
"Error reading JObject from JsonReader. Current JsonReader item is not an object: StartArray"
Has anyone else run into this? Does anyone know any way around it? I am at a dead stop until I solve it.
I was getting the exact same error and eventually figured it out. Instead of using JObject.Parse use JArray.Parse. So here is your code:
string sCmdStr = String.Format("https://api.twitter.com/1/users/lookup.json?screen_name={0}", sParam);
string strJson = _oauth.APIWebRequest("GET", sCmdStr, null);
JArray jsonDat = JArray.Parse(strJson);
You can then loop through the array and create a jobject for each individual tweet.
for(int x = 0; x < jsonDat.Count(); x++)
{
JObject tweet = JObject.Parse(jsonDat[x].toString());
string tweettext = tweet["text"].toString();
//whatever else you want to look up
}
I am querying a web service that was built by another developer. It returns a result set in a JSON-like format. I get three column values (I already know what the ordinal position of each column means):
[["Boston","142","JJK"],["Miami","111","QLA"],["Sacramento","042","PPT"]]
In reality, this result set can be thousands of records long.
What's the best way to parse this string?
I guess a JSON deserializer would be nice, but what is a good one to use in C#/.NET? I'm pretty sure the System.Runtime.Serialization.Json serializer won't work.
Using the built in libraries for asp.net (System.Runtime.Serialization and System.ServiceModel.Web) you can get what you want pretty easily:
string[][] parsed = null;
var jsonStr = #"[[""Boston"",""142"",""JJK""],[""Miami"",""111"",""QLA""],[""Sacramento"",""042"",""PPT""]]";
using (var ms = new System.IO.MemoryStream(System.Text.Encoding.Default.GetBytes(jsonStr)))
{
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(string[][]));
parsed = serializer.ReadObject(ms) as string[][];
}
A little more complex example (which was my original answer)
First make a dummy class to use for serialization. It just needs one member to hold the result which should be of type string[][].
[DataContract]
public class Result
{
[DataMember(Name="d")]
public string[][] d { get; set; }
}
Then it's as simple as wrapping your result up like so: { "d": /your results/ }. See below for an example:
Result parsed = null;
var jsonStr = #"[[""Boston"",""142"",""JJK""],[""Miami"",""111"",""QLA""],[""Sacramento"",""042"",""PPT""]]";
using (var ms = new MemoryStream(Encoding.Default.GetBytes(string.Format(#"{{ ""d"": {0} }}", jsonStr))))
{
var serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(Result));
parsed = serializer.ReadObject(ms) as Result;
}
How about this?
It sounds like you have a pretty simple format that you could write a custom parser for, since you don't always want to wait for it to parse and return the entire thing before it uses it.
I would just write a recursive parser that looks for the tokens "[", ",", "\"", and "]" and does the appropriate thing.