json.net IEnumerable - c#

I have the following json file
{"fields":[
{
"status":"active",
"external_id":"title",
"config":{},
"field_id":11848871,
"label":"Title",
"values":[
{
"value":"Test Deliverable"
}
],
"type":"text"
},{
"status":"active",
"external_id":"client-name",
"config":{},
"field_id":12144855,
"label":"Client Name",
"values":[
{
"value":"Chcuk Norris"
}
],
"type":"text"
}}
And I want to select the value of the field that has its external_id = "title" for example, I'm using Json.Net and already parsed the object. How do i do this using lambda or linq on the Json object, I trird something like this
JObject o = JObject.Parse(json);
Title = o["fields"].Select(q => q["extenral_id"].Values[0] == "title");
Which is not event correct in terms of syntax. I'm not very proficient in Lambda or Linq thought its been there for a while. Appreciate the help
Thanks
Yehia

Or you can do this:
string json = "{\"fields\":[{\"status\":\"active\",\"external_id\":\"title\",\"config\":{},\"field_id\":11848871,\"label\":\"Title\",\"values\":[{\"value\":\"Test Deliverable\"}],\"type\":\"text\"},{\"status\":\"active\",\"external_id\":\"client-name\",\"config\":{},\"field_id\":12144855,\"label\":\"Client Name\",\"values\":[{\"value\":\"Chcuk Norris\"}],\"type\":\"text\"}]}";
JObject obj = JObject.Parse(json);
JArray arr = (JArray)obj["fields"];
var externalIds = arr.Children().Select(m=>m["external_id"].Value<string>());
externalIds is a IEnumerable array of string
Or you can chain it together and select the object in one line:
var myVal = JObject.Parse(json)["fields"].Children()
.Where(w => w["external_id"].ToString() == "title")
.First();
From there you can append whatever selector you want ie if you want the external_id value then append ["external_id"].ToString() to the end of the first() selector.

Build classes for your objects first, then parse them so you can access them correctly and its no anonymous type anymore.
For example this classes:
class MyJson {
public List<MyField> fields {get;set;}
}
class MyField {
public string status {get;set;}
public string external_id {get;set;}
// and so on
}
Then use that class for parsing the json (don't know the exact syntax right now) like this:
var o = Json.Parse(json, typeof(MyJson));
And then you can select your data easily with Linq and have intellisense in VS (or similar dev env):
var myData = o.fields.Where(q=>q.external_id=="title");

If you had your JSON converted to objects (basically what Marc suggested), the LINQ query would look something like:
o.fields.Single(q => q.external_id == "title")
But if you don't want to do that, you have to access the values by string keys. If you don't want to convert the type of the value, you can simply use indexing (["key"]). But if you want to convert the type, you can use Value<Type>("key"). Putting it together, the whole query might be:
o["fields"].Single(q => q.Value<string>("external_id") == "title")

Related

Converting Newtonsoft code to System.Text.Json which is using Newtonsoft.Json.Linq.JObject

I need help in converting following code which is using newtonsoft to System.Text.Json
string myList = null!;
string jSon = /* From some source */;
object jsonObject = JsonConvert.DeserializeObject(jSon, typeof(object));
// Loop through the keys
foreach (var jsonList in ((Newtonsoft.Json.Linq.JObject)(jsonObject)))
{
if (jsonList.Key == "myKey")
{
foreach (object o in (jsonList.Value.ToArray()))
{
myList += o.ToString().ToUpper() + ',';
}
}
}
json like:
{"myKey":["fir","dsdsd"],"status":"ok"}
With System.Text.Json, you can parse arbitrary JSON using either the JsonDocument or JsonNode document object models. The differences are:
JsonNode is modifiable and is, in my opinion, easier to work with as it most closely resembles Newtonsoft's LINQ to JSON model. It was added in .NET 6.
JsonDocument is read-only, but may be a little more memory-efficient in parsing huge JSON files. It was introduced as part of the original System.Text.Json API in .NET Core 3.0.
Thus, using JsonNode, your code can be rewritten as follows:
static string? QueryJson(string json, string myKey, bool addComma = false)
{
// Parse to a JsonNode and cast to JsonObject. An exception is thrown if not an object
var node = JsonNode.Parse(json)!.AsObject();
// Query the array of strings
var query = (node[myKey] as JsonArray)?.Select(i => i?.ToString().ToUpper());
if (query == null)
return null; // Return null if key not found as per original code
if (addComma)
query = query.Concat(new [] { "" });
// Join the string array into a single comma-separated string
return string.Join(',', query);
}
And here is a version of the same logic using JsonDocument:
static string? QueryJsonWithJsonDocument(string json, string myKey, bool addComma = false)
{
// Parse to a JsonNode and cast to JsonObject. An exception is thrown if not an object
using var doc = JsonDocument.Parse(json);
// Query the array of strings
var query = doc.RootElement.Get(myKey)?.EnumerateArray().Select(e => e.GetString()?.ToUpper());
if (query == null)
return null; // Return null if key not found as per original code
if (addComma)
query = query.Concat(new [] { "" });
// Join the string array into a single comma-separated string
return string.Join(',', query);
}
This uses the following extension method from here to check for missing or null properties:
public static partial class JsonExtensions
{
public static JsonElement? Get(this JsonElement element, string name) =>
element.ValueKind != JsonValueKind.Null && element.ValueKind != JsonValueKind.Undefined && element.TryGetProperty(name, out var value)
? value : (JsonElement?)null;
}
Notes:
You tagged your question .net-core-3.1. This version goes out of support in about a month, on December 13, 2022. If you are using this version you will need to use JsonDocument since JsonNode was introduced in .NET 6.
JsonDocument is disposable, and should be disposed to ensure that pooled memory is returned to the system. JsonNode is not disposable.
It will be more efficient to use string.Join() than manually building a comma-separated string using multiple string additions.
Your current code adds a trailing comma to the string: FIR,DSDSD,. This looks like a bug, but if you want that you can make string.Join() add a trailing comma by adding an extra empty string to the query.
Demo fiddle here.

Replace Json properties with NewtonSoft

No idea where to begin with this, so I don't have any sample code.
I need to change the name of a property in a json document.
var json = (#"{""id"":""12"",
""title"":""My Title"",
""Chunks"":[
{
""id"":""137"",
""title"":""Title"",
""description"":""null"",
""selections"":[
{
""id"":""169"",
""title"":""Choice"",
""sort_order"":""null"",
""questions"":[
]
}
]
}
]
}
}
}");
I need to change the "id" that's got the value of 12 to "document_id" and leave the other ids alone. Are there any C# libraries like NewtonSoft that allow you to change the property rather than the property value. Seems like a common scenario but I haven't seen anything close to what I'm trying to do. I suppose I could convert the json to a string and do a replace, but that doesn't seem very elegant.
An approach using Newtonsoft.Json.Linq.JObject would look something like:
var obj = JObject.Parse(json);
obj["document_id"] = obj["id"]; // create new property called "document_id"
obj.Remove("id"); // remove the "id" property
Console.WriteLine(obj);
Also note that your JSON is not valid. It has two extra } at the end.
Assuming you would want to replace all the keys when there could be more than one node with key as "id" and value "12", you could use Linq to identify Tokens with Key "Id" and Value "12" and then use Add/Remove methods for creating a new node with different name.
For example,
JToken node = JToken.Parse(json);
var jObjectsWithTitle = node
.SelectTokens("$..*")
.OfType<JObject>()
.Where(x => x.Property("id") != null && Convert.ToInt32(x.Property("id").Value) == 12);
foreach(var item in jObjectsWithTitle)
{
item.TryGetValue("id",out var currentValue);
item.Add("document_id",currentValue);
item.Remove("id");
}

