I need to deserialize the this json returned from grogle maps api:
{
"destination_addresses": [
"Via Medaglie D'Oro, 10, 47121 Forlì FC, Italia",
"Via Torino, 20123 Milano, Italia",
"Via Guglielmo Marconi, 71, 40121 Bologna, Italia",
"Via Irnerio, 40126 Bologna, Italia"
],
"origin_addresses": [
"Via Medaglie D'Oro, 10, 47121 Forlì FC, Italia",
"Via Torino, 20123 Milano, Italia",
"Via Guglielmo Marconi, 71, 40121 Bologna, Italia",
"Via Irnerio, 40126 Bologna, Italia"
],
"rows": [
{
"elements": [
{
"distance": {
"text": "1 m",
"value": 0
},
"duration": {
"text": "1 min",
"value": 0
},
"status": "OK"
},
{
"distance": {
"text": "286 km",
"value": 286281
},
"duration": {
"text": "2 ore 48 min",
"value": 10083
},
"status": "OK"
},
{
"distance": {
"text": "80,1 km",
"value": 80088
},
"duration": {
"text": "1 ora 3 min",
"value": 3789
},
"status": "OK"
},
{
"distance": {
"text": "77,6 km",
"value": 77594
},
"duration": {
"text": "57 min",
"value": 3422
},
"status": "OK"
}
]
},
{
"elements": [
{
"distance": {
"text": "288 km",
"value": 287811
},
"duration": {
"text": "2 ore 48 min",
"value": 10052
},
"status": "OK"
},
{
"distance": {
"text": "1 m",
"value": 0
},
"duration": {
"text": "1 min",
"value": 0
},
"status": "OK"
},
{
"distance": {
"text": "212 km",
"value": 212423
},
"duration": {
"text": "2 ore 8 min",
"value": 7664
},
"status": "OK"
},
{
"distance": {
"text": "218 km",
"value": 218219
},
"duration": {
"text": "2 ore 9 min",
"value": 7740
},
"status": "OK"
}
]
},
{
"elements": [
{
"distance": {
"text": "78,5 km",
"value": 78528
},
"duration": {
"text": "56 min",
"value": 3346
},
"status": "OK"
},
{
"distance": {
"text": "212 km",
"value": 212190
},
"duration": {
"text": "2 ore 5 min",
"value": 7519
},
"status": "OK"
},
{
"distance": {
"text": "1 m",
"value": 0
},
"duration": {
"text": "1 min",
"value": 0
},
"status": "OK"
},
{
"distance": {
"text": "2,0 km",
"value": 1979
},
"duration": {
"text": "5 min",
"value": 316
},
"status": "OK"
}
]
},
{
"elements": [
{
"distance": {
"text": "74,7 km",
"value": 74719
},
"duration": {
"text": "55 min",
"value": 3278
},
"status": "OK"
},
{
"distance": {
"text": "218 km",
"value": 217951
},
"duration": {
"text": "2 ore 9 min",
"value": 7712
},
"status": "OK"
},
{
"distance": {
"text": "3,8 km",
"value": 3782
},
"duration": {
"text": "11 min",
"value": 671
},
"status": "OK"
},
{
"distance": {
"text": "1 m",
"value": 0
},
"duration": {
"text": "1 min",
"value": 0
},
"status": "OK"
}
]
}
],
"status": "OK"
}
I need to create a Distance Matrix so I'm only interested in the "value" field inside "distance".
I've tried this approach:
DataSet data = JsonConvert.DeserializeObject<DataSet>(jsonResponse);
DataTable dataTab = data.Tables["Elements"];
foreach (DataRow elements in dataTab.Rows)
{
Console.WriteLine(elements["distance"]);
//Do something else here
}
But The JSonConvert returns "Additional text found in JSON string after finishing deserializing object."
You should deserialize to classes that match your data. You can generate these classes at http://json2csharp.com/.
// use like
var rootObj = JsonConvert.DeserializeObject<RootObject>(jsonResponse);
foreach (var row in rootObj.rows)
{
foreach (var element in row.elements)
{
Console.WriteLine(element.distance.text);
}
}
// you might want to change the property names to .Net conventions
// use [JsonProperty] to let the serializer know the JSON names where needed
public class Distance
{
public string text { get; set; }
public int value { get; set; }
}
public class Duration
{
public string text { get; set; }
public int value { get; set; }
}
public class Element
{
public Distance distance { get; set; }
public Duration duration { get; set; }
public string status { get; set; }
}
public class Row
{
public List<Element> elements { get; set; }
}
public class RootObject
{
public List<string> destination_addresses { get; set; }
public List<string> origin_addresses { get; set; }
public List<Row> rows { get; set; }
public string status { get; set; }
}
I believe the issue is with the cast to 'DataSet' based on a similar question I found searching Stack Overflow.
Try this as I believe it would work (you may need to use 'rows' instead of 'Elements', but I believe the approach of using a JObject will resolve the primary issue of the 'additional text'.
JObject json = JsonConvert.DeserializeObject<JObject>(jsonResponse);
foreach (Dictionary<string, object> item in data["Elements"])
{
foreach (string val in item.Values) {
Console.WriteLine(val);
}
}
Using dynamic :
dynamic json = JsonConvert.DeserializeObject(jsonResponse);
var rowCount = json.rows.Count;
Func<dynamic, int> getElementCount = r => r.elements.Count;
var maxElements = Enumerable.Max(json.rows, getElementCount);
var matrix = new int?[rowCount, maxElements];
for(int i = 0; i < rowCount; i++)
{
var elements = json.rows[i].elements;
for(int j = 0; j < elements.Count; j++)
{
var element = elements[j];
matrix[i, j] = element.distance.value;
}
}
Related
I am looking for a script to find the value of $6383.12 for Accounts Receivable (A/R) in this code. There are several values I want to be able to find but I can't seem to figure out how to structure my code to find the values I need.
I have spent time looking through and testing various versions of arrays, ILIst<> and other suggestions but I can't seem to get the final result I am looking for. I can find a single value (for example "Savings") but I don't know how to get the $800 value.
The script I am using is:
var root = JToken.Parse(data);
IList<JToken> t = root.SelectTokens("$...ColData[?(#.value == 'Accounts Receivable (A/R)')]").ToList();
foreach (var item in t)
{
Response.Write(item.ToString() + "<br/><br/>");
}
This gives me the Accounts Receivable (A/R) value but not the dollar value associated with it.
Here is the JSON result I am trying to parse through:
{
"Header": {
"ReportName": "BalanceSheet",
"Option": [
{
"Name": "AccountingStandard",
"Value": "GAAP"
},
{
"Name": "NoReportData",
"Value": "false"
}
],
"DateMacro": "this calendar year-to-date",
"ReportBasis": "Accrual",
"StartPeriod": "2016-01-01",
"Currency": "USD",
"EndPeriod": "2016-10-31",
"Time": "2016-10-31T09:42:21-07:00",
"SummarizeColumnsBy": "Total"
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "ASSETS"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Current Assets"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Bank Accounts"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "35",
"value": "Checking"
},
{
"value": "1350.55"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "36",
"value": "Savings"
},
{
"value": "800.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "BankAccounts",
"Summary": {
"ColData": [
{
"value": "Total Bank Accounts"
},
{
"value": "2150.55"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Accounts Receivable"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "84",
"value": "Accounts Receivable (A/R)"
},
{
"value": "6383.12"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "AR",
"Summary": {
"ColData": [
{
"value": "Total Accounts Receivable"
},
{
"value": "6383.12"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Other current assets"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "81",
"value": "Inventory Asset"
},
{
"value": "596.25"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "4",
"value": "Undeposited Funds"
},
{
"value": "2117.52"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "OtherCurrentAssets",
"Summary": {
"ColData": [
{
"value": "Total Other current assets"
},
{
"value": "2713.77"
}
]
}
}
]
},
"type": "Section",
"group": "CurrentAssets",
"Summary": {
"ColData": [
{
"value": "Total Current Assets"
},
{
"value": "11247.44"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Fixed Assets"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"id": "37",
"value": "Truck"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "38",
"value": "Original Cost"
},
{
"value": "13495.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"Summary": {
"ColData": [
{
"value": "Total Truck"
},
{
"value": "13495.00"
}
]
}
}
]
},
"type": "Section",
"group": "FixedAssets",
"Summary": {
"ColData": [
{
"value": "Total Fixed Assets"
},
{
"value": "13495.00"
}
]
}
}
]
},
"type": "Section",
"group": "TotalAssets",
"Summary": {
"ColData": [
{
"value": "TOTAL ASSETS"
},
{
"value": "24742.44"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "LIABILITIES AND EQUITY"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Current Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"Header": {
"ColData": [
{
"value": "Accounts Payable"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "33",
"value": "Accounts Payable (A/P)"
},
{
"value": "1984.17"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "AP",
"Summary": {
"ColData": [
{
"value": "Total Accounts Payable"
},
{
"value": "1984.17"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Credit Cards"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "41",
"value": "Mastercard"
},
{
"value": "157.72"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "CreditCards",
"Summary": {
"ColData": [
{
"value": "Total Credit Cards"
},
{
"value": "157.72"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Other Current Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "89",
"value": "Arizona Dept. of Revenue Payable"
},
{
"value": "4.55"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "90",
"value": "Board of Equalization Payable"
},
{
"value": "401.98"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "43",
"value": "Loan Payable"
},
{
"value": "4000.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "OtherCurrentLiabilities",
"Summary": {
"ColData": [
{
"value": "Total Other Current Liabilities"
},
{
"value": "4406.53"
}
]
}
}
]
},
"type": "Section",
"group": "CurrentLiabilities",
"Summary": {
"ColData": [
{
"value": "Total Current Liabilities"
},
{
"value": "6548.42"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Long-Term Liabilities"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "44",
"value": "Notes Payable"
},
{
"value": "25000.00"
}
],
"type": "Data"
}
]
},
"type": "Section",
"group": "LongTermLiabilities",
"Summary": {
"ColData": [
{
"value": "Total Long-Term Liabilities"
},
{
"value": "25000.00"
}
]
}
}
]
},
"type": "Section",
"group": "Liabilities",
"Summary": {
"ColData": [
{
"value": "Total Liabilities"
},
{
"value": "31548.42"
}
]
}
},
{
"Header": {
"ColData": [
{
"value": "Equity"
},
{
"value": ""
}
]
},
"Rows": {
"Row": [
{
"ColData": [
{
"id": "34",
"value": "Opening Balance Equity"
},
{
"value": "-9337.50"
}
],
"type": "Data"
},
{
"ColData": [
{
"id": "2",
"value": "Retained Earnings"
},
{
"value": "91.25"
}
],
"type": "Data"
},
{
"ColData": [
{
"value": "Net Income"
},
{
"value": "2440.27"
}
],
"type": "Data",
"group": "NetIncome"
}
]
},
"type": "Section",
"group": "Equity",
"Summary": {
"ColData": [
{
"value": "Total Equity"
},
{
"value": "-6805.98"
}
]
}
}
]
},
"type": "Section",
"group": "TotalLiabilitiesAndEquity",
"Summary": {
"ColData": [
{
"value": "TOTAL LIABILITIES AND EQUITY"
},
{
"value": "24742.44"
}
]
}
}
]
},
"Columns": {
"Column": [
{
"ColType": "Account",
"ColTitle": "",
"MetaData": [
{
"Name": "ColKey",
"Value": "account"
}
]
},
{
"ColType": "Money",
"ColTitle": "Total",
"MetaData": [
{
"Name": "ColKey",
"Value": "total"
}
]
}
]
}
}
You can try this,
var json = File.ReadAllText("json1.json");
var jToken = JToken.Parse(json);
var reader = jToken.CreateReader();
while (reader.Read())
{
var value = reader.Value;
if (value != null && value.ToString() == "Accounts Receivable (A/R)")
{
var test = jToken.SelectToken(reader.Path.Replace("[0].value", "[1].value"));
}
}
If it's not doable to write json path which selects proper tokens you could try using Parent property and Children method.
foreach (var item in t)
{
var valueToken = item.Parent.Children().ElementAt(1);
Response.Write(valueToken.ToString() + "<br/><br/>");
}
i have a Json file that contains some information i need elsewhere in my code but a lot of the information is irrelivant.
At the moment ive just put it into a dynamic object so i could check that it was all working:
var data = JsonConvert.DeserializeObject<dynamic>(response.Content);
How do i get the information i need out of the Json file and store them somewhere as variables.
All other tutorials where its stored in a class use the whole Json file and doesnt look like it would be useful in my case.
Here's the Json, i only really need the Stats section at the end of the file for what im doing
{
"data": {
"id": "",
"type": "player",
"children": [
{
"id": "legend_8",
"type": "legend",
"metadata": {
"legend_name": "Pathfinder",
"icon": "https://trackercdn.com/cdn/apex.tracker.gg/legends/pathfinder-tile.png",
"bgimage": "https://trackercdn.com/cdn/apex.tracker.gg/legends/pathfinder-concept-bg-small.jpg",
"is_active": true
},
"stats": [
{
"metadata": {
"key": "Kills",
"name": "Kills",
"categoryKey": "combat",
"categoryName": "Combat",
"isReversed": false
},
"value": 377.0,
"percentile": 21.0,
"displayValue": "377",
"displayRank": ""
},
{
"metadata": {
"key": "Finishers",
"name": "Finishers",
"categoryKey": "game",
"categoryName": "Game",
"isReversed": false
},
"value": 39.0,
"percentile": 0.2,
"rank": 886,
"displayValue": "39",
"displayRank": "886"
}
]
},
{
"id": "legend_5",
"type": "legend",
"metadata": {
"legend_name": "Bloodhound",
"icon": "https://trackercdn.com/cdn/apex.tracker.gg/legends/bloodhound-tile.png",
"bgimage": "https://trackercdn.com/cdn/apex.tracker.gg/legends/bloodhound-concept-bg-small.jpg",
"is_active": false
},
"stats": [
{
"metadata": {
"key": "Kills",
"name": "Kills",
"categoryKey": "combat",
"categoryName": "Combat",
"isReversed": false
},
"value": 235.0,
"percentile": 16.0,
"displayValue": "235",
"displayRank": ""
}
]
}
],
"metadata": {
"statsCategoryOrder": [
"combat",
"game",
"weapons"
],
"platformId": 2,
"platformUserHandle": "",
"accountId": "",
"cacheExpireDate": "11/10/2019 10:48:14 PM",
"level": 49,
"avatarUrl": "https://avatar-cdn.tracker.gg/api/avatar/2/",
"countryCode": null,
"collections": 36,
"activeLegend": 8
},
"stats": [
{
"metadata": {
"key": "Level",
"name": "Level",
"categoryKey": "combat",
"categoryName": "Combat",
"isReversed": false
},
"value": 49.0,
"percentile": 46.0,
"displayValue": "49",
"displayRank": ""
},
{
"metadata": {
"key": "Kills",
"name": "Kills",
"categoryKey": "combat",
"categoryName": "Combat",
"isReversed": false
},
"value": 612.0,
"percentile": 20.0,
"displayValue": "612",
"displayRank": ""
},
{
"metadata": {
"key": "Finishers",
"name": "Finishers",
"categoryKey": "game",
"categoryName": "Game",
"isReversed": false
},
"value": 39.0,
"percentile": 0.5,
"displayValue": "39",
"displayRank": ""
},
{
"metadata": {
"key": "RankScore",
"name": "Rank Score",
"categoryKey": "game",
"categoryName": "Game",
"isReversed": false
},
"value": 64.0,
"percentile": 21.0,
"displayValue": "64",
"displayRank": ""
}
]
}
}
You could create a data structure which has only the relevant properties. For example,
public class StatMetaData
{
public string key { get; set; }
public string name { get; set; }
public string categoryKey { get; set; }
public string categoryName { get; set; }
public bool isReversed { get; set; }
}
public class Stat
{
public StatMetaData metadata { get; set; }
public double value { get; set; }
public double percentile { get; set; }
public string displayValue { get; set; }
public string displayRank { get; set; }
}
public class Data
{
public List<Stat> stats { get; set; }
}
public class RootObject
{
public Data data { get; set; }
}
Now you could deserialize the json as the following to retrieve the stats sections
var result = JsonConvert.DeserializeObject<RootObject>(json).data.stats;
i am having issue to get information from json response, i was trying to get information for label and value only from details object of json response, however i am unable to get those information because while converting json to c# classes from http://json2csharp.com/ gives different classes for 'General', 'AC Adapter' etc.. however in my case it will not work because the response having dynamic classes and therefore i cannot create classes.
{
"data": {
"General": {
"label": "General",
"details": [
{
"label": "Operating System",
"value": "Google Chrome OS"
},
{
"label": "Product Type",
"value": "Chromebook"
}
]
},
"AC Adapter": {
"label": "AC Adapter",
"details": [
{
"label": "Input",
"value": "AC 120/230 V ( 50/60 Hz )"
},
{
"label": "Output",
"value": "45 Watt , 20 V , 2.25 A"
}
]
},
"Audio & Video": {
"label": "Audio & Video",
"details": [
{
"label": "Camera",
"value": "Yes - 720p"
},
{
"label": "Graphics Processor",
"value": "Intel HD Graphics"
},
{
"label": "Resolution",
"value": "1 Megapixel"
},
{
"label": "Sound",
"value": "Stereo speakers , microphone"
}
]
},
"Battery": {
"label": "Battery",
"details": [
{
"label": "Capacity",
"value": "45 Wh"
},
{
"label": "Run Time",
"value": "Up to 10 hours"
},
{
"label": "Technology",
"value": "3-cell lithium ion"
}
]
},
"Communications": {
"label": "Communications",
"details": [
{
"label": "Features",
"value": "Dual stream (2x2)"
},
{
"label": "Wireless",
"value": "Bluetooth 4.0, 802.11a/b/g/n/ac"
},
{
"label": "Wireless Controller",
"value": "Intel Dual Band Wireless-AC 7260 - M.2 Card"
}
]
},
"Connections & Expansion": {
"label": "Connections & Expansion",
"details": [
{
"label": "Interfaces",
"value": "USB 3.0 � 2 x USB 2.0 � HDMI � Headphone/microphone combo jack"
},
{
"label": "Memory Card Reader",
"value": "Yes ( microSD )"
}
]
},
"Dimensions & Weight": {
"label": "Dimensions & Weight",
"details": [
{
"label": "Dimensions (WxDxH)",
"value": "11.8 in x 8.5 in x 0.9 in"
},
{
"label": "Weight",
"value": "2.84 lbs"
}
]
},
"Display": {
"label": "Display",
"details": [
{
"label": "Features",
"value": "Anti-glare"
},
{
"label": "Image Aspect Ratio",
"value": "16:9"
},
{
"label": "LCD Backlight Technology",
"value": "LED backlight"
},
{
"label": "Resolution",
"value": "1366 x 768 ( HD )"
},
{
"label": "Type",
"value": "11.6\""
},
{
"label": "Widescreen",
"value": "Yes"
}
]
},
"Input": {
"label": "Input",
"details": [
{
"label": "Features",
"value": "Spill-resistant"
},
{
"label": "Type",
"value": "Keyboard, touchpad"
}
]
},
"Manufacturer Warranty": {
"label": "Manufacturer Warranty",
"details": [
{
"label": "Service & Support",
"value": "Limited warranty - 1 year - carry-in"
}
]
},
"Memory": {
"label": "Memory",
"details": [
{
"label": "Max RAM Supported",
"value": "8 GB"
},
{
"label": "RAM",
"value": "4 GB ( provided memory is soldered )"
},
{
"label": "Speed",
"value": "1600 MHz"
},
{
"label": "Technology",
"value": "DDR3L SDRAM"
}
]
},
"Miscellaneous": {
"label": "Miscellaneous",
"details": [
{
"label": "Features",
"value": "Security lock slot (cable lock sold separately), administrator password, hard drive password, power-on password"
},
{
"label": "Included Accessories",
"value": "Power adapter"
},
{
"label": "Localization",
"value": "English"
},
{
"label": "Manufacturer Selling Program",
"value": "TopSeller"
}
]
},
"Processor / Chipset": {
"label": "Processor / Chipset",
"details": [
{
"label": "64-bit Computing",
"value": "Yes"
},
{
"label": "CPU",
"value": "Intel Celeron N3050 / 1.6 GHz"
},
{
"label": "Cache",
"value": "2 MB"
},
{
"label": "Features",
"value": "Integrated memory controller"
},
{
"label": "Max Turbo Speed",
"value": "2.16 GHz"
},
{
"label": "Number of Cores",
"value": "Dual-Core"
}
]
},
"Storage": {
"label": "Storage",
"details": [
{
"label": "Main Storage",
"value": "16 GB SSD - ( eMMC )"
}
]
}
}
}
http://json2csharp.com/ gives different classes for 'General', 'AC Adapter' etc
This works better: https://quicktype.io/?l=cs&r=json2csharp
However, I think your data is actually a dictionary here. So the final contract:
public class Response
{
[JsonProperty("data")]
public Data Data { get; set; }
}
public class Data : Dictionary<string, Item> { }
public class Item
{
[JsonProperty("details")]
public Detail[] Details { get; set; }
[JsonProperty("label")]
public string Label { get; set; }
}
public class Detail
{
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("value")]
public string Value { get; set; }
}
And if you use Newtonsoft, deserialization:
var response = JsonConvert.DeserializeObject<Response>(jsonString);
if you just want to convert a json string to C# dynamic object, look at this SO question. The code is in the final version.
I have a WebAPI method that returns Json in a flexible structure that depends on the request.
Part of the problem is that there could be any number of columns, and they could be any type. The 2 given below (Code and Count) are just one example.
This structure is based on the underlying classes but there could be any number of columns in the output. So, rather than the usual properties you might expect, these are objects in a collection with Name and Value properties.
The downside of this flexible approach is that it gives a non-standard format.
Is there a way to transform this into a more normalised shape? Are there maybe some attributes I can add to the class properties to change the way they are serialised?
For example, where there are 2 columns - Code (string) and Count (numeric):
Current Json:
{
"Rows": [
{
"Columns": [
{
"Value": "1",
"Name": "Code"
},
{
"Value": 13,
"Name": "Count"
}
]
},
{
"Columns": [
{
"Value": "2",
"Name": "Code"
},
{
"Value": 12,
"Name": "Count"
}
]
},
{
"Columns": [
{
"Value": "9",
"Name": "Code"
},
{
"Value": 1,
"Name": "Count"
}
]
},
{
"Columns": [
{
"Value": "5",
"Name": "Code"
},
{
"Value": 2,
"Name": "Count"
}
]
}
]
}
Ideally I'd like to transform it to this:
{
"Rows": [
{
"Code": "1",
"Count": 13
},
{
"Code": "2",
"Count": 12
},
{
"Code": "9",
"Count": 1
},
{
"Code": "5",
"Count": 2
}
]
}
The controller method (C#)
public ReportResponse Get(ReportRequest request)
{
var result = ReportLogic.GetReport(request);
return result;
}
The output classes
public class ReportResponse
{
public List<ReportRow> Rows { get; set; }
public ReportResponse()
{
Rows = new List<ReportRow>();
}
}
public class ReportRow
{
public List<ReportColumn> Columns { get; set; }
public ReportRow()
{
Columns = new List<ReportColumn>();
}
}
public class ReportColumn<T> : ReportColumn
{
public T Value { get; set; }
public ReportColumn(string name)
{
Name = name;
}
}
public abstract class ReportColumn
{
public string Name { get; internal set; }
}
I think the easiest way would be to map your class to a dictionary before serializing. Something like:
var dictionaries = List<Dictionary<string, object>();
foreach(var column in rows.Columns)
{
dictionaries.Add(new Dictionary<string, object>{{column.Name, column.Value}});
}
Then serialize the dictionaries variable should do the trick.
If you're using the output in JavaScript, you could translate as follows:
var
data = {
"Rows": [
{
"Columns": [
{
"Value": "1",
"Name": "Code"
},
{
"Value": 13,
"Name": "Count"
}
]
},
{
"Columns": [
{
"Value": "2",
"Name": "Code"
},
{
"Value": 12,
"Name": "Count"
}
]
},
{
"Columns": [
{
"Value": "9",
"Name": "Code"
},
{
"Value": 1,
"Name": "Count"
}
]
},
{
"Columns": [
{
"Value": "5",
"Name": "Code"
},
{
"Value": 2,
"Name": "Count"
}
]
}
]
},
output = [
];
data.Rows.forEach(function (row)
{
var
newRow = {};
row.Columns.forEach(function (column)
{
newRow[column.Name] = column.Value;
});
output.push(newRow);
})
console.log(JSON.stringify(output));
Lets see, the json can be dynamic and can probably have number of nested arrays within any property.
Example:
{
"items": [
{
"id": "0001",
"name": "Cake",
"batters": {
"batter": [
{
"id": "1001",
"type": "Regular"
},
{
"id": "1002",
"type": "Chocolate"
},
{
"dry": [
{
"id": "1003",
"type": "Devil's Food"
}
]
}
],
"other": [
{
"id": "1004",
"type": "Home Food"
}
]
},
"topping": [
{
"id": "5002",
"type": "Glazed"
},
{
"id": "5005",
"type": "Sugar"
}
]
},
{
"id": "0002",
"name": "Sweets"
}
]
}
A simple list should return elements as:
[
{
"id": "1001",
"type": "Regular"
},
{
"id": "1002",
"type": "Chocolate"
},
{
"id": "1003",
"type": "Devil's Food"
},
{
"id": "1004",
"type": "Home Food"
},
{
"id": "5002",
"type": "Glazed"
},
{
"id": "5005",
"type": "Sugar"
},
{
"id": "0002",
"name": "Sweets"
}
]
Please note:
Json can by anything, no property can be used for extraction , just knowing that what needed is stuff inside an JArray.
What i have tried so far but its just a start:
public static bool ParseJsonArray(JToken token, List<string> extracts, string parentLocation = "")
{
if (token.HasValues)
{
foreach (JToken child in token.Children())
{
if (token.Type == JTokenType.Array)
{
parentLocation += ((JProperty)token).Name;
extracts.Add(token.ToString());
}
ParseJsonArray(child, extracts, parentLocation);
}
return true;
}
else
{
return false;
}
}
token here is the parsed dynamic json.
It appears as though you want to recursively find all JArray entries that do not themselves contain nested arrays. Let's call these "leaf" array entries. I say that because you don't include the following non-leaf entry in your results:
{
"id": "0001",
"name": "Cake"
}
That being said, you can find leaf array entries with the following extension method:
public static class JsonExtensions
{
public static IEnumerable<JToken> LeafArrayEntries(this JContainer container)
{
var nonLeafEntries = new HashSet<JToken>(container.DescendantsAndSelf()
.OfType<JArray>()
.SelectMany(a => a.Ancestors().Where(p => p.Type != JTokenType.Property)));
return container.DescendantsAndSelf().Where(c => c.Parent is JArray && !nonLeafEntries.Contains(c));
}
}
Then put the returned items in an array of their own with:
var leafItemArray = new JArray(rootJContainer.LeafArrayEntries());