Is there any way to combine 2 foreach loops?
I'm trying to get the value of “total” and “Na” from a JSON file in one loop but I doesn’t work.
I can’t find the value of “total” when I use “data.items” and I can’t find the value of “Na” when I use “data.total”.
I tried to use “data” instead but it doesn’t work either......
Code:
foreach (var p in jsonbject.SelectToken("data.items"))
{
Na = "";
}
foreach (var f in jsonbject.SelectToken("data.total"))
{
total = "";
}
JSON code
{{
"data": {
"total": 125,
"items": [
{
"Na": "hdbcjd213",
}
I want to extract the value of "total" and "items" and save in the database.
In short, I want to write something like this:
foreach (var p in jsonbject.SelectToken("['data.total','data.items']"))
{
total = "";
id = "";
}
You are probably trying the wrong approach.
The best approach would be to convert the data into a poco object
public class Item
{
[JsonProperty("Na")]
public string Na { get; set; }
}
public class Data
{
[JsonProperty("total")]
public int total { get; set; }
[JsonProperty("items")]
public IList<Item> items { get; set; }
}
public class Example
{
[JsonProperty("data")]
public Data data { get; set; }
}
And then deserialize the data-
var data = JsonConvert.Deserialize<Example>("{ \"data\": ...... ")
Now you can get the data using the object data. data.Items, data.Total.
So you can write -
foreach( var item in data.Items){
var toal = data.total;
var na = item.Na;
}
Alternatively, If you only need to do is to get the values, you can use dynamic.
var data = JsonConvert.Deserialize<dynamic>("{ \"data\": ...... ");
var items = data.items;
var total = data.total;
....
foreach( var item in data.Items){
var total = data.total;
var na = item.Na;
}
but for this approach you have to cast them again whenever you use them.
I hope this helps. If this is not something you are looking for, let me know.
Related
Is it possible to do special formatted order in c#?
I have *.json file with data like
{
"RECORDS": [
{
"ROWW": "279166",
"ALBUMID": "3",
"LINK": "https://...1"
},
{
"ROWW": "279165",
"ALBUMID": "1",
"LINK": "https://...2"
},
{
"ROWW": "279164",
"ALBUMID": "2",
"LINK": "https://...3"
}]
}
... a lot of records. And I need to get DataRows ordered by Roww casted like number.
That's How I trying to do this:
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
//...
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public class RECORD_PHOTO
{
public string ROWW { get; set; }
public string ALBUMID { get; set; }
public string LINK { get; set; }
}
public class PhotoObject
{
public List<RECORD_PHOTO> RECORDS { get; set; }
}
public List<string[]> listForJson = new List<string[]>();
public List<String> PHOTO_Rows = new List<String>();
public List<String> PHOTO_AlbumIds = new List<String>();
public List<String> PHOTO_Links = new List<String>();
string JsonFileName = #"C:\temp_work\test.json"
public DataTable dtFromJson;
private void Starting()
{
string jsonn = File.OpenText(JsonFileName).ReadToEnd();
var result = JsonConvert.DeserializeObject<PhotoObject>(JsonFileName);
PHOTO_Rows = result.RECORDS.Select(p => p.ROWW).ToList();
PHOTO_AlbumIds = result.RECORDS.Select(p => p.ALBUMID).ToList();
PHOTO_Links = result.RECORDS.Select(p => p.LINK).ToList();
for (int i = 0; i < PHOTO_Rows.Count; i++)
{
listForJson.Add(new string[] { PHOTO_Rows[i], PHOTO_AlbumIds[i], PHOTO_Links[i]});
}
dtFromJson = ConvertListToDataTable(VKPH);
dtFromJson.Columns[0].ColumnName = "ROWW";
dtFromJson.Columns[1].ColumnName = "ALBUMID";
dtFromJson.Columns[2].ColumnName = "LINK";
//
DataRow[] rows = dtFromJson.Select("", "ROWW ASC");
}
}
}
But Sorting in Select by "ROWW" worked like String so I need to add some cast like:
DataRow[] rows = dtFromJson.Select("", "TO_NUMBER(ROWW) ASC");
But this is wrong
The DataColumn.Expression property can be used to add another column to the table that maintains an int version of your ROWW column:
dtFromJson.Columns.Add("ROWWint", typeof(int)).Expression = "CONVERT([ROWW], 'System.Int32')";
You can then orderby this column in your Select
DataRow[] rows = dtFromJson.Select("", "ROWWint");
See it in action: https://dotnetfiddle.net/Cuh2np
--
You could also query the row collection using LINQ:
dtFromJson = dtFromJson.Cast<DataRow>().OrderBy(x => Convert.ToInt32((string)x["ROWW"])).ToArray();
if you want to sort by ROWW just like number then try below piece of code:
string jsonn = File.OpenText(JsonFileName).ReadToEnd();
//Your code modified. Initially it was reading file name .
//Now reading json string from file.
var result = JsonConvert.DeserializeObject<PhotoObject>(jsonn);
//Sort by ROWW after converting to int.
var sortedByRowwResult = result.RECORDS.OrderBy(x => Convert.ToInt32(x.ROWW)).ToList();
After this you can put into data table. But please check your requirement. Is it really required to put json into datatable?
I have a json dataset that varies widely. it can have a field that is either an object or a list. how do I map these into a data model property if when I'm ingesting the data it can be either or. I can have a list of if else statements to check if a property is a list or object but for 10 fields that would grow rather big and make the code ugly.
field:{property1: 3, property2:4}
or
field:{[property1: 3, property2:4], [property1: 5, property2:6]}
if I understand you correctly, you receive data whose format is partially unknown to you.
var input = "{\"field\":{\"property1\": 3, \"property2\":4, \"property3\": 5, \"property4\":6}}";
var obj = JsonConvert.DeserializeObject<JObject>(input);
var res = new MyClass(){Fields = new List<MyField>()};
var field = obj.SelectToken("field") as JObject;
if(field != null)
{
foreach (var item in field.Properties())
{
res.Fields.Add(new MyField()
{
Name = item.Name,
Value = item.Value.Value<int>()
});
}
}
public sealed class MyField
{
public string Name { get; set; }
public object Value { get; set; }
}
public sealed class MyClass
{
public List<MyField> Fields { get; set; }
}
I am trying to parse manually a string in json. This is how my json look like
{{
"dbViews": [
{
"viewID": 0,
"viewColumns": [
{
"dbTitle": "ColNmid",
"viewTitle": "string",
"activated": true,
"activatedLabel": "Afficher"
},
{
"dbTitle": "ColNmdelete",
"viewTitle": "string",
"activated": true,
"activatedLabel": "Afficher"
}
]
}
],
"AddViewName": "test"
}}
This is how i am trying to read it.
UserViewDto User = new UserViewDto();
dynamic obj = JObject.Parse(json);
User.id = obj.dbViews.viewID;
User.viewName = obj.AddViewName;
foreach (var item in obj.viewColumns)
{
if (obj.dbTitle == "ColNmid")
{
User.ColNmid = obj.viewTitle;
}
}
I can only read addViewName, i can't seem to access viewID or viewColumn.
Update:
after the comments I obviously miss the second array. Here my new code witch work
UserViewDto User = new UserViewDto();
dynamic obj = JObject.Parse(json);
User.viewName = obj.AddViewName;
foreach (var view in obj.dbViews)
{
User.id = view.viewID;
foreach (var item in view.viewColumns)
{
if (item.dbTitle == "ColNmid")
{
User.ColNmid = item.viewTitle;
}
}
}
Your json in question is invalid (extra { and } at start and end). It seems that you are using Newtonsoft's Json.NET library. Usual approach is to create model corresponding to your json structure and deserialize it:
public class Root
{
[JsonProperty("dbViews")]
public List<DbView> DbViews { get; set; }
[JsonProperty("AddViewName")]
public string AddViewName { get; set; }
}
public class DbView
{
[JsonProperty("viewID")]
public long ViewId { get; set; }
[JsonProperty("viewColumns")]
public List<ViewColumn> ViewColumns { get; set; }
}
public class ViewColumn
{
[JsonProperty("dbTitle")]
public string DbTitle { get; set; }
[JsonProperty("viewTitle")]
public string ViewTitle { get; set; }
[JsonProperty("activated")]
public bool Activated { get; set; }
[JsonProperty("activatedLabel")]
public string ActivatedLabel { get; set; }
}
var result = JsonConvert.DeserializeObject<Root>();
You don't need to include all properties in your class, you can include only needed ones.
If you don't want to create custom models and want to loop through the JObject properties in your case you can do it for example like that:
var jObj = JObject.Parse(json);
foreach(var view in jObj["dbViews"]) // dbViews is an array
{
Console.WriteLine(view["viewID"]);
foreach (var viewColumn in view["viewColumns"]) // viewColumns is an array
{
Console.WriteLine(viewColumn["dbTitle"]);
}
}
I am trying to compare json value and based on that i want to update the existing value,for example, currently we have "value" : [r0] in json, i want to compare and if value : [r0] ,then update it to [r0,r1] but iam hiting error that it cannot compare and there is a cast issue, could someone suggest what could be done
public void updateJsonParameter(string file)
{
try
{
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
var jobject = JObject.Parse(file);
var ringvalue = (string)jobject["properties"]["parameters"]["ringValue"]["value"]; // unable to case here and compare
jobject["properties"]["parameters"]["ringValue"]["value"] = array; // able to update value but i want to update after comparing the existing values
var result = JsonConvert.SerializeObject(jobject);
}
following is the json format
{
"properties": {
"displayName": "jayatestdefid",
"description": "test assignment through API",
"metadata": {
"assignedBy": "xyz#gmail.com"
},
"policyDefinitionId": "/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters": {
"ringValue": {
"value": ["r0"]
}
},
"enforcementMode": "DoNotEnforce",
}
}
jobject.properties.parameters.ringValue.value is an array ["r0"] with one element "r0". If you want to check if it's an array with one element and that element is "r0", do exactly that:
var ringvalue = jobject["properties"]["parameters"]["ringValue"]["value"];
if(ringvalue.length == 1 && ringvalue[0] == "r0")
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
You could compare the ringvalue (which is an JArray) using JArray.DeepEquals and then replace if the comparison returns true. For example,
var list = new List<string> { "joe", "test" };
JArray array = new JArray(list);
JArray valueToCompare = new JArray(new[]{"r0"});
var ringvalue = (JArray)jobject["properties"]["parameters"]["ringValue"]["value"];
if(JArray.DeepEquals(ringvalue,valueToCompare))
{
jobject["properties"]["parameters"]["ringValue"]["value"] = array;
}
First, as Klaycon said in his answer, it's worth noting that your "value" is not a single string. In json, whenever you see [ and ] then you have a collection, or an array, or a list.
When I work with json strings, I always like to be able to convert them into a strongly typed object. There is a very handy online tool I use all the time: http://json2csharp.com/
I took your json string that you provided and pasted it into that website. Here is that your object(s) look like when converted into c# classes:
public class RootObject // You can name this whatever you want
{
public Properties properties { get; set; }
}
public class Metadata
{
public string assignedBy { get; set; }
}
public class RingValue
{
public List<string> value { get; set; }
}
public class Parameters
{
public RingValue ringValue { get; set; }
}
public class Properties
{
public string displayName { get; set; }
public string description { get; set; }
public Metadata metadata { get; set; }
public string policyDefinitionId { get; set; }
public Parameters parameters { get; set; }
public string enforcementMode { get; set; }
}
Now, we can easily do the logic you need as follows:
// This is your json string, escaped and turned into a single string:
string file = "{ \"properties\": { \"displayName\": \"jayatestdefid\", \"description\": \"test assignment through API\", \"metadata\": { \"assignedBy\": \"xyz#gmail.com\" }, \"policyDefinitionId\": \"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test\", \"parameters\": { \"ringValue\": { \"value\": [\"r0\"] } }, \"enforcementMode\": \"DoNotEnforce\", }}";
// Convert your json string into an instance of the RootObject class
RootObject jobject = JsonConvert.DeserializeObject<RootObject>(file);
// Get a list of all the "values"
List<string> values = jobject.properties.parameters.ringValue.value;
// Loop over your colleciton of "value" and do your logic
for (int i = 0; i < values.Count; ++i)
{
if (values[i] == "r0")
{
values[i] = "r0,r1";
}
}
// And finally, turn your object back into a json string
var result = JsonConvert.SerializeObject(jobject);
And this is the final result:
{
"properties":{
"displayName":"jayatestdefid",
"description":"test assignment through API",
"metadata":{
"assignedBy":"xyz#gmail.com"
},
"policyDefinitionId":"/providers/Microsoft.Management/managementgroups/MGTest/providers/Microsoft.Authorization/policyDefinitions/test",
"parameters":{
"ringValue":{
"value":[
"r0,r1"
]
}
},
"enforcementMode":"DoNotEnforce"
}
}
I have the following JSON coming back from a remote API (I cannot modify the JSON returned)
{
"APITicket": {
"location": "SOMEVALUE",
"ticket": "SOMEVALUE"
}
}
Now using JSON.Net to convert to this to a model I have to create 2 models.
public class TicketModel
{
public string location { get; set; }
public string ticket { get; set; }
}
public class TicketContainer
{
public TicketModel APITicket { get; set; }
}
and do something like..
var myObject = JsonConvert.DeserializeObject<TicketContainer>(this.JSONResponse);
and this works well - my problem arises when I have around 50 calls to make to the API and really dont fancy creating a second 'Container' for each. Is there a way to bind the example above directly to the TicketModel?
You can do it this way:
var json = #"
{
'APITicket': {
'location': 'SOMEVALUE',
'ticket': 'SOMEVALUE'
}
}";
//Parse the JSON:
var jObject = JObject.Parse(json);
//Select the nested property (we expect only one):
var jProperty = (JProperty)jObject.Children().Single();
//Deserialize it's value to a TicketModel instance:
var ticket = jProperty.Value.ToObject<TicketModel>();
use Newtonsoft's JArray to customize ur json before deserialize
public List<APITicket> JsonParser(string json)
{
Newtonsoft.Json.Linq.JArray jArray = Newtonsoft.Json.Linq.JArray.Parse(json);
var list = new List<APITicket>();
foreach(var item in jArray)
{
list.Add(
new APITicket { location = item["APITicket"]["location"],
ticket = item["APITicket"]["ticket"]
}
);
}
return list;
}
Modify the JSON so it looks like this
{
"location": "SOMEVALUE",
"ticket": "SOMEVALUE"
}
and do
List<TicketModel> tickets = JsonConvert.DeserializeObject<List<TicketModel>>(this.JSONResponse);
or even
Dictionary<string, string> tickets = JsonConvert.DeserializeObject<Dictionary<string, string>>(this.JSONResponse);
so you don't need any models.