How to sort a Newtonsoft JArray? - c#

Would it be possible to sort the JArray below by col2 for example?
[
{
"col1": "thiscol",
"col2": "thisval"
},
{
"col1": "thiscol2",
"col2": "thisval2"
},
{
"col1": "thiscol3",
"col2": "thisval3"
}
]
If converting this to an Array is the only solution then how could I do this?

I don't think you can sort a JArray in place, but you can sort the contents and load the result into another JArray. Would this work for you?
string json = #"
[
{
""col1"": ""foo"",
""col2"": ""bar""
},
{
""col1"": ""baz"",
""col2"": ""quux""
},
{
""col1"": ""fizz"",
""col2"": ""bang""
}
]";
JArray array = JArray.Parse(json);
JArray sorted = new JArray(array.OrderBy(obj => (string)obj["col2"]));
Console.WriteLine(sorted.ToString(Formatting.Indented));
Output:
[
{
"col1": "fizz",
"col2": "bang"
},
{
"col1": "foo",
"col2": "bar"
},
{
"col1": "baz",
"col2": "quux"
}
]
Fiddle: https://dotnetfiddle.net/2lTZP7

Related

C# How to get from json file list of nodes that contains specific key-value

I have a json file like this:
[
{
"key1": {
"find": 5,
"count": 65,
"name": "Parser"
},
"init": {
"key2": {
"find": 5,
"count": 15,
"name": "Some"
},
"arr": [
{
"key2": {
"find": 8,
"count": 32,
"name": "Object"
},
"temp": {
"pay": null
}
}
]
}
},
{
"key3": {
"find": 5,
"count": 23,
"name": "String"
},
"classes": [],
}
]
And I want to get list of all nodes that contains key "find" and value "5". The result have to be:
{
"find": 5,
"count": 65,
"name": "Parser"
},
{
"find": 5,
"count": 15,
"name": "Some"
},
{
"find": 5,
"count": 23,
"name": "String"
}
The difficulty is that the nesting can be any, but I need to get only those nodes that contain key "find" and the value "5" for it. How can I go through the entire file and get the nodes I need?
You can use JToken for this purpose, use the below function to find the nodes.
public void FindNodes(JToken json, string name, string value, List<JToken> nodes)
{
if (json.Type == JTokenType.Object)
{
foreach (JProperty child in json.Children<JProperty>())
{
if (child.Name == name && child.Value.ToString() == value)
{
nodes.Add(child);
}
FindNodes(child.Value, name, value, nodes);
}
}
else if (json.Type == JTokenType.Array)
{
foreach (JToken child in json.Children())
{
FindNodes(child, name, value, nodes);
}
}
}
Use the method in this way,
var json = JsonConvert.DeserializeObject<JToken>(jsonString);
var nodes = new List<JToken>();
FindNodes(json, "find", "5", nodes);

How to replace json from another json in C# using NewtonSoft?

I have two JSON objects -
json1 = {
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "test1",
"arrayProp1": [1, 2, 3],
"arrayProp2": [{
"prop1": "value1",
"prop2": "value2"
},
{
"prop1": "2_value1",
"prop2": "2_value2"
}
]
}
}
json2 = {
"payload": {
"code": "newCode",
"arrayProp1": [3,4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}
]
}
}
If I use the built-in merge (json1.Merge(json2)) the result obtained is -
result : {
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "newCode",
"arrayProp1": [1, 2, 3, 3, 4],
"arrayProp2": [{
"prop1": "value1",
"prop2": "value2"
},
{
"prop1": "newValue1",
"prop2": "newValue2"
},
{
"prop1": "2_value1",
"prop2": "2_value2"
}
]
}
}
Expected result -
{
"payload": {
"firstName": "John",
"lastName": "Doe",
"code": "newCode",
"arrayProp1": [3, 4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}]
}
}
I want to replace the parent property values of json1 based on values provided in json2.
I tried to write a function and this is the current version I have -
string Merge(string req1, string req2) {
try
{
JObject json1 = JObject.Parse(req1);
JObject json2 = JObject.Parse(req2);
foreach (var a in json2.DescendantsAndSelf())
{
if (a is JObject obj)
{
foreach (var prop in obj.Properties())
{
if(json1.SelectTokens(prop.Path).Any())
{
json1[prop.Path] = prop.Value;
}
}
}
}
req1 = json1.ToString();
}
catch(Exception ex)
{
//do nothing
}
return req1; }
There are 2 problems here -
"payload" is identified as property and json1 is replaced fully by json2 because of which I lose some of its properties.
After being replaced, when the loop continues to run, say property 'code' is to be updated, then the property path is payload.code, so on the line json1[prop.path] = prop.Value, instead of updating the existing code in the payload, it creates a new property called payload.code with value "newcode"
The final result of the code above is -
{
"payload": {
"code": "newCode",
"arrayProp1": [3, 4],
"arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}],
"payload.code": "newCode",
"payload.arrayProp1": [3, 4],
"payload.arrayProp2": [{
"prop1": "newValue1",
"prop2": "newValue2"
}],
"payload.arrayProp1[0].prop1": "newValue1",
"payload.arrayProp1[0].prop2": "newValue2"
}
}
Can someone please help me with this?
Your requirement is that array contents are replaced rather than concatenated when merging two JSON objects with JContainer.Merge(). You can achieve this via the JsonMergeSettings.MergeArrayHandling setting, which has the following values:
Concat 0 Concatenate arrays.
Union 1 Union arrays, skipping items that already exist.
Replace 2 Replace all array items.
Merge 3 Merge array items together, matched by index.
Specifically MergeArrayHandling.Replace will work as required:
json1.Merge(json2, new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Replace
});
Demo fiddle here.

How can I find Index of object in JArray based on a matching search?

I am trying to find the index of an object inside an JArray based on a search.
What I want to end up is the ability to do this
JArray articles = (JArray)DetailedData["product"]["articlesList"][x]
The problem is I dont know how to find what x is
The JSON looks like this ( severly cut down )
"articlesList": [
{
"code": "0587026001",
I want to find the index x where code = 0587026001 but I cannot figure it out
I tried
var index = articlesList.IndexOf("$.[?(#.<code>=='0587026001')]");
but that returned -1
How can I find the index x where code matches as per above?
Hope I understood your question correctly. You can find the Index as following
var result = JObject.Parse(json);
var selectedIndex = result["articlesList"].Select((x,index)=> new { Code= x.Value<string>("code"), Node = x, Index = index})
.Single(x=>x.Code == "0587026003")
.Index;
You can use the SelectTokens to find the relevant tokens based on filter criteria.
The below code selects all the token under articleList which has code equals to '0587026001'
IEnumerable<JToken> tokens = o.SelectTokens("$..articlesList[?(#.Code == '0587026001')]");
Check this dotnet fiddle - https://dotnetfiddle.net/EJvyfp which demonstrates the usage of it.
Sample code:
public class Program
{
public static void Main()
{
JArray o = JArray.Parse(#"[{
'Stores': [
'Lambton Quay',
'Willis Street'
],
'articlesList': [
{
'Code': '0587026001',
'Name': 'Acme Co',
'Products': [
{
'Name': 'Anvil',
'Price': 50
}
]
},
{
'Code': '456',
'Name': 'Contoso',
'Products': [
{
'Name': 'Elbow Grease',
'Price': 99.95
},
{
'Name': 'Headlight Fluid',
'Price': 4
}
]
}
]
},
{
'Stores': [
'ABD',
'XYZ'
],
'articlesList': [
{
'Code': '789',
'Name': 'Acme Co',
'Products': [
{
'Name': 'Anvil',
'Price': 50
}
]
},
{
'Code': '1234',
'Name': 'Contoso',
'Products': [
{
'Name': 'Elbow Grease',
'Price': 99.95
},
{
'Name': 'Headlight Fluid',
'Price': 4
}
]
}
]
}]");
//Console.WriteLine(o);
IEnumerable<JToken> tokens = o.SelectTokens("$..articlesList[?(#.Code == '0587026001')]");
Console.WriteLine(tokens.Count());
Console.WriteLine(tokens.First());
Console.WriteLine("Hello World");
}
}
The above program returns the output as
{
"Code": "0587026001",
"Name": "Acme Co",
"Products": [
{
"Name": "Anvil",
"Price": 50
}
]
}
Here's how you could do it:
private static int GetIndex(string code)
{
string json = "{\"product\": {\"articleList\": [{\"code\": \"0587026001\"}, {\"code\": \"0587026002\"}]}}";
var jObject = JObject.Parse(json);
var articleList = JArray.Parse(jObject["product"]["articleList"].ToString());
var requiredArticle = articleList.First(a => a["code"].ToString().Equals(code));
return articleList.IndexOf(requiredArticle);
}

Filtering out the set difference of two List<JObject> in C# using LINQ

I have 2 List<JObject> to be compared for their set differences,
The format of the two List<JObject> to be compared are as follows:
This is the JSON structure for my base List<JObject> :
[
{
"name": "competency",
"subLists": [
{
"canonicalForm": "c1",
"list": [
"c one",
"c 1",
"cone",
"Cone"
]
}
],
"roles": []
},
{
"name": "demoList",
"subLists": [],
"roles": []
}
]
This is the JSON structure of the List<JObject> that I want to find the set difference against:
[
{
"name": "competency",
"subLists": [
{
"canonicalForm": "c1",
"list": [
"c one",
"c 1",
"cone",
"Cone",
"C ONE"
]
},
{
"canonicalForm": "c2",
"list": [
"c two",
"c 2"
]
}
],
"roles": []
},
{
"name": "leavetype",
"subLists": [
{
"canonicalForm": "annual",
"list": [
"Easter"
]
}
],
"roles": []
},
{
"name": "demoList",
"subLists": [],
"roles": []
}
]
With the output set difference JSON being:
[
{
"name": "competency",
"subLists": [
{
"canonicalForm": "c1",
"list": [
"c one",
"c 1",
"cone",
"Cone",
"C ONE"
]
},
{
"canonicalForm": "c2",
"list": [
"c two",
"c 2"
]
}
],
"roles": []
},
{
"name": "leavetype",
"subLists": [
{
"canonicalForm": "annual",
"list": [
"Easter"
]
}
],
"roles": []
}
]
I have tried using the following code using two for-loops:
List<JObject> baseList = JsonConvert.DeserializeObject<List<JObject>>(baseListString);
List<JObject> comparedList = JsonConvert.DeserializeObject<List<JObject>>(comparedListString);
List<JObject> finalResultList = new List<JObject>();
for (int i = 0; i < baseList.Count; i++)
{
for (int j = 0; i < comparedList.Count; j++)
{
if(baseList[i]["subLists"] != comparedList[j]["subLists"])
finalResultList.Add(comparedList[j]);
}
}
But this is not cutting it, I want to compare the entire JObject based on the key values of name, canonicalForm, list keys and filter out the set difference using LINQ. But I am unable to do so.
I have tried using .Except() extension method but that is not working as well.
Edit:
I want to check if there is any change in the 3 keys which are: name, canonicalForm and list, if there are any change in the compareObject compared to the BaseObject I want to return the JObject which has the change. The output is displayed above.
Any help will be appreciated.
I finally solved my problem by implementing the IEqualityComparer for JObject.
Here is my JObjectEqualityComparer class:
public class JObjectEqualityComparer : IEqualityComparer<JObject>
{
public bool Equals(JObject x, JObject y)
{
if (x == null && y == null)
return true;
if ((x != null && y == null) || (x == null && y != null))
return false;
return JObject.DeepEquals(x, y);
}
public int GetHashCode(JObject obj)
{
JTokenEqualityComparer comparer = new JTokenEqualityComparer();
int hashCode = comparer.GetHashCode(obj);
return hashCode;
}
}
Finally I have used this overload of .Except() extension method to find the Set Difference.
Here is the code:
List<JObject> baseList = JsonConvert.DeserializeObject<List<JObject>>(baseListString);
List<JObject> comparedList = JsonConvert.DeserializeObject<List<JObject>>(comparedListString);
List<JObject> finalResultList = new List<JObject>();
finalResultList = comparedList.Except(baseList, new JObjectEqualityComparer()).ToList();
Thanks to Ed Plunkett, dbc and Coding Yoshi for pointing me out in the correct direction.

How to transform a JSON array of objects to an object containing arrays

I have json serialized written with JSON.NET that looks like this:
{
"data": [
{
"A": "1",
"B": "4"
},
{
"A": "2",
"B": "5"
},
{
"A": "3",
"B": "6"
}
]
}
Any idea how can I change from multiple keys to one key with multiple values like this
{
"data": {
"A": [
"1",
"2",
"3"
],
"B": [
"4",
"5",
"6"
]
}
}
Thanks in advance.
You can do this fairly easily using Json.Net's LINQ-to-JSON API:
JObject obj = JObject.Parse(json);
obj["data"] = new JObject(obj["data"]
.Children<JObject>()
.SelectMany(jo => jo.Properties())
.GroupBy(jp => jp.Name)
.Select(g => new JProperty(g.Key, new JArray(g.Values()))));
Console.WriteLine(obj.ToString());
Fiddle: https://dotnetfiddle.net/dXCdlO

Categories

Resources