How to parse and read Json formatted text? - c#

I have a File with following formatted Json
{
"Id": 0,
"MsgId": 125,
"ExceptionDetails": "whatever2"
}
{
"Id": 1,
"MsgId": 135,
"ExceptionDetails": "whatever2"
}
THIS IS EXACTLY HOW IT IS IN A FILE WITH NO BRAKETS
I need to parse this text file and get the values of these Keys, for instance in this example I need to get the 0 and 1
var json = System.IO.File.ReadAllText(#"C:\development\commonArea\test3.txt");
var objects = JArray.Parse(json); // parse as array
foreach (JObject root in objects)
{
foreach (KeyValuePair<String, JToken> app in root)
{
if (app.Key == "Id")
{
var appName2 = app.Key;
Console.WriteLine(I HAVE NO IDEA);
}
}
}
Thanks

var objects = JArray.Parse(json); // parse as array
foreach (JObject jobject in objects)
{
Console.WriteLine(jobject.Value<int>("Id"));
}
prints:
0
1
You presented an invalid JSON. I've modified it, so that it became a valid JSON array:
[
{ "Id": 0, "MsgId": 125, "ExceptionDetails": "whatever2" },
{ "Id": 1, "MsgId": 135, "ExceptionDetails": "whatever2" }
]

Make a class that matches and then use a Deserializer. This is using the System.Web.Script.Serialization namespace.
public class Item
{
public int Id { get; set; }
public int MsgId { get; set; }
public string ExceptionDetails { get; set; }
}
public class RootObject
{
public List<Item> Items { get; set; }
public RootObject DeserializeClass()
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
RootObject obj = serializer.Deserialize<RootObject >(JSONSTRING);
return obj;
}
}

Related

How to convert json with dynamic root name to C# list

var stringResult = await HttpHelper.PostAsync(batchUrl, content);
I am getting following result as an API response in C# in above stringResult variable after calling above line. I want to convert below "Items" value to C# list. In every result, first GUID is different. How to convert the below result in C# List. I want only Items.
{
"0934009e-6518-4440-91e3-c252d2e2cc4f": {
"Status": 200,
"Headers": {
"Content-Type": "application/json; charset=utf-8"
},
"Content": {
"Items": [{
"Timestamp": "2021-10-18T14:00:00Z",
"Value": 20.7,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-10-25T14:00:00Z",
"Value": 15.9,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-01T14:00:00Z",
"Value": 14.8,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-08T15:00:00Z",
"Value": 20.1,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-15T15:00:00Z",
"Value": 19.5,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-22T15:00:00Z",
"Value": 19.7,
"UnitsAbbreviation": "ppm"
}, {
"Timestamp": "2021-11-29T15:00:00Z",
"Value": 20.4,
"UnitsAbbreviation": "ppm"
}
]
}
}
}
When some part of the json structure is unknown, you need to explore it manually. There are several ways to do it, but I'm used to passing JObject :
var root = JObject.Parse(text);
// Unknown name property, then iterate
// When the object has one property, First is a good fit
var response = root.First as JProperty;
var guid = response.Name;
var itemsJson = response.Value["Content"]["Items"];
var items = itemsJson.ToObject<List<Item>>();
you can try this code
List<Item> items = JObject.Parse(stringResult).Properties()
.First().Value["Content"]["Items"].ToObject<List<Item>>();
public class Item
{
public DateTime Timestamp { get; set; }
public double Value { get; set; }
public string UnitsAbbreviation { get; set; }
}
go to https://json2csharp.com/
convert your json to C# class.
since your root node is dynamic guid, you cannot directly use class structure deserialization but you can use a inner nodes
Pseudo Program
System.Net.ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
WebClient w = new WebClient();
string json = w.DownloadString(new Uri("https://jsonkeeper.com/b/GETO"));
var firstObject = JObject.Parse(json);
var guid = firstObject.Properties().Select(p => p.Name).FirstOrDefault();
//Console.Write(guid);
Root output = firstObject[guid].ToObject<Root>();
Console.Write(output.Content.Items.Count());
The DTO structure
public class Root
{
public int Status { get; set; }
public Headers Headers { get; set; }
public Content Content { get; set; }
}
public class Content
{
public List<Item> Items { get; set; }
}
public class Headers
{
[JsonProperty("Content-Type")]
public string ContentType { get; set; }
}
public class Item
{
public DateTime Timestamp { get; set; }
public double Value { get; set; }
public string UnitsAbbreviation { get; set; }
}
here's fiddle: https://dotnetfiddle.net/w5fO0w
I have used below code to get items -
var resultObjects = AllChildren(JObject.Parse(json))
.First(c => c.Type == JTokenType.Array )
.Children<JObject>();
foreach (JObject result in resultObjects)
{
foreach (JProperty property in result.Properties())
{
}
}
And method is -
private static IEnumerable<JToken> AllChildren(JToken json)
{
foreach (var c in json.Children())
{
yield return c;
foreach (var cc in AllChildren(c))
{
yield return cc;
}
}
}

