serialize dictionary with Json.net and select query on entity - c#

I have code that looks like this...
var records = from part in this.DataWorkspace.AUTOData.TestParameterViews
select new
{Name = part.ParamName, Val = part.CurrentValue}
File.WriteAllText(#"c:\params.json", JsonConvert.SerializeObject(new{parameters = records }, Formatting.Indented));
The generated json file looks like this.....
{
"parameters": [
{
"Name": "Var1",
"Val": 6666.0
},
{
"Name": "Var2",
"Val": 1.0
},
{
"Name": "Var3",
"Val": 5500.0
},
And so on...listing all the members within the entity.
PROBLEM: I would like the json output to be in a dictionary format (shown below), but still query the entity.
"parameters": {
"Var1": 6666.0,
"Var2": 1.0,
"Var3": 5500.0,
I have tried the following code but am hung up on syntax. Specifically Intellisense is indicating an error on the select saying "Cannot implicitly convert type....An explicit conversion exists(are you missing a cast?)
Dictionary<string, float> records = from part in this.DataWorkspace.AUTOData.TestParameterViews
select new Dictionary<string, float>
{Name = part.ParamName, Val = part.CurrentValue}
File.WriteAllText(#"c:\params.json", JsonConvert.SerializeObject(new{parameters = records }, Formatting.Indented));
Thanks for your help!

Create the dictionary. Then loop thru TestParameterViews adding to the dictionary. Then serialize.
Dictionary<string, float> records = new Dictionary<string, float>();
this.DataWorkspace.AUTOData.TestParameterViews.ForEach(part => part.ParamName, part.CurrentValue);
File.WriteAllText(#"c:\params.json", JsonConvert.SerializeObject(new { parameters = records }, Formatting.Indented));

Related

Add a list in an existing JSON value

So I have below call to a method where my argument is a json string of this type
var jsonWithSearchData = await querySearchData(jsonOut);
jsonOut ->
[
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": "",
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
]
The querySearchData() returns me two list something like this :["P123","P124","P987"] and ["Ba123","KO817","Daaa112"]
I want to add this list in my r:searchData key above. The key inside my searchData i.e. r:Porelation and ClassA and ClassB remains static. So I would like my searchData in my input Json to finally become something like this.
"r:searchData": {
"r:Porelation":{
"ClassA": ["P123","P124","P987"],
"ClassB": ["Ba123","KO817","Daaa112"]
}
},
How can I do this? What I tried:
JArray jfinObject = JArray.Parse(jobjects);
jfinObject["r:searchData"]["r:relations"]["ClassA"] = JArray.Parse(ListofCode.ToString());
And I get below error:
System.Private.CoreLib: Exception while executing function: Function1.
Newtonsoft.Json: Accessed JArray values with invalid key value:
"r:searchData". Int32 array index expected.
There are a few ways you can add a node/object/array to existing json.
One option is to use Linq-to-Json to build up the correct model.
Assuming you have the json string described in your question, the below code will add your desired json to the r:searchData node:
var arr = JArray.Parse(json); // the json string
var payloadNode = arr[0]["data"]["payload"];
// use linq-to-json to create the correct object
var objectToAdd = new JObject(
new JProperty("r:Porelation",
new JObject(
new JProperty("r:ClassA", array1),
new JProperty("r:ClassB", array2))));
payloadNode["r:searchData"] = objectToAdd;
where array1 and array2 above could come from a linq query (or just standard arrays).
// Output:
{
"data": {
"_hash": null,
"kind": "ENY",
"id": "t123",
"payload": {
"r:attributes": {
"lok:934": "#0|I"
},
"r:relations": {
"lok:1445": "15318",
"lok:8538": "08562"
},
"r:searchData": {
"r:Porelation": {
"r:ClassA": [
"P123",
"P456"
],
"r:ClassB": [
"Ba123",
"Ba456"
]
}
},
"r:type": [
"5085"
]
},
"type": "EQT",
"version": "d06"
}
}
Online demo
Another option is to create the json from an object, which could be achieved using JToken.FromObject(). However, this will only work if you have property names which are also valid for C# properties. So, this won't work for your desired property names as they contain invalid characters for C# properties, but it might help someone else:
// create JToken with required data using anonymous type
var porelation = JToken.FromObject(new
{
ClassA = new[] { "P123", "P456" }, // replace with your arrays here
ClassB = new[] { "Ba123", "Ba456" } // and here
});
// create JObject and add to original array
var newObjectToAdd = new JObject(new JProperty("r:Porelation", porelation));
payloadNode["r:searchData"] = newObjectToAdd;

'Accessed JObject values with invalid key value: 1. Object property name expected.'

I am trying to get JSON data from an api.
I have this json with me:
{
"elements": [
{
"id": 1,
"name": "Bob",
"address": "abc street",
"hobbies": {
"indoor": "Games, reading books",
"outdoor": ""
}
},
{
"id": 2,
"name": "Mark",
"address": "def street",
"hobbies": {
"indoor": "Games, reading books",
"outdoor": ""
}
}
]
}
I have this code with me:
using(var httpClient = new HttpClient()) {
HttpResponseMessage response = httpClient.GetAsync("api_url_here").Result;
var studentJsonString = response.Content.ReadAsStringAsync().Result;
var Jsresult = new JavaScriptSerializer().Deserialize<dynamic>(studentJsonString).ToString();
JObject jObject = JObject.Parse(Jsresult);
IEnumerable<dynamic> listDyn = jObject[0].Select(items => new StudentModel// gives error here as whole
{
id = items["id"].ToString(),
name = items["name"].ToString(),
address= items["address"].ToString()
});
}
But when I am calling the above method but it is giving me an error:
'Accessed JObject values with invalid key value: 1. Object property name expected.'
What am I missing?
Why are you deserializing twice? The result of
JavaScriptSerializer().Deserialize(customerJsonString)
is already an object. You don't need to parse it again with JObject.Parse(). You can just do
JObject jObject= JObject.Parse(customerJsonString)
Furthermore the result of JObject.Parse() is a dictionary and not an array. It has properties, which you can access by their names. For instance
jObject["elements"]
But of course, the compiler can't possibly predict, that jObject["elements"] will be an IEnumerable, so you will have to make sure of that.
jObject.Value<JArray>("elements").Select(item => ...)
This reads the property elements, of jObject as a JArray.

Last entry in dictionary overwrites first written entry when adding dictionary to json file [duplicate]

This question already has an answer here:
Adding object to JArray overwriting first element
(1 answer)
Closed 4 years ago.
I have an existing json file which looks like this:
{
"players": [],
"games": []
}
I want to add objects to the players array so it looks like this:
{
"players": [
{
"name": "Peter",
"checksum": "6fa95b1427af77b3d769ae9cb853382f"
},
{
"name": "John",
"checksum": "61409aa1fd47d4a5332de23cbf59a36f"
},
{
"name": "Bob",
"checksum": "2fc1c0beb992cd7096975cfebf9d5c3b"
}
],
"games": []
}
Players are stored in a global Dictionary<string, string>. But in my implementation, the next element in the dictionary overwrites the first written element so when the loop is at John the next element would be Bob and then Peter gets replaced by Bob. The result of this looks like this:
{
"players": [
{
"name": "Bob",
"checksum": "2fc1c0beb992cd7096975cfebf9d5c3b"
},
{
"name": "John",
"checksum": "61409aa1fd47d4a5332de23cbf59a36f"
},
{
"name": "Bob",
"checksum": "2fc1c0beb992cd7096975cfebf9d5c3b"
}
],
"games": []
}
This is my code:
string json = File.ReadAllText("file.json");
JObject jsonObject = JObject.Parse(json);
JArray jsonPlayerArray = (JArray) jsonObject["players"];
JObject newPlayerEntry = new JObject();
var sortedDict = PlayerChecksumDict.OrderBy(x => x.Key);
foreach (var item in sortedDict)
{
newPlayerEntry["name"] = item.Key;
newPlayerEntry["checksum"] = item.Value;
jsonPlayerArray.Add(newPlayerEntry);
}
string modifiedJson = jsonObject.ToString(Formatting.Indented);
File.WriteAllText("file-modified.json", modifiedJson);
(Similar questions to this have been asked several times, but I haven't been able to find a duplicate, so I figure it's worth answering instead.)
You're creating a single JObject instance, then modifying it multiple times within your loop. Each iteration will overwrite the data set in the previous iteration. Your JArray ends up with lots of references to the same JObject.
Instead, you need to create a new JObject for each entry in your dictionary. To do this, you just need to move the declaration of newPlayerEntry into the loop:
var sortedDict = PlayerChecksumDict.OrderBy(x => x.Key);
foreach (var item in sortedDict)
{
JObject newPlayerEntry = new JObject();
newPlayerEntry["name"] = item.Key;
newPlayerEntry["checksum"] = item.Value;
jsonPlayerArray.Add(newPlayerEntry);
}
Now each element in the JArray will be a reference to a different JObject.

How take this json path in newtonsoft.json C#

I have been building an application where JSON will be provided from a user API. It should read the data from the JSON using JSONPath and persist the selected portions. I am trying to do this using Json.Net (Newtonsoft). The following JSON is a sample:
{
// other properties here and different structure here
"Data": [
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
},
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
},
{
"Code": "625087",
"Name": "Customer Name",
"Email": "test#hfgidfgd.com"
}
],
// other properties here and different structure here
}
I would like to extract the array presented by the Data property content using JSONPath and convert it to List<Dictionary<string, object>> to manipulate in my application.
In tools like jsonpath.com the following JSONPath query works fine but with Newtonsoft it does not:
// get that json
string content = GetJson();
var jo = JObject.Parse(content);
var jsonPath = "$..Data.*";
var jsonPathResult = jo.SelectTokens(jsonPath, true /* to get error when it is not found */ );
Instead I got the exception:
Property '*' not valid on JArray.
If I do the JSONPath like this:
var jsonPath = "$..Data"; // same for just: "Data"
var jsonPathResult = jo.SelectTokens(jsonPath);
I have to loop on the result with two nested foreach, what I think it is not an elegant solution:
var result = new List<Dictionary<string, object>>();
foreach (var jsonResult in jsonPathResult)
{
foreach (var item in jsonResult)
{
var fields = JsonConvert.DeserializeObject<Dictionary<string, object>>(item.ToString());
// some adjusts on the fields dictionary will be applied here...
result.Add(fields);
}
}
Is there any way to get the result to take a single loop the only the content of Data property?
As shown in JSONPath - XPath for JSON, the syntax for an array element wildcard is [*]. Thus your code should look like:
var jsonPath = "$..Data[*]";
var result = jo.SelectTokens(jsonPath, true /* to get error when it is not found */ )
.Select(o => o.ToObject<Dictionary<string, object>>())
.ToList();
Here I am using JToken.ToObject<T>() to deserialize each array element directly to a Dictionary<string, object>> without re-serializing to a string.
Sample working .Net fiddle.

How to get the name of a JSON object using? (C# Newtonsoft.JSON)

For those of you familiar with Minecraft, the 1.8 update stores the sounds as a file with an encrypted hash as the name (which you can really just change the extension to .ogg to play). There is an index stored as a JSON file in the assets folder which shows the proper sound name for each file with the encrypted hash name.
I'm trying to create a program that which the user types the name and it will find the sound(s) that contains that name. The index is stored in this fashion:
{ "objects":{"minecraft/sounds/mob/wither/idle2.ogg": {
"hash": "6b2f86a35a3cd88320b55c029d77659915f83239",
"size": 19332
},
"minecraft/lang/fil_PH.lang": {
"hash": "e2c8f26c91005a795c08344d601b10c84936e89d",
"size": 74035
},
"minecraft/sounds/note/snare.ogg": {
"hash": "6967f0af60f480e81d32f1f8e5f88ccafec3a40c",
"size": 3969
},
"minecraft/sounds/mob/villager/idle1.ogg": {
"hash": "a772db3c8ac37dfeb3a761854fb96297257930ab",
"size": 8605
},
"minecraft/sounds/mob/wither/hurt3.ogg": {
"hash": "a4cf4ebe4c475cd6a4852d6b4228a4b64cf5cb00",
"size": 16731
}
For example if the user types wither, it will grab the hashes for "minecraft/sounds/mob/wither/idle2.ogg"
and
"minecraft/sounds/mob/wither/hurt3.ogg"
My question is, how do I get the object names (the names, not the properties) to compare with the user's keyword string.
Sorry if I didn't use proper terminology for some words, I don't tinker with JSON files much. Correct my terminology as needed.
EDIT
This answer solves it a lot more nicely (without dynamic):
https://stackoverflow.com/a/32129497/563532
Original answer:
This works:
var obj = JsonConvert.DeserializeObject<dynamic>(#"{ ""objects"":{""minecraft/sounds/mob/wither/idle2.ogg"": {
""hash"": ""6b2f86a35a3cd88320b55c029d77659915f83239"",
""size"": 19332
},
""minecraft/lang/fil_PH.lang"": {
""hash"": ""e2c8f26c91005a795c08344d601b10c84936e89d"",
""size"": 74035
},
""minecraft/sounds/note/snare.ogg"": {
""hash"": ""6967f0af60f480e81d32f1f8e5f88ccafec3a40c"",
""size"": 3969
},
""minecraft/sounds/mob/villager/idle1.ogg"": {
""hash"": ""a772db3c8ac37dfeb3a761854fb96297257930ab"",
""size"": 8605
},
""minecraft/sounds/mob/wither/hurt3.ogg"": {
""hash"": ""a4cf4ebe4c475cd6a4852d6b4228a4b64cf5cb00"",
""size"": 16731
}
}
}");
var t = obj.objects;
var names = new HashSet<String>();
foreach(JProperty fileThing in t)
{
names.Add(fileThing.Name);
}
names.Dump();
Gives:
minecraft/sounds/mob/wither/idle2.ogg
minecraft/lang/fil_PH.lang
minecraft/sounds/note/snare.ogg
minecraft/sounds/mob/villager/idle1.ogg
minecraft/sounds/mob/wither/hurt3.ogg
You can also do this:
var t = obj.objects;
var names = new Dictionary<String, String>();
foreach(JProperty fileThing in t)
{
names.Add(fileThing.Name, (string)t[fileThing.Name].hash);
}
Which gives you a dictionary linking the original name to the hash:
minecraft/sounds/mob/wither/idle2.ogg -> 6b2f86a35a3cd88320b55c029d77659915f83239
minecraft/lang/fil_PH.lang -> e2c8f26c91005a795c08344d601b10c84936e89d
minecraft/sounds/note/snare.ogg -> 6967f0af60f480e81d32f1f8e5f88ccafec3a40c
minecraft/sounds/mob/villager/idle1.ogg -> a772db3c8ac37dfeb3a761854fb96297257930ab
minecraft/sounds/mob/wither/hurt3.ogg -> a4cf4ebe4c475cd6a4852d6b4228a4b64cf5cb00
Assuming you have a jsonString as a string variable.
jsonString = "";
JArray array = JArray.Parse(json);
foreach (JObject content in array.Children<JObject>())
{
foreach (JProperty prop in content.Properties())
{
Console.WriteLine(prop.Name);
}
}

Categories