Converting json string into list of existing object in C#

I work with an api, that returns a json formatted resultset of a database query.
I have an equivalent object or "model" for the results.
What is the best way to convert the json string into a list of this object?
Of course there are many threads about this, but no one fits my needs properly.
One of the solutions I've found was this:
var jobj = (JObject)JsonConvert.DeserializeObject(json);
var items = jobj.Children()
.Cast<JProperty>()
.Select(j => new
{
ID = j.Name,
Topic = (string)j.Value["Topic_ID"],
Moved = (string)j.Value["Moved_ID"],
Subject = (string)j.Value["subject"],
})
.ToList();
This seems pretty close to what I need. I need to be able to map the keys/values to the appropriate object attributes, which DOES already exist. So maybe you only need to change a few things to make it work for my object?
PS: I'm using Newtonsoft. Any solution for .NET or Newtonsoft or if needed any other library would be great!
I have recently been consuming data from a WebApi and i have been using the following code to convert the json object to an object to work with:
using (var client = new HttpClient())
{
var response = client.GetAsync(apiUri).Result;
// For single objects.
MyObject data = response.Content.ReadAsAsync<MyObject>().Result;
// For an array of objects
IEnumerable<MyObject> data = response.Content.ReadAsAsync<IEnumerable<MyObject>>().Result;
}
Hope this helps.
OK, so you have something like this:
public class MyObject
{
public int ID {get; set;}
public string Topic {get; set;}
public string Subject {get; set;}
}
And you want to instantiate an array of MyObjects with the properties coming from your JSON?
In that case you're just a bout there - you're currently creating a dynamic object with the same properties as MyObject, right? So all you need to do is create an actual MyObject instead:
.Select(j => new **MyObject()**
{
ID = j.Name,
Topic = (string)j.Value["Topic_ID"],
Moved = (string)j.Value["Moved_ID"],
Subject = (string)j.Value["subject"]
})
Note that if your json property names exactly match your C# ones (including case), you can do this as a one-liner with NewtonSoft: http://www.newtonsoft.com/json/help/html/SerializingJSON.htm. But to use that method you'd have to have an intermediate C# class to match your JSON, and then automap (or manually convert) those to MyObjects. Or you'd have to make sure your json and c# properties match exactly. But you're already very close to a quicker (though some would argue less elegant) solution.
Why aren't you deserializing the json into the object type directly? you can do it like this...
var obj = (YourType)JsonConvert.DeserializeObject(
json,
typeof(YourType),
new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.Auto,
MissingMemberHandling=MissingMemberHandling.Ignore
});
or am I missing something in the question?