Is there a better way to parse this JSON structure?

I'm dealing with a web service that defines the following JSON structure as the return for a GET to the 'positions' endpoint:
{
"positions": {
"position": [
{
"cost_basis": 207.01,
"date_acquired": "2018-08-08T14:41:11.405Z",
"id": 130089,
"quantity": 1.00000000,
"symbol": "AAPL"
},
{
"cost_basis": 1870.70,
"date_acquired": "2018-08-08T14:42:00.774Z",
"id": 130090,
"quantity": 1.00000000,
"symbol": "AMZN"
},
Which is all find and good, except that when there's just one position, they return:
{
"positions":
{
"cost_basis": 1870.70,
"date_acquired": "2018-08-08T14:42:00.774Z",
"id": 130090,
"quantity": 1.00000000,
"symbol": "AMZN"
}
}
Is there some industry trick to deserializing this from JSON? The best I've come up with is:
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, $"v1/accounts/{tradierHost.TradierAccount}/positions"))
using (HttpResponseMessage response = await this.tradierClient.SendAsync(httpRequestMessage))
{
// Make sure we executed with no errors.
response.EnsureSuccessStatusCode();
var jObject = JObject.Parse(await response.Content.ReadAsStringAsync());
IEnumerable<BrokerPosition> brokerPositions = null;
if (jObject["positions"] is JObject positionsObject)
{
// Update one position.
if (positionsObject["position"] is JObject positionObject)
{
var brokerPositionList = new List<BrokerPosition>();
brokerPositionList.Add(positionObject.ToObject<BrokerPosition>());
}
// Update many positions.
if (positionsObject["position"] is JArray positionArray)
{
brokerPositions = positionArray.ToObject<IEnumerable<BrokerPosition>>();
}
}
}
Is there a better way to parse this vendor's API? I don't see a practical way to use a POCO.
I prefer to use a constructor
Data data = JsonConvert.DeserializeObject<Data>(json);
classes
public class Data
{
public Positions Positions { get; set; } = new Positions();
[Newtonsoft.Json.JsonConstructor]
public Data(JToken positions)
{
var positionsObj = JObject.FromObject(positions);
if (positions["position"] != null)
Positions.Position = positionsObj["position"].ToObject<List<Position>>();
else
{
Positions.Position = new List<Position>();
Positions.Position.Add(positionsObj.ToObject<Position>());
}
}
}
public class Positions
{
public List<Position> Position { get; set; }
}
public class Position
{
public double cost_basis { get; set; }
public DateTime date_acquired { get; set; }
public int id { get; set; }
public double quantity { get; set; }
public string symbol { get; set; }
}
or if you don't need the whole object, it can be much simplier. You only need one class
var positionsObj = JObject.Parse(json)["positions"];
List<Position> positions = new List<Position>();
if (positionsObj["position"] != null)
positions = positionsObj["position"].ToObject<List<Position>>();
else
positions.Add(positionsObj.ToObject<Position>());
You can define your class model to use it to parse JSON in the model.And use System.Text.Json or Newtonsoft.Json
Like example:
var responseModel = JsonSerializer.Deserialize<YourReponseModel>(response.Content.ReadAsStringAsync());
So you can get access to Position by object property: responseModel.Positions

Flatten nested JSON with JSON.NET in C#

I receive a bill of materials in JSON format via a WebApi, which has a corresponding hierarchy.
The hierarchy or the nesting can be any depth.
An example bill of materials is shown below:
{
"Quantity":0,
"QuantityUnit":"pcs",
"PartNumber":"12345",
"Parent":"",
"Children":[
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"88774",
"Parent":"12345",
"Children":[
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"42447",
"Parent":"88774"
},
{
"Quantity":0.420,
"QuantityUnit":"kg",
"PartNumber":"12387",
"Parent":"88774"
}
]
}
]
}
How can I resolve this nested structure into a simple structure using JSON.NET in C#?
I want to transform it to:
[
{
"Quantity":0,
"QuantityUnit":"pcs",
"PartNumber":"12345",
"Parent":""
},
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"88774",
"Parent":"12345"
},
{
"Quantity":1,
"QuantityUnit":"pcs",
"PartNumber":"42447",
"Parent":"88774"
},
{
"Quantity":0.420,
"QuantityUnit":"kg",
"PartNumber":"12387",
"Parent":"88774"
}
]
For the deserialization I use the following class:
public class Bom
{
public class TopLevel
{
public double Quantity { get; set; }
public string QuantityUnit { get; set; }
public string PartNumber { get; set; }
public string Parent { get; set; }
public List<Item> Children { get; set; }
}
public class Item
{
public double Quantity { get; set; }
public string QuantityUnit { get; set; }
public string PartNumber { get; set; }
public string Parent { get; set; }
}
public double Quantity { get; set; }
public string QuantityUnit { get; set; }
public string PartNumber { get; set; }
public string Parent { get; set; }
public IList<TopLevel> Children { get; set; }
}
Furthermore, I use this code to deserialize the JSON to an object:
Bom bom = JsonConvert.DeserializeObject<Bom>(File.ReadAllText(jsonPath));
First let's define a mapper
JObject Map(JObject source)
{
var result = (JObject)source.DeepClone();
result.Remove("Children");
return result;
}
It simply clones the object and removes the Children property
Next let's define a recursive function to accumulate the JObjects
void Flatten(JArray children, JArray accumulator)
{
if (children == null) return;
foreach (JObject child in children)
{
accumulator.Add(Map(child));
Flatten((JArray)child["Children"], accumulator);
}
}
And finally let's make use of them
var semiParsed = JObject.Parse(json);
var accumulator = new JArray();
accumulator.Add(Map(semiParsed));
Flatten((JArray)semiParsed["Children"], accumulator);
The ToString call on the accumulator will return this
[
{
"Quantity": 0,
"QuantityUnit": "pcs",
"PartNumber": "12345",
"Parent": ""
},
{
"Quantity": 1,
"QuantityUnit": "pcs",
"PartNumber": "88774",
"Parent": "12345"
},
{
"Quantity": 1,
"QuantityUnit": "pcs",
"PartNumber": "42447",
"Parent": "88774"
},
{
"Quantity": 0.42,
"QuantityUnit": "kg",
"PartNumber": "12387",
"Parent": "88774"
}
]
UPDATE #1
If your source json contains a deep hierarchy (lets say more than 5 levels) then the DeepClone is not really efficient, since you are copying the whole subtree.
To fix this problem you just need to rewrite the Map function
JObject Map(JObject source)
=> JObject.FromObject(new
{
Quantity = (double)source["Quantity"],
QuantityUnit = (string)source["QuantityUnit"],
PartNumber = (string)source["PartNumber"],
Parent = (string)source["Parent"]
});
Deserialize the original list, flatten it with Enumerable.SelectMany, and serialize the resulting sequence.

