I'm currently working on JSON string extraction using C#. My JSON string consist of an array with repetitive keys. Not sure if I'm describing it right since I'm new to this.
This is my JSON string
{"Index":
{ "LibraryName":"JGKing"
, "FormName":"AccountsPayable"
, "User":null
, "FilingPriority":null
, "FileDescription":null
, "Fields":
{"Field":
[
{ "Name":"invItemID"
, "Value":"6276"
}
,{ "Name":"invEntityCode"
, "Value":"16"
}
,{ "Name":"invVendorCode"
, "Value":"MIRUB01"
}
,{ "Name":"invNumber"
, "Value":"PWD5"
}
,{ "Name":"invDate"
, "Value":"2017-08-21"
}
,{ "Name":"invStatus"
, "Value":""
}
,{ "Name":"invCurrencyCode"
, "Value":"AU"
}
,{ "Name":"invCurrencyRate"
, "Value":"1"
}
,{ "Name":"invTax"
, "Value":"454.3"
}
, {"Name":"invTotal"
, "Value":"4997.27"
}
, {"Name":"invReceivedDate"
, "Value":"2017-09-06"
}
,{ "Name":"InvoiceLine1"
, "Value":"{\r\n \"invLineNumber\": \"1\",\r\n \"invPONumber\": \"\",\r\n \"invPOLineNo\": \"1\",\r\n \"invPOJobID\": \"\",\r\n \"invCostCode\": \"\",\r\n \"invCategory\": \"\",\r\n \"invGLCode\": \"61-01-49-6862.517\",\r\n \"invDescription\": \"\",\r\n \"invEntryType\": \"\",\r\n \"invAmount\": \"4542.97\",\r\n \"invTaxAmount\": \"454.3\",\r\n \"invTaxCode\": \"GST\",\r\n \"invAmountIncTax\": \"4997.27\"\r\n}"}]}}}
I need to extract the value of invItemID key which is inside the array.
I tried to serialize my json string from a class but it returns null in the List<>
Here's my code
public void CFExport(string jsonFile)
{
string ItemIDField;
string ItemIDValue;
using (StreamReader r = new StreamReader(jsonFile))
{
JsonSerializer s = new JsonSerializer();
var Idx = (JSONMain)s.Deserialize(r, typeof(JSONMain));
var flds = (Fields)s.Deserialize(r, typeof(Fields));
if (flds != null)
{
foreach (var _field in flds.Field)
{
ItemIDField = _field.Name;
ItemIDValue = _field.Value;
}
}
}
}
public class JSONMain
{
public Index Index { get; set; }
}
public class Index
{
public string LibraryName { get; set; }
public string FormName { get; set; }
public string User { get; set; }
public string FilingPriority { get; set; }
public string FileDescription { get; set; }
}
public class Fields
{
public List<Field> Field { get; set; }
}
public class Field
{
public string Name { get; set; }
public string Value { get; set; }
}
I hope you can help me.
Thanks in advance
Try to reflect the JSON file with your classes like this:
public class Index
{
public string LibraryName { get; set; }
public string FormName { get; set; }
public string User { get; set; }
public string FilingPriority { get; set; }
public string FileDescription { get; set; }
public Fields Fields { get; set; } //this line makes the difference
}
If you deserialize now, the fields should be populated automatically. I also advice you to use JsonConvert.Deserialze<>() since it is a bit easier (see documentation) and you are new to this topic.
Getting the value of invItemID could look like this:
public void CFExport(string jsonFile)
{
string ItemIDField = "invItemID";
string ItemIDValue;
using (StreamReader r = new StreamReader(jsonFile))
{
var Idx = JsonConvert.DeserializeObject<JSONMain>(r);
foreach(var field in Idx.Index.Fields.Field)
{
if(field.Name == ItemIDField)
{
ItemIDValue = field.Value;
}
}
}
}
Whoohoo. My first answer on Stackoverflow! I hope this helps you.
I need to extract the value of invItemID key which is inside the array.
You can retrieve value for your specified key invItemID from Field array by using JObject.
So you have no more need to manage classes for your json.
Here i created a console app for your demonstration purpose.
class Program
{
static void Main(string[] args)
{
//Get your json from file
string json = File.ReadAllText(#"Your path to json file");
//Parse your json
JObject jObject = JObject.Parse(json);
//Get your "Field" array to List of NameValuePair
var fieldArray = jObject["Index"]["Fields"]["Field"].ToObject<List<NameValuePair>>();
//Retrieve Value for key "invItemID"
string value = fieldArray.Where(x => x.Name == "invItemID").Select(x => x.Value).FirstOrDefault();
//Print this value on console
Console.WriteLine("Value: " + value);
Console.ReadLine();
}
}
class NameValuePair
{
public string Name { get; set; }
public string Value { get; set; }
}
Output:
Related
I have a C# code that defines a constant JSON string and a corresponding POCO class. however i get an exception:
The JSON value could not be converted Path: $ | LineNumber: 0 | BytePositionInLine: 1.
Code
try
{
var filters = JsonSerializer.Deserialize <CmsContactsFilter>(FilterJson);
}
catch(Exception ex)
{
}
JSON
#"[{""cms"":""us-its"",""group"":[""ciso"",""cloudAdminsDistributionList"",""cloudAdmins""]},""cms"":""us-csdaudit"",""abc"":[""biso"",""costManagement""]},]";
POCO Class
public class CmsContactsFilter
{
public string Cms { get; set; }
public List<string> Group { get; set; }
}
Your json is not valid, here is the valid version of your json:
[
{
"cms": "us-its",
"group": [
"ciso",
"cloudAdminsDistributionList",
"cloudAdmins"
]
},
{
"cms": "us-csdaudit",
"group": [
"biso",
"costManagement"
]
}
]
Your code should be looks like this:
using System.Text.Json;
string filterJson = System.IO.File.ReadAllText("data.json");
var filters = JsonSerializer.Deserialize<List<CmsContactsFilter>>(filterJson);
foreach (var item in filters)
{
Console.WriteLine(item.cms+":");
foreach (var y in item.group)
{
Console.WriteLine("----"+y);
}
}
public class CmsContactsFilter
{
public string cms { get; set; }
public List<string> group { get; set; }
}
the name of the properties of the the CmsContactsFilter should be same with your json attributes names. if they are in lower-case format, your attribute name in the C# should be in the lower-case too.
your json is not valid, you need to add { to the second array item, and use an object collection for deserialization
var FilterJson = #"[{""cms"":""us-its"",""group"":[""ciso"",""cloudAdminsDistributionList"",""cloudAdmins""]},{""cms"":""us-csdaudit"",""abc"":[""biso"",""costManagement""]}]";
var filters = System.Text.Json.JsonSerializer.Deserialize <List<CmsContactsFilter>>(FilterJson);
and fix class
public class CmsContactsFilter
{
public string cms { get; set; }
public List<string> group { get; set; }
public List<string> abc { get; set; }
}
but as I understand your array has much more objects then 2. So you can try this code for the big json with different array names (if you had used Newtonsoft.Json this code could be significanly simplier)
JsonArray array = JsonNode.Parse(FilterJson).AsArray();
List<CmsContactsFilter> filters = new List<CmsContactsFilter>();
foreach (JsonObject item in array)
{
var obj = new CmsContactsFilter();
foreach (var prom in item.AsObject())
{
var name = prom.Key;
if (name == "cms")
{
obj.cms = prom.Value.ToString();
continue;
}
obj.groupName = name;
obj.group = System.Text.Json.JsonSerializer.Deserialize<List<string>>(prom.Value.ToString());
}
filters.Add(obj);
}
}
class
public class CmsContactsFilter
{
public string cms { get; set; }
public string groupName { get; set; }
public List<string> group { get; set; }
}
I know its an array, but I am completely new to JSON and need help comprehending how this is structured, here is my attempt at extracting data:
String JSonString = readURL("//my URL is here");
JSONArray s = JSONArray.fromObject(JSonString);
JSONObject Data =(JSONObject)(s.getJSONObject(0));
System.out.println(Data.get("RecycleSiteUrl"));
I want to extract RecycleSiteUrl based on SiteId
My JSON data that I have goes like this :
[
{
"SiteId": 1,
"RecycleLogoUrl": "https://static-contrado.s3-eu-west- 1.amazonaws.com/cms/recyclecarelabel/d867c499-abc0-4ade-bc1a-f5011032c3e0132901511939451201.jpeg",
"RecycleSiteUrl": "bagsoflove.co.uk/recycling",
"Culture": "en-GB"
},
{
"SiteId": 10,
"RecycleLogoUrl": "https://static-contrado.s3-eu-west-1.amazonaws.com/cms/recyclecarelabel/95d28588-33e3-420c-8b24-4a8095c0f6ac132901511364264751.jpeg",
"RecycleSiteUrl": "contrado.co.uk/recycling",
"Culture": "en-GB"
}]
I dont really have a strong grasp of this stuff so all the help is appreciated.
you can try this, it doesn't need to create any classes
var jsonParsed=JArray.Parse(json);
var siteId=10;
var recycleSiteUrl = GetRecycleSiteUrl(jsonParsed,siteId); // contrado.co.uk/recycling
public string GetRecycleSiteUrl(JArray jArray, int siteId)
{
return jArray.Where(x=> (string) x["SiteId"] == siteId.ToString()).First()["RecycleSiteUrl"].ToString();
}
or using json path
string recycleSiteUrl= (string)jsonParsed
.SelectToken("$[?(#.SiteId=="+siteId.ToString()+")].RecycleSiteUrl");
using Newtonsoft.Json;
using System.Linq;
public void Method()
{
var yourSearchParameter = 10;
string jsonStr = readURL("//my URL is here");
var obj = JsonConvert.DeserializeObject<List<RecycleSite>>(jsonStr);
var siteUrl = obj.SingleOrDefault(q => q.SiteId == yourSearchParameter).RecycleSiteUrl;
/* Do something with the siteUrl */
}
public class RecycleSite
{
public int SiteId { get; set; }
public string RecycleLogoUrl { get; set; }
public string RecycleSiteUrl { get; set; }
public string Culture{ get; set; }
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
public Class Site
{
public string GetRecycleSiteUrl(int siteId, string jsonArray)
{
var siteInfos = JsonConvert.DeserializeObject<List<SiteInfo>>(jsonArray);
string recycleSiteUrl = siteInfos.FirstOrDefault(info => info.SiteId == siteId).RecycleSiteUrl;
return recycleSiteUrl;
}
}
public class SiteInfo
{
public int SiteId { get; set; }
public string RecycleLogoUrl { get; set; }
public string RecycleSiteUrl { get; set; }
public string Culture { get; set; }
}
You can create Site object and access GetRecycleSiteUrl method by passing respective parameter values.
I am attempting to use the Newtonsoft JSON library to parse a JSON string dynamically using C#. In the JSON is a named array. I would like to remove the square brackets from this array and then write out the modified JSON.
The JSON now looks like the following. I would like to remove the square bracket from the ProductDescription array.
{
"Product": "123",
"to_Description": [
{
"ProductDescription": "Product 1"
}
]
}
Desired result
{
"Product": "123",
"to_Description":
{
"ProductDescription": "Product 1"
}
}
I believe I can use the code below to parse the JSON. I just need some help with making the modification.
JObject o1 = JObject.Parse(File.ReadAllText(#"output.json"));
The to_Description property starts off as List<Dictionary<string,string>> and you want to take the first element from the List.
So, given 2 classes
public class Source
{
public string Product {get;set;}
public List<Dictionary<string,string>> To_Description{get;set;}
}
public class Destination
{
public string Product {get;set;}
public Dictionary<string,string> To_Description{get;set;}
}
You could do it like this:
var src = JsonConvert.DeserializeObject<Source>(jsonString);
var dest = new Destination
{
Product = src.Product,
To_Description = src.To_Description[0]
};
var newJson = JsonConvert.SerializeObject(dest);
Note: You might want to check there really is just 1 item in the list!
Live example: https://dotnetfiddle.net/vxqumd
You do not need to create classes for this task. You can modify your object like this:
// Load the JSON from a file into a JObject
JObject o1 = JObject.Parse(File.ReadAllText(#"output.json"));
// Get the desired property whose value is to be replaced
var prop = o1.Property("to_Description");
// Replace the property value with the first child JObject of the existing value
prop.Value = prop.Value.Children<JObject>().FirstOrDefault();
// write the changed JSON back to the original file
File.WriteAllText(#"output.json", o1.ToString());
Fiddle: https://dotnetfiddle.net/M83zv3
I have used json2csharp to convert the actual and desired output to classes and manipulated the input json.. this will help in the maintenance in future
First defined the model
public class ToDescription
{
public string ProductDescription { get; set; }
}
public class ActualObject
{
public string Product { get; set; }
public List<ToDescription> to_Description { get; set; }
}
public class ChangedObject
{
public string Product { get; set; }
public ToDescription to_Description { get; set; }
}
Inject the logic
static void Main(string[] args)
{
string json = "{\"Product\": \"123\", \"to_Description\": [ { \"ProductDescription\": \"Product 1\" } ]} ";
ActualObject actualObject = JsonConvert.DeserializeObject<ActualObject>(json);
ChangedObject changedObject = new ChangedObject();
changedObject.Product = actualObject.Product;
changedObject.to_Description = actualObject.to_Description[0];
string formattedjson = JsonConvert.SerializeObject(changedObject);
Console.WriteLine(formattedjson);
}
Why not:
public class EntityDescription
{
public string ProductDescription { get; set; }
}
public class Entity
{
public string Product { get; set; }
}
public class Source : Entity
{
[JsonProperty("to_Description")]
public EntityDescription[] Description { get; set; }
}
public class Target : Entity
{
[JsonProperty("to_Description")]
public EntityDescription Description { get; set; }
}
var raw = File.ReadAllText(#"output.json");
var source = JsonConvert.DeserializeObject<Source>(raw);
var target = new Target { Product = source.Product, Description = source.Description.FirstOrDefault() };
var rawResult = JsonConvert.SerializeObject(target);
Update For dynamic JSON
var jObject = JObject.Parse(File.ReadAllText(#"output.json"));
var newjObject = new JObject();
foreach(var jToken in jObject) {
if(jToken.Value is JArray) {
List<JToken> l = jToken.Value.ToObject<List<JToken>>();
if(l != null && l.Count > 0) {
newjObject.Add(jToken.Key, l.First());
}
} else {
newjObject.Add(jToken.Key, jToken.Value);
}
}
var newTxt = newjObject.ToString();
I am querying an API and returning data to a C# Console App. I am able to query my data successfully except for the array element of such. This is how the data is returned in JSON format
[
{
"UserType": "Admin",
"UserPerms:" [
{
"level1:" "Yes",
"level2:" "No",
"level3:" "No",
"level4:" "Yes",
"level5:" [
{
"door1:" "Yes",
"door2:" "No",
"door3:" "No",
"doory4:" "Yes"
}
]
}
]
}
]
And this is the C# syntax that I am trying to use to return the data - what is the proper C# syntax to return each door value for level5?
public class RootObject
{
public string UserType { get; set; }
public List<UserPerms> UserPerms { get; set; }
}
public class UserPerms
{
public string level1 { get; set; }
public string level2 { get; set; }
public string level3 { get; set; }
public string level4 { get; set; }
public string[] level5 { get; set; }
}
public class Main[]
{
var response = syncClient.DownloadString(url);
var o = JsonConvert.DeserializeObject<RootObject[]>(response);
foreach (RootObject ro in o)
if (ro.UserPerms != null)
foreach (UserPerms info in ro.UserPerms)
{
Console.WriteLine("Access to Level1" + info.level1);
Console.WriteLine("Access to Level2" + info.level2);
Console.WriteLine("Access to Level3" + info.level3);
Console.WriteLine("Access to Level4" + info.level4);
Console.WriteLine("Access to Level5" + info.level5);
}
}
The JSON for level5 displays a "list" of "key-value pair", so....
public List<Dictionary<string, string>> level5 { get; set; }
I'll try to come up with a fiddle soon.
I have below scenario:
This is my class structure :
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public System.Collections.ObjectModel.Collection<Likes> Likes { get; set; }
}
public class Likes
{
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
}
When I serialize object of User class then it will generate the below json string :
{"FirstName":"Naresh",
"LastName":"Parmar",
"Likes": [{"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"}]
}
I want to generate above json string like below:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
I want the nested properties as primary one.
Any help would be appreciated.
Thanks in advance..
EDIT:
{"FirstName":"Naresh",
"LastName":"Parmar",
"Sport":"Cricket,Chess,Football",
"Music":"Classic",
"Food":"Gujarati",
"Place":"India"
}
It's really bad practice, since the code i'll post bellow doesn't have great maintainability, however if that's what you looking for, you can use this. Another class that have the format that you'd like, and have a method that adds a list of likes to the format you've required. That the class you should serialize to JSON:
class NestedUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Sport { get; set; }
public string Music { get; set; }
public string Food { get; set; }
public string Place { get; set; }
public void AddLikes(System.Collections.ObjectModel.Collection<Likes> likes)
{
foreach (Likes like in likes)
{
Sport += like.Sport + ",";
Music += like.Music + ",";
Food += like.Food + ",";
Place += like.Place + ",";
}
if (Sport != string.Empty)
{
Sport = Sport.Substring(0, Sport.Length - 1);
}
if (Music != string.Empty)
{
Music = Music.Substring(0, Music.Length - 1);
}
if (Food != string.Empty)
{
Food = Food.Substring(0, Food.Length - 1);
}
if (Place != string.Empty)
{
Place = Place.Substring(0, Place.Length - 1);
}
}
}
Since it's not only limited to Likes objects I'd suggest using dynamic objects. So the User class I propose is as follows:
public class User
{
public string FirstName { get; set; }
public string LastName { get; set; }
public dynamic Details { get; set; }
public User()
{
Details = new ExpandoObject();
}
public void AddSingleDetail(string key, string value)
{
var dict = this.Details as IDictionary<string, Object>;
if (dict.ContainsKey(key))
{
dict[key] += "," + value;
}
else
{
dict[key] = value;
}
}
public void AddDetails(object detailsObject)
{
var type = detailsObject.GetType();
foreach (var prop in type.GetProperties())
{
AddSingleDetail(prop.Name, prop.GetValue(detailsObject).ToString());
}
}
}
You can use it for adding single proerpties or adding an object as a whole. I used reflection to get all the property name and values and add them to the user details.
Sample usage:
static void Main(string[] args)
{
var user1 = new User() { FirstName = "Homer", LastName = "Simpson" };
user1.AddSingleDetail("Sport", "Bowling");
user1.AddSingleDetail("Sport", "Sleeping");
user1.AddSingleDetail("Food", "Donut");
user1.AddSingleDetail("Music", "Rock");
string flattenedHomer1 = ConvertUserToFlattenedJson(user1);
var user2 = new User() { FirstName = "Homer", LastName = "Simpson" };
var likes1 = new Likes() { Food = "Donut", Music = "Rock", Place = "Springfield", Sport = "Bowling" };
var likes2 = new Likes() { Food = "Steaks", Music = "Metal", Place = "Evergreen Terrace", Sport = "Sleeping" };
var proStuff = new ProfessionalStuff() { Title = "Boss" };
user2.AddDetails(likes1);
user2.AddDetails(likes2);
user2.AddDetails(proStuff);
string flattenedHomer2 = ConvertUserToFlattenedJson(user2);
}
And the method performing the JSON conversion is:
public static string ConvertUserToFlattenedJson(User u)
{
dynamic flatUser = new ExpandoObject();
flatUser.FirstName = u.FirstName;
flatUser.LastName = u.LastName;
var dict = u.Details as IDictionary<string, Object>;
foreach (var like in dict)
{
((IDictionary<string, Object>)flatUser)[like.Key] = like.Value;
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(flatUser);
return json;
}
In my sample above user2 is converted to the following JSON string which I believe is what you are looking for:
{
"FirstName": "Homer",
"LastName": "Simpson",
"Sport": "Bowling,Sleeping",
"Music": "Rock,Metal",
"Food": "Donut,Steaks",
"Place": "Springfield,Evergreen Terrace",
"Title": "Boss"
}
While concatenating strings you can check for null or duplicate values. I didn't handle that part.
For the sake of completeness, here's the ProfessionalStuff class I made up:
public class ProfessionalStuff
{
public string Title { get; set; }
}
Hope this helps.