I get an error while parsing a json string into an object. I am using system.json to parse the json string.
The JSON file: (NOTE: I cannot change the structure of this json file because it is generated)
{
title: "My Title",
log: "",
nid: "1234",
type: "software",
language: "EN",
created: "1364480345",
revision_timestamp: "1366803957",
body: {
und: [
{
value: "abc",
summary: "def"
}
]
}
}
The C# code:
string jsonString = new WebClient().DownloadString(".......MyJson.json"); //For test purpose
var obj = JsonObject.Parse (jsonString); ///<--- At this line the exception is thrown
The Exception:
System.ArgumentException has been thrown.
Invalid JSON string literal format. At line 1, column 2
How to solve this?
Thanks in advance!
You can't. That isn't valid json. Field names must be enclosed in quotes. All json parsing tools will throw when trying to parse that.
You could process it and turn it to valid json before deserializing, but really, you need to correct it API side. No clients will work with that.
How to solve this?
(NOTE: I cannot change the structure of this json file because it is generated)
Easy, use json.Net. it works without any problem with your json
var j = JObject.Parse(jsonString);
You can even use dynamic keyword
dynamic j = JObject.Parse(jsonString);
Console.WriteLine("{0},{1}", j.title, j.body.und[0].value);
Related
I have an ugly JSON string that is getting returned from an API that looks like this (this is the result of Console.Write on the string):
{"d":"\"\\\"\\\\\\\"[{\\\\\\\\\\\\\\\"foo\\\\\\\\\\\\\\\":15,\\\\\\\\\\\\\\\"bar\\\\\\\\\\\\\\\":null}]\\\\\\\"\\\"\\n\""}
I am trying to parse this into a C# object in the simplest way possible, so I can access properties like foo and bar. But I am having a difficult time doing this.
I have tried parsing it a number of ways, including:
// code to get the response string
client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
var serializedData = "{data: 'data'}";
var responseString = client.UploadString(url, "POST", serializedData);
// parse the response string
dynamic obj = Newtonsoft.Json.JsonConvert.DeserializeObject(jsonString);
This allows me to access the value of d, which is the actual string I need to parse. I then tried to parse that separately using JArray.Parse(obj["d"]), but I get an error saying that obj["d"] is not an array.
Unfortunately, I have no access to the API itself so can't modify how it's serializing the data it's returning.
Any suggestions?
You can replace all New Line, Backslash, Double quotes to format the JSON
var formattedJson = jsonString.Replace(#"\n", string.Empty)
.Replace(#"\", string.Empty)
.Replace("\"\"", string.Empty);
Console.WriteLine(formattedJson);
OUTPUT
{
"d": [
{
"foo": 15,
"bar": null
}
]
}
Convert to JArray.
var jArray = JArray.Parse(JObject.Parse(formattedJson)["d"].ToString());
Console.WriteLine($"{jArray[0]["foo"]} {jArray[0]["bar"]}");
OUTPUT
15
The problem is that the value of "d" is a string representing a string representing a string ... representing an array. You could call it JSON serialization "inception".
The way to deal with this is to deserialize the value corresponding number of times. If you're sure that the value is never going to be an actual string, you could do it like this, without having to know how many times the value was serialized:
var myObject = JObject.Parse(s);
var d = myObject["d"];
while(d.Type == JTokenType.String)
d = JToken.Parse(d.ToObject<string>());
myObject["d"] = d;
After this procedure myObject represents this data:
{
"d": [
{
"foo": 15,
"bar": null
}
]
}
Replacing escape characters in fine however I would not rely on the console.write command as the definitive output to examine. Here are a couple of other ways: -
Use Postman to make the API call so you can see the raw result. This will (hopefully) show it in an easy to read format that you can then define your class to deserialise to.
Write the raw response to a “.json” file. Open that file in a good editor (such as VS Code or VS itself) to see how the data is actually structured when it is received.
On a side note I would recommend using RestSharp to do the REST calls and Newtonsoft.Json to do the serialising/deserialising.
In the code snippet below, the JSON string in the commented out jsonString variable is valid while the uncommented out one causes JObject.Parse to throw a JsonReaderException with the message:
After parsing a value an unexpected character was encountered: e. Path 'Key', line 1, position 15.
var jsonString = "{\"Key\":\"Value \"extra\" \"}";
//var jsonString = "{\"Key\":\"Value \\\"extra\\\" \"}";
JObject.Parse(jsonString);
Are there any methods available in Newtonsoft.Json or elsewhere that can transform a JSON string to make it valid?
No, because NewtonSoft cannot guess what you want. E.g. is extra a new key and did you just ommit a comma or is it part of the previous value, or is it just something that can be ignored. It would be better to have the thing you are consuming the json from construct valid json.
Using Regex might help you to resolve the existing JSON you have. If you can control how subsequent JSON is generated, you really should fix it at that point.
This solution counts the value as existing from the first " after a "key":, through to the last " before a , or a }, and then it reserializes the value to ensure that it is correctly escaped. If it finds ",, it expects it to be followed by another key ("key":). This is in an attempt to avoid red herrings (i.e. {"key": "test "," value"}) which might otherwise confuse it.
private static string FixJson(string json)
{
var regex = new Regex("\"(?<key>.*?)\"\\W?:\\W?\"(?<value>.*?)\"(?=,\".*?\"\\W?:|}$)");
return regex.Replace(json, new MatchEvaluator(m => {
var key = m.Groups["key"].Value;
var val = m.Groups["value"].Value;
return string.Format("\"{0}\":{1}", key, JsonConvert.SerializeObject(val));
}));
}
Disclaimer: It's a regular expression, it's not foolproof, and if your JSON is more broken than you have indicated, it will probably spit out broken JSON, or incorrect values, so use it at your own risk.
Try it online
I have this JSON file:
[
{
"param1": "someURL",
"param2": "someURL2"
},
{
"param1": "someURL3",
"param2": "someURL4"
}
]
JsonLint says that this JSON is valid.
Now I read this JSON file from Azure Storage download it to a stream and then encode it:
string content = Encoding.UTF8.GetString(memoryStream.ToArray());
Next I want to deserialize this to a list of objects:
List<MyParamObject> deserialized = JsonConvert.DeserializeObject<List<MyParamObject>>(text);
MyParamObject is a POCO with two attributes named Param1 and Param2
When I try to deserialize it I get the following error:
Unexpected character encountered while parsing value: ?. Path '', line 0, position 0.
But I do give JsonConvert a string with a valid JSON what can I do?
Through a HEX Editor I checked the beginning of the file and I found out that my IDE added a BOM to the beginning of the file. So it looks like this:
[.. {.. "
As they are not recommended I chose to get rid of them by creating a new file with Explorer/Finder and adding my JSON in there.
I've got this code to try to open a .json file and read it:
[Route("{unit}/{begindate}")]
public string Get(string unit, string begindate)
{
string _unit = unit;
string _begindate = String.Format("{0}01", PlatypusWebReportsConstsAndUtils.HyphenizeYYYYMM(begindate));
string appDataFolder = HttpContext.Current.Server.MapPath("~/App_Data/");
// semi-hardcoded file name for now
string jsonFilename = string.Format("PoisonToe_{0}_{1}.json", _unit, _begindate);
string fullPath = Path.Combine(appDataFolder, jsonFilename);
JObject platypusComplianceJson = JObject.Parse(File.ReadAllText(fullPath));
. . .
On the last line, I get:
Newtonsoft.Json.JsonReaderException was unhandled by user code
HResult=-2146233088
Message=Error reading JObject from JsonReader. Current JsonReader item is not an object:
Based on what I read here, I thought this would be the way to do it. What am I doing wrong?
It's difficult to give a better answer without the information requested in comments, but this means, as it suggests, that the current token isn't the start of an object.
Just to be clear, we're talking about "object" in the JSON vocabulary, and not in the C#/OOP vocabulary sense.
It sounds like what's going on here is something like the non-JSON bool.Parse("1"). Yes, "1" is valid input to a parse method (int.Parse, for instance), but this is the wrong method.
The simple trick (warning: Band-Aid fix) is to switch to JToken.Parse. JToken is a polymorphic parent of JObject, JArray, JValue, and the lot, so its parse is able to handle a lot more types of unstructured input.
Before you do that, as I'm sure you know, you should of course double-check your contracts and the file, to see which is wrong. There's certainly no good in successfully parsing a JArray that you then use as a JObject.
For good measure, a few file texts that would cause this error are:
(empty file)
[{ "test": "val" }] (array)
"test" (string)
null
These should all be valid inputs to JToken.Parse, I believe, but they'd all give this error on JObject.Parse, because they aren't objects. You need something like:
{ "test": "val" }
{ "test": { "val": 2 } }
Or something to that effect.
Back on my OOP point, a JObject isn't the elementary base type of everything in JSON.net, but JToken is. So even though you could say,
object i = new int[0];
in C#, you can't say,
JObject i = JObject.Parse("[0, 0, 0]");
in JSON.net.
I am using Json.NET 6.x and I noticed weird behaviour:
If I want to deserialize this simple JSON, I get an error:
The code to deserialize:
object o = Newtonsoft.Json.JsonConvert.DeserializeObject(text);
and the JSON:
[
{
"Username": "tb386",
"TimestampUpdated": "2015-01-19T18:49:52.771571+01:00",
"AuthTokens": [
"Ua7JR5E7hSAxjafp6dpMrvw3HlICW3ZZdDuArMaU5ks="
]
}
]
The error I get is:
Unexpected character encountered while parsing value: U. Path '', line 0, position 0.
If I remove the array, it works fine. But all I have to do, is to remove the string inside the array, making it empty:
[
{
"Username": "tb386",
"TimestampUpdated": "2015-01-19T18:49:52.771571+01:00",
"AuthTokens": [ ]
}
]
and then it works fine. I should also note that the serialized JSON was produced by the Newtonsoft library, so the source is the same library!
If I try a validator (like http://jsonlint.com/) on the JSON with the array, it valides OK!
Can anyone help me out here?
Additional information: Even if I add a string inside VS and write the JSON hardcoded, it fails!
string text = "[ {\"Username\": \"tb386\",\"TimestampUpdated\": \"2015-01-19T18:49:52.771571+01:00\",\"AuthTokens\": [\"Ua7JR5E7hSAxjafp6dpMrvw3HlICW3ZZdDuArMaU5ks=\"] } ]";
object o = Newtonsoft.Json.JsonConvert.DeserializeObject(text);
Version info on Newtonsoft dll: