how to parse 3 level nested array using newtonsoft json - c#

I have the following json which is in geojson format, and Id like to be able to parse this into a nested list in c#:
public IList<IList<IList<double>>> Coordinates { get; set; }
"coordinates": [
[
[-3.213338431720785, 55.940382588499197],
[-3.213340490487523, 55.940381867350276],
[-3.213340490487523, 55.940381867350276],
[-3.213814166228732, 55.940215021175085],
[-3.21413960035129, 55.940100842843712]
]
]
I have tried the following but I get an exception:
var node = jsonProperties["geometry"]["coordinates"].Values();
var coordinates = node.Select(x=>x.Value<List<double>>());
Exception detail:
Cannot cast Newtonsoft.Json.Linq.JArray to
Newtonsoft.Json.Linq.JToken.

To deserialize using newtonsoft. Create Foo class with a coordinates property, inclose the JSON script with curly brackets to denote it as an object then call JsonConvert.DeserializeObject<Foo>(Json).
private class Foo
{
public List<List<List<double>>> coordinates { get; set; }
}
var json = #"{
coordinates: [
[
[-3.213338431720785, 55.940382588499197],
[-3.213340490487523, 55.940381867350276],
[-3.213340490487523, 55.940381867350276],
[-3.213814166228732, 55.940215021175085],
[-3.21413960035129, 55.940100842843712]
]
]
}";
var result = JsonConvert.DeserializeObject<Foo>(json);

May not be exactly what you want but using dynamic type I could access the values. For example this sample code
class Program
{
static void Main(string[] args)
{
string sampleJson = #"{ ""coordinates"": [
[
[-3.213338431720785, 55.940382588499197],
[-3.213340490487523, 55.940381867350276],
[-3.213340490487523, 55.940381867350276],
[-3.213814166228732, 55.940215021175085],
[-3.21413960035129, 55.940100842843712]
]
]}";
dynamic d = JObject.Parse(sampleJson);
Console.WriteLine(d.coordinates[0].Count);
foreach (var coord in d.coordinates[0])
{
Console.WriteLine("{0}, {1}", coord[0], coord[1]);
}
Console.ReadLine();
}
displays the following:
5
-3.21333843172079, 55.9403825884992
-3.21334049048752, 55.9403818673503
-3.21334049048752, 55.9403818673503
-3.21381416622873, 55.9402150211751
-3.21413960035129, 55.9401008428437

I suggest you to parse them into something more suitable like List<Tuple<double, double>> though there is also solution for nested lists. Please check my inline comments:
const string json = #"
{
""coordinates"":
[
[
[-3.213338431720785, 55.940382588499197],
[-3.213340490487523, 55.940381867350276],
[-3.213340490487523, 55.940381867350276],
[-3.213814166228732, 55.940215021175085],
[-3.21413960035129, 55.940100842843712]
]
]
}";
var jsObject = JObject.Parse(json);
/*
* 1. Read property "coordinates" of your root object
* 2. Take first element of array under "coordinates"
* 3. Select each pair-array and parse their values as doubles
* 4. Make a list of it
*/
var result = jsObject["coordinates"]
.First()
.Select(pair => new Tuple<double, double> (
pair[0].Value<double>(),
pair[1].Value<double>()
)
).ToList();
And for List<List<List<double>>> please see #YTAM answer.

Related

Sorting JObject inside array by a field value

I have a JSON string like below:
{
"MetaData": {
"ResourcesUsed": 1
},
"Result": [
{
"locations": [
{
"country": "Papua New Guinea",
"city": "Jacquinot Bay",
"locTypeAttributes": {
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-08T04:21:00-07:00",
},
"point": {
"coordinates": [
151.52,
-5.6
],
"type": "Point"
}
},{
"country": "Papua New Guinea2",
"city": "Jacquinot Bay2",
"locTypeAttributes": {
"localDate": "2018-10-08T04:21:00-07:00",
"utcDate": "2018-10-02T04:21:00-07:00",
},
"point": {
"coordinates": [
151.52,
-5.6
],
"type": "Point"
}
}
]
}
]
}
I converted it to a JSON object using Newtonsoft. What I want to do is to sort the locations array(s) inside the Result array by the utcDate field nested in each locations item. I found the following thread: C# Sort JSON string keys. However, I could not still implement it since I have arrays inside my object, while that question deals purely with sorting objects inside objects alphabetically by property name.
Here is a piece of code that I wrote so far:
public string GenerateJson()
{
var model = (JObject)JsonConvert.DeserializeObject(data);
Sort(model);
}
private void Sort(JObject jObj)
{
var props = jObj["Result"][0]["locations"].ToList();
foreach (var prop in props)
{
prop.Remove();
}
foreach (var prop in props.OrderBy(p => p.Name))
{
jObj.Add(prop);
if (prop.Value is JObject)
Sort((JObject)prop.Value);
if (prop.Value is JArray)
{
Int32 iCount = prop.Value.Count();
for (Int32 iIterator = 0; iIterator < iCount; iIterator++)
if (prop.Value[iIterator] is JObject)
Sort((JObject)prop.Value[iIterator]);
}
}
}
You can sort each individual "Result[*].locations" array using LINQ as follows:
// Load the JSON without parsing or converting any dates.
var model = JsonConvert.DeserializeObject<JObject>(data, new JsonSerializerSettings{ DateParseHandling = DateParseHandling.None });
// Construct a serializer that converts all DateTime values to UTC
var serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings{ DateTimeZoneHandling = DateTimeZoneHandling.Utc });
foreach (var locations in model.SelectTokens("Result[*].locations").OfType<JArray>())
{
// Then sort the locations by utcDate converting the value to UTC at this time.
var query = from location in locations
let utcDate = location.SelectToken("locTypeAttributes.utcDate").ToObject<DateTime>(serializer)
orderby utcDate
select location;
locations.ReplaceAll(query.ToList());
}
Notes:
The JSON is initially loaded using DateParseHandling.None to prevent the "localDate" and "utcDate" strings from being prematurely interpreted as DateTime objects with a uniform DateTime.Kind.
(For a discussion of how Json.NET interprets strings that look like dates, see Serializing Dates in JSON.)
We then iterate through all "locations" arrays using SelectTokens("Result[*].locations") where [*] is the JSONPath wildcard character, selecting all entries in the "Results" array.
We then order each "locations" array by deserializing the nested locTypeAttributes.utcDate to a UTC date, then ordering using LINQ.
Finally the array is updated using JArray.ReplaceAll().
If any locTypeAttributes.utcDate property is missing, an exception will be thrown. You could instead deserialize to DateTime? if that is a possibility.
Working sample .Net fiddle here.

C# Json to List

I have a json object as follows:
"dnsNames": {
"type": "array",
"defaultValue": [
"something.else.com",
"something.com",
"else.com"
]
}
I'd like to read that into a List<string> the same way I can read it into a string (i.e. without creating a class for it):
JObject jsonParameters = JObject.Parse(File.ReadAllText(filePath));
string test = jsonParameters["parameters"]["dnsNames"]["defaultValue"].ToString();
Just unsure if that's possible or what the syntax for it might be.
Navigate the object structure as you see it dnsNames.defaultValue then convert that object to a given type (List<string> in our case):
var json =
#"{""dnsNames"": {
""type"": ""array"",
""defaultValue"": [
""something.else.com"",
""something.com"",
""else.com""
]
}}";
var jObject = JObject.Parse(json);
var list = jObject["dnsNames"]["defaultValue"].ToObject<List<string>>();
// ?list
// Count = 3
// [0]: "something.else.com"
// [1]: "something.com"
// [2]: "else.com"

Json Deserialize C#

I want to parsing this json file.
{"features":[{"type":"Feature","geometry":{"type":"Polygon","coordinates":[[[26.4217861898109,40.127607984644],[26.4219934821323,40.1275230229872],[26.4218810759267,40.1273800013679],[26.4216801413981,40.1274730404221],[26.4217861898109,40.127607984644]]]},"properties":{"ParselNo":"1","Alan":"340.48
m2","Mevkii":"-","Nitelik":"Arsa","Ada":"698","Il":"Çanakkale","Ilce":"Merkez","Pafta":"16","Mahalle":"Barbaros"}}],"type":"FeatureCollection","crs":{"type":"name","properties":{"name":"EPSG:4326"}}}
I try this code:
string fileName = file.FileName;
string json = System.IO.File.ReadAllText(fileName);
dynamic stuff = JsonConvert.DeserializeObject(json);
string s1 = Convert.ToString(stuff.features.Count);
string s2 = stuff.properties.ParselNo;
MessageBox.Show(s1);
MessageBox.Show(s2);
s1 is working but s2 give error. How can I fix it?
I want to get it like this:
Coordinates[] coordinates = [(26.xx, 40.xx), (26.xx,40.xx) ... ]
ParselNo = 1
Alan = 340.48
Nitelik = Arsa
Ada = 698
İl = Çanakkale
İlçe = Merkez
Pafta = 16
dat_name = EPSG:4326
what can i do?
If you properly format your json as below i believe
stuff.features.properties.ParselNo;
should get the the Parse1No
{
"features":[
{
"type":"Feature",
"geometry":{
"type":"Polygon",
"coordinates":[
[
[
26.4217861898109,
40.127607984644
],
[
26.4219934821323,
40.1275230229872
],
[
26.4218810759267,
40.1273800013679
],
[
26.4216801413981,
40.1274730404221
],
[
26.4217861898109,
40.127607984644
]
]
]
},
"properties":{
"ParselNo":"1",
"Alan":"340.48 m2",
"Mevkii":"-",
"Nitelik":"Arsa",
"Ada":"698",
"Il":"Çanakkale",
"Ilce":"Merkez",
"Pafta":"16",
"Mahalle":"Barbaros"
}
}
],
"type":"FeatureCollection",
"crs":{
"type":"name",
"properties":{
"name":"EPSG:4326"
}
}
}
According to the json you provided features are List<Feature> so you cannot access a property of list like stuff.features.properties.ParselNo it should be
stuff.features[0].properties.ParselNo
i used features[0] because it will get the first feature from the list and features.Count will return the number of features in list you can use http://json2csharp.com/ to check your json
Edit
and about your second question it should be like this
List<List<double>> s2 =stuff.features[0].geometry.coordinates[0].ToObject<List<List<double>>>();
var firstcordinates = s2[0];
it will get the coordinates from array and s2[0] will get first coordinates from list
I try this:
string s2 = stuff.features.properties.ParselNo;
MessageBox.Show(s2);
give this error:
Error...
This code work: stuff.features[0].properties.ParselNo
But don't this: stuff.features[0].geometry.coordinates[0];
I don't understand it :(
Error code..

Json.NET SelectTokens not working if json contains empty array

I have a valid JSON object that contains multiple "en-US" keys, which I'm trying select. For that purpose I use the JsonPath
"$..en-US"
which is given to the SelectTokens procedure implemented by the Json.NET. It's a JSON framework for .NET . Everything is working fine and well as long as my JSON doesn't contain any empty array.
Here's an example:
var myJsonPath = "$..en-US";
var myJson =
#"{
'controls': [
{
'messages': {
'addSuggestion': {
'en-US': 'Add'
}
}
},
{
'header': {
'controls': []
},
'controls': [
{
'controls': [
{
'defaultCaption': {
'en-US': 'Sort by'
},
'sortOptions': [
{
'label': {
'en-US': 'Name'
}
}
]
}
]
}
]
}
]
}";
var jToken = JObject.Parse(myJson);
var tokens = jToken.SelectTokens(myJsonPath);
Here, the tokens variable will contain just one element! That will be the "en-US" occurence BEFORE the empty array in the 'controls' of the 'header' object. However, when I just leave this 'header' object out:
var myJson =
#"{
'controls': [
{
'messages': {
'addSuggestion': {
'en-US': 'Add'
}
}
},
{
'controls': [
{
'controls': [
{
'defaultCaption': {
'en-US': 'Sort by'
},
'sortOptions': [
{
'label': {
'en-US': 'Name'
}
}
]
}
]
}
]
}
]
}";
I will get all the 3 occurencies of the "en-US" as expected. Btw, if I validate my JsonPath on the first JSON object (i.e. which contains an empty array) in an online tool, then as expected, I get all the three "en-US" cases. This diverges from what I'm getting from the Json.NET. I'm wondering whether it's a bug or do I have to handle this case manually somehow?
This is a bug that has been fixed. Upgrade to the latest version of Json.NET.
If you're in the same situation as me where you're a bit stuck with respect to updating your version of Json.NET, you can work around the issue by doing something along the lines of this:
IEnumerable<JValue> vals = jToken
.Desecendants()
.Where(w => w is JProperty && w.Name=="en-US")
.Select(s => s.Value);
Hope that helps! The vals array will contain the same tokens you would have gotten using the selector you were trying to use before.

Passing Array from Javascript to C#

I have a .js script that contain an array:
The output of the js is like:
var foo=
[
{
"bar1":"value1",
"bar2":"value2"
// And so on...
}
]
I have no access to the js source, so i cannot output as JSON and Deserialize.
I can only get this as a String using WebClient, but how i can parse it and create an Array/Dictionary and work on it inside C#?
You should consider calling WebClient.DownloadString . Then Parse using JSON.Net or whatever
As per the example provided over there
string json = #"{
""Name"": ""Apple"",
""Expiry"": "2008-12-28T00:00:00",
""Price"": 3.99,
""Sizes"": [
""Small"",
""Medium"",
""Large""
]
}";
JObject o = JObject.Parse(json);
string name = (string)o["Name"];
// Apple
JArray sizes = (JArray)o["Sizes"];
string smallest = (string)sizes[0];
// Small
var foo = new JavaScriptSerializer().Deserialize<List<YourModelHere>>(YourString);
You can use a JavaScriptSerializer to deserialize that string:
string str=
#"var foo =
[
{
""bar1"":""value1"",
""bar2"":""value2""
}
]";
JavaScriptSerializer js = new JavaScriptSerializer();
var o = js.Deserialize<Dictionary<string,string>[]>(str.Substring(str.IndexOf('[')));
Result:
Dictionary<String,String> (2 items)
Key Value
------ --------
bar1 value1
bar2 value2

Categories

Resources