How to read the json data - c#

I have the following json data, I need to read the data from it and them perform some comparisons.
{"expiration": "2013-04-01T00:00:00Z",
"conditions": [
{"bucket": "the-s3-bucket-in-question"},
["starts-with", "$key", "donny/uploads/"],
{"acl": "private"},
["eq", "$Content-Type", "text/plain"],
["starts-with", "x-amz-meta-yourelement", ""],
["content-length-range", 0, 1048576]
]
}
By using the following code I have found the first element
var policy = Encoding.UTF8.GetString(policyByteArray);
JObject obj = JObject.Parse(policy);
string policyexpiration = obj.First.First.Path;
I have used JToken for finding all the conditions but I am getting only one element in that array. Can you please help me to get all the elements present in the conditions.
Following is the way I have used JToken
JToken entireJson = JToken.Parse(policy);
var items = entireJson["conditions"].Value<JArray>()[0];
XmlDocument xdoc = (XmlDocument)JsonConvert.DeserializeXmlNode(items.ToString(), "root");
XmlNode xmlarray = xdoc.GetElementsByTagName("root")[0];
foreach (XmlNode xmlelement in xmlarray)
{
}

I'm not sure why you need the XML tools at all. Iterating the "conditions" in your json structure is simple with Json.NET and you're already very close.
var items = entireJson["conditions"].Value<JArray>();
foreach (JToken condition in items)
{
//do work on one condition here
}
Note that this json structure is a little odd. A single condition can either be an array such as ["starts-with", "$key", "donny/uploads/"] OR an object such as {"bucket": "the-s3-bucket-in-question"}.
Depending what you want to do with the conditions, you may need to distinguish between the two. You can use C#'s is operator with the Json.NET types, like this:
var items = entireJson["conditions"].Value<JArray>();
foreach (JToken condition in items)
{
if (condition is JArray)
{
//do something with the array
}
else if (condition is JObject)
{
//do something with the object
}
}

You are you only getting one element because you are selecting the value at index 0 of the JArray
var items = entireJson["conditions"].Value<JArray>()[0];
Instead of using the Value method, use Values which returns an IEnumerable
var items = entireJson["conditions"].Values<JObject>();

As far as I know DeserializeXmlNode() only accept string that represent JSON object. That's why it worked when you passed only the first value of conditions property :
var items = entireJson["conditions"].Value<JArray>()[0];
XmlDocument xdoc = JsonConvert.DeserializeXmlNode(items.ToString(), "root");
But throwing exception if you pass the entire value or the second value of conditions because both represent JSON array instead of JSON object :
//pass entire value
var items = entireJson["conditions"].Value<JArray>();
//or pass the second value : ["starts-with", "$key", "donny/uploads/"]
var items = entireJson["conditions"].Value<JArray>()[1];
XmlDocument xdoc = JsonConvert.DeserializeXmlNode(items.ToString(), "root");
It isn't clear what kind of XML format you want to create from given JSON string. But just to make it work, you can try to create another JSON object having one property named conditions with value copied from the initial JSON :
var items = entireJson["conditions"].Value<JArray>();
var newObject = string.Format("{{conditions : {0}}}", items.ToString());
XmlDocument xdoc = (XmlDocument)JsonConvert.DeserializeXmlNode(newObject, "root");

Related

How to Loop on JSON JArray in c# when Array size becomes Zero

I have two auto generated JSON data as shown below. I want to get all the data in Colors Tag.
I Created a JArray of "Colors" and started looping on all data available, but when there is only one color available my code starts giving exceptions as "Colors" is not a JArray instead a JProperty. See sample code below.
What is the ideal way of handling this situation?
{
"UID":1234,
"Colors":["red", "blue", "green"]
}
{
"UID":1234,
"Colors":"green"
}
JObject jsonObject = (JObject)JsonConvert.DeserializeObject(jsonText, settings);
foreach (JObject reg in jsonObject["Colors"]) {
// Write to console.
}
First I would let your schema JSON "Colors" be an array because that can let your JSON be a strong schema.
if you can't modify the schema You can try to use JObject.Parse then use is to judge the type
var jsonObject = JObject.Parse(jsonText);
if (jsonObject["Colors"] is JArray)
{
foreach (JObject reg in jsonObject["Colors"]) {
// Write to console.
}
}
else if(jsonObject["Colors"] is JToken)
{
//jsonObject["Colors"]
}

C# find JSON value based only on Key name through multiple levels of array

I have a variety of input JSON formatted data which all contain a particular key-name terminalSize. This is the only piece I know. The total number of JSON trees or the exact depth of terminalSize inside the JSON tree will forever be an unknown and subject to change.
I'm looking for a C# solution to loop through every child of the JSON string and find terminalSize then fetch the value.
I've tried this with success but it will only work if terminalSize is in the first level of the JSON:
var list = JsonConvert.DeserializeObject<List<Dictionary<string, string>>>(jsonString);
var dict = list.SelectMany(d => d).ToDictionary(p => p.Key, p => p.Value);
var terminal = dict["terminalSize"];
Example 1.
{
"status": "success",
"data": {
"terminalSize": 3766505.46,
"totalTerminalSize": 3766505.46
},
"message": null
}
Example 2.
{
"lastUpdated": 1588020678,
"terminalData": {
"terminalSize": "451679852",
"totalTerminalSize": "2100000000"
},
"terminalValueSeries": {
"8x7": 2.33,
"8x6": 3.73,
"8x5": 4.49,
"8x4": 3.68,
"8x3": 13998,
"8x2": 274936,
"8x1": 5.09
}
}
Example 3.
{
"terminalSize": "492612346.17",
"terminalStatus": "online"
}
You can parse your JSON to a JToken, then use SelectToken with the recursive descent JsonPath operator .. to get the terminalSize anywhere in the JSON:
var terminalSize = (double?) JToken.Parse(json).SelectToken("$..terminalSize");
Fiddle: https://dotnetfiddle.net/5ziYbP
If there might be multiple terminalSize keys in the JSON, for example if you had an array of terminals, you can use SelectTokens instead and put the terminal sizes into a Dictionary keyed by path:
var sizes = JToken.Parse(json4)
.SelectTokens("$..terminalSize")
.ToDictionary(t => t.Path, t => (double)t);
Fiddle: https://dotnetfiddle.net/ivSM88
You could also use linq and filter the JProperty collection based on JProperty.Name. For example
var result = JObject.Parse(jsonString)
.DescendantsAndSelf()
.OfType<JProperty>()
.Single(x=>x.Name.Equals("terminalSize"))
.Value;
You may parse your JSON into JObject, then recursively go through all properties and sub objects to find a terminalSize value. There is no need to deserialize the entire JSON into specific object
var json = JObject.Parse(jsonString);
var result = GetTerminalSize(json);
double GetTerminalSize(JObject input)
{
foreach (var property in input.Properties())
{
if (property.Name == "terminalSize")
return property.Value.Value<double>();
if (property.Value.Type == JTokenType.Object)
return GetTerminalSize((JObject) property.Value);
//not sure, if the is a need to handle an array
if (property.Value.Type == JTokenType.Array)
foreach (var item in (JArray) property.Value)
return GetTerminalSize((JObject) item);
}
return 0;
}
It returns a correct value for all 3 examples

Deserialize Json to XML with array of objects contained in single XML node

I need to generate XMLDocument from JObjects, and I'm trying to figure out how to make an array of JObjects convert properly to XML. This is the section giving me trouble:
JObject billsegment = new JObject
{
{"ext_bill_id", bill.ExternalBillID},
{"cust", new JObject
{
{"typ_id_cust","1"},
{"id_cust", bill.CustomerID}
}
},
// This element is giving me trouble
{"bill_line_list", GetBillLines(bill.LineData)}
};
The problem: The resulting XML is:
<bill_line_list>
<bill_line>
<line_no>1</line_no>
<id_elm_bill>06159</id_elm_bill>
</bill_line>
</bill_line_list>
<bill_line_list>
<bill_line>
<line_no>2</line_no>
<id_elm_bill>05432</id_elm_bill>
</bill_line>
</bill_line_list>
Notice there are two <bill_line_list> elements, of which I only want one. I want the result to be:
<bill_line_list>
<bill_line>
<line_no>1</line_no>
<id_elm_bill>06159</id_elm_bill>
</bill_line>
<bill_line>
<line_no>2</line_no>
<id_elm_bill>05432</id_elm_bill>
</bill_line>
</bill_line_list>
My GetBillLines() method returns a JArray, which I formulate like this:
JArray GetBillLines(dynamic lineData)
{
int num_lines = lineData.NumLines;
JArray lines = new JArray();
for (int lineNum = 1; lineNum < num_lines+1; lineNum++)
{
JObject line = new JObject
{
{"line_no", lineNum },
{"id_elm_bill", billData.Lines[lineNum].billCode},
};
lines.Add(new JObject
{
{"bill_line", line}
});
}
return lines;
}
What I've tried: I've tried making the return type of my GetBillLines() to JArray and JToken[], and I've tried returning the JArray with .ToArray(). Also, in my JObject billsegment I've tried changing the last line to
JToken.FromObject(GetBillLines(bill.LineData))
and other various things. I'm wondering why it creates two <bill_line_list>s, since when I create the object I am only adding ONE bill_line_list property, and setting the JToken as an array.
I know that you can force Json arrays when serializing from XML (via json:Array='true'), is there an equivalent the other way around?

Newtonsoft Object serialized to String. JObject instance expected

Hi so am trying to parse this JSON line but i got some others that are like this in files thats why i want to automate this so i can remove the invalid lines to make the file a valid JSON for reading, The problem is that the JSON contains multiple JSON in 1 line
Example:
{"item":"value"}{"anotheritem":"value"}
Is there anyway to remove
{"anotheritem":"value"}
So it turns in to a valid JSON that is readable to start parsing the files
I tried doing using StreamReader cause there in a file i have multiple files that contain these invalid JSON
So i got it to be able to detect the Invalid JSON but for some reason i can't get it to read the JSON so i can use .remove to remove the invalid line
using (StreamReader r = new StreamReader(itemDir))
{
string json = r.ReadToEnd();
if (json.Contains("anotheritem"))
{
JObject NoGood = JObject.FromObject(json);
MessageBox.Show(NoGood.ToString());
}
}
The Error:
Object serialized to String. JObject instance expected.
Thank you all for your time and help.
If each object are side by side without space or any other character, you can convert your string to an json array.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
string arrayValue = "[" + value.Replace("}{", "},{") + "]";
var array = JArray.Parse(arrayValue);
var goopArray = array.OfType<JObject>().Where(o => o.Property("anotheritem") == null);
Edit : see my second answer. More robust solution. More modern. And support dotnet core builtin json serializer.
Json.Net
Even better solution, Json.NET have a builtin feature for this exact scenario. See Read Multiple Fragments With JsonReader
The JsonTextReader have a property SupportMultipleContent that allow to read consecutive items when set to true
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var reader = new JsonTextReader(new System.IO.StringReader(value));
reader.SupportMultipleContent = true;
var list = new List<JObject>();
while (reader.Read())
{
var item = JObject.Load(reader);
list.Add(item);
}
System.Text.Json
If you want to use System.Text.Json, it's also acheivable. They are no SupportMultipleContent property but Utf8JsonReader will do the job for you.
string value = "{\"item\":\"value\"}{\"anotheritem\":\"value\"}";
var bytes = Encoding.UTF8.GetBytes(value).AsSpan();
var list = new List<JsonDocument>();
while (bytes.Length != 0)
{
var reader = new Utf8JsonReader(bytes);
var item = JsonDocument.ParseValue(ref reader);
list.Add(item);
bytes = bytes.Slice((int) reader.BytesConsumed);
}

split json string into its constituent 1st child nodes and put keys into string array

I have a Json file which has unknown child nodes each of which have child nodes for an unknown depth.
I want to get the 1st level of child node names into an array.
How do i do this if i dont know their names or the number of child nodes - ie the json structure is dynamic?
eg json input
{
"childNode1":"value", "childNode2":"value", "childNode3":"value", "childNode4":"value"
}
expected output is equivalent to this array:
string[] jsonArray =
new[] { "childNode1", "childnode2", "childNode3", "childnode4" };
The code i have will show me the children in the debugger 'locals', how can i get their keys and values?
JObject json = JObject.Parse(System.IO.File.ReadAllText(filePath));
I can do it if i know what nodes I'm looking for but i don't in this case?
If you deserialize the object as a dictionary, you can get the keys easily. Here's an example using Json.NET.
var dict = JsonConvert.DeserializeObject<Dictionary<string, object>>(s);
string[] jsonArray = dict.Keys.ToArray();
Depending on what you want to do with the object, the second line might be redundant.
If you already have it as a JObject, you can get the names like this:
JObject json = // something
string[] jsonArray = ((IDictionary<string, JToken>)json).Keys.ToArray(); // or
string[] jsonArray = json.Properties().Select(x => x.Name).ToArray();
you could do,
IEnumerable<string> ParsePropertyNames(string s)
{
var o = JObject.Parse(s);
return o.Properties().Select(p => p.Name);
}
which your could use like,
var results = ParsePropertyNames(yourString).ToArray();

Categories