Serialize Json object with properties dinamycally with dictionary

I need to serialize a response of an object with a dictionary dynamically
left the json examples
I am trying to serialize this response object (request_validator) in a c# class
but this is not working
someone who can help me please, any ideas?
{
"person": {
"testing": "CC",
"simple": "1234545",
"errorNames": {
"id": "655789",
"error": "simple"
},
"errorColor": {
"id": "2",
"error": "error color"
}
}
}
{
"request_validator": [
{
"person.errorNames": [
"error names"
],
"person.errorColor": [
"error color"
]
}
]
}
public class DeserializeResponse{
public Dictionary<string, List<string>> request_validator { get; set; }
}
var error = JsonConvert.DeserializeObject<List<DeserializeResponse>>(content);
You can use Newtonsoft.Json library to get all properties from string array into dictionary
in this case you just need to point to the searched level
using Newtonsoft.Json.Linq;
...
JObject validator = JObject.Parse(content);
IJEnumerable<JToken> validatorTokens = validator.SelectTokens("request_validator")?.Values();
Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
if (validatorTokens != null)
{
foreach (JProperty prop in validatorTokens.Values())
{
if (!errors.ContainsKey(prop.Name))
{
errors.Add(prop.Name, new List<string>());
}
errors[prop.Name].Add(prop.Value?.ToString());
}
}
public class DeserializeResponse
{
[JsonPropertyName("request_validator")]
public RequestValidator[] RequestValidator { get; set; }
}
public class RequestValidator
{
[JsonPropertyName("person.errorNames")]
public string[] PersonErrorNames { get; set; }
[JsonPropertyName("person.errorColor")]
public string[] PersonErrorColor { get; set; }
}
...
var error = JsonSerializer.Deserialize<DeserializeResponse>(content);