LINQ need to parse JSON out of a column

In a table, Leads, there is a column Data that contains a JSON string. In a LINQ statement, I need to extract a field from that JSON:
var results = from l in leads
select new MyLeadObject
{
LeadID = l.LeadID,
...
RequestType = (string)l.Data["RequestTypeID"]
};
Here's a shortened version of the JSON:
{
"RequestTypeID":1
}
RequestTypeID is a string.
I've been reading other threads and trying to cobble this together. Not having much luck.
EDIT:
With help from Nkosi, I got this far:
RequestType = (string)JSONNetSerialization.DeserializeJsonNet<LeadData>(l.Data).RequestTypeID
The only problem is that LeadData.RequestTypeID is an enum, so it won't convert the enum to a string. I'm not sure how to get the value of the enum instead of the entire enum itself. Outside of LINQ I could do this: RequestTypeID.GetDisplayName(); but .GetDisplayName() is not recognized by LINQ.
You can use Json.Net to parse the JSON in Data field to get the property.
var results = leads.Select(l =>
new MyLeadObject {
LeadID = l.LeadID,
//...
RequestType = (string)JsonConvert.DeserializeObject(l.Data)["RequestTypeID"]
});

JSON.Net getting a dynamic object

I don't think the title of this post explains what the problem is, but I didn't know how to word it.
Basically I have this response from an API of which I have no control over:
"variations":{
"1033308042319364133":{
"id":"1033308042319364133",
"order":null,
"created_at":"2015-07-20 13:45:45",
"updated_at":"2015-07-20 13:47:11",
"title":"Male",
"mod_price":"+0.00",
"modifier":1033306667720114205,
"product":0,
"difference":"+£0.00"
},
"1033308953984892967":{
"id":"1033308953984892967",
"order":null,
"created_at":"2015-07-20 13:47:34",
"updated_at":"2015-07-20 13:47:34",
"title":"Female",
"mod_price":"+0.00",
"modifier":1033306667720114205,
"product":0,
"difference":"+£0.00"
},
"1033309404260204585":{
"id":"1033309404260204585",
"order":null,
"created_at":"2015-07-20 13:48:27",
"updated_at":"2015-07-20 13:48:27",
"title":"Male (Junior)",
"mod_price":"+0.00",
"modifier":1033306667720114205,
"product":0,
"difference":"+£0.00"
},
"1033309540147265579":{
"id":"1033309540147265579",
"order":null,
"created_at":"2015-07-20 13:48:44",
"updated_at":"2015-07-20 13:48:44",
"title":"Female (Junior)",
"mod_price":"+0.00",
"modifier":1033306667720114205,
"product":0,
"difference":"+£0.00"
}
}
in my c# code I loop through variations like this:
// Get our child variants
var variations = model["variations"];
var IsNull = IsJTokenNull(variations);
var variants = !IsNull ? new List<VariationResponseModel>() : null;
// If we have some variations
if (!IsNull)
{
// Loop through our variations
foreach (var variant in variations)
{
// Add our variant to our list
variants.Add(CreateVariants(variant.First));
}
}
As you can see, I am using variant.First to select the object within the property. My question is, is this the best way to do this? It seems like an awful hack.
This looks like a .net Dictionary more than a list. If VariationResponseModel has the correct properties, you could just do:
var variants = JsonConvert.DeserializeObject<Dictionary<string, Variant>>(variations);
or using the JObject class
var variants = JObject.Parse(variations).ToObject<Dictionary<string, Variant>>();
Both approaches are equivalent, and assume that you got your input as a JSON string. If your input is already a JObject, you can just use:
var variants = variations.ToObject<Dictionary<string, Variant>>()
If you need the variants in a list/enumerable afterwards, just use variants.Values
(JsonConvert / JObject is from the Json.net deserializer)

Categories

Resources