Deserializing this object in JSON.NET

I have the following object:
{
"pickups": {
"7": [
5,
8
],
"10": [
6,
7,
9
],
"15": [
1
],
"20": [
0,
2
],
"25": [
3,
4
]
}
}
I'd like to de-serialize each pickups element into the following object:
public class Pickups {
public Pickup[] pickups;
}
public class Pickup {
public int Group; // This could be the 7, 10, 15, 20, 25, etc.
public int[] Values; // If this was the "7" grouping, it would contain 5, 8.
}
As you can see from the data its a bit tricky to do this. I've been trying to use a JsonConverter to convert the object with a bit of custom code but its been a nightmare and I haven't been able to get it right. I am wondering if anyone would know the best way to convert this type of object into the correct format I need?
While a converter would be a good choice you can still deserialize the Json and construct the desired object graph
var root = JsonConvert.DeserializeObject<RootObject>(json);
var pickups = new Pickups {
pickups = root.pickups.Select(kvp =>
new Pickup {
Group = int.Parse(kvp.Key),
Values = kvp.Value
}
).ToArray()
};
Where
public class RootObject {
public IDictionary<string, int[]> pickups { get; set; }
}
This is what son2csharp.com says, its gets error because you can not define names with starting number.
public class Pickups
{
public List<int> __invalid_name__7 { get; set; }
public List<int> __invalid_name__10 { get; set; }
public List<int> __invalid_name__15 { get; set; }
public List<int> __invalid_name__20 { get; set; }
public List<int> __invalid_name__25 { get; set; }
}
public class RootObject
{
public Pickups pickups { get; set; }
}
But I think
[DataMember(Name = "Name")]
should work cause its not an error in JSON format side.
If it is a viable option for you to use JObject.Parse(...) instead, you could use the following code (and write it more cleanly, with exception handling and safe casts and so on):
var jsonPickups = JObject.Parse(json);
var myPickups = new Pickups
{
pickups = jsonPickups.First.First.Select(x =>
{
JProperty xProp = x as JProperty;
return new Pickup
{
Group = int.Parse(xProp.Name),
Values = (xProp.Value as JArray).Select(y => int.Parse(y.ToString())).ToArray()
};
}).ToArray()
};

Categories