JSON Parser Element not found - c#

This is my JSON
{
"State of Origin 2014":{
"1471137":{
"EventID":1471137,
"ParentEventID":1471074,
"MainEvent":"State Of Origin Series 2014",
"Competitors":{
"ActiveCompetitors":3,
"Competitors":[
{
"Team":"New South Wales (2 - 1)",
"Win":"2.15",
},
{
"Team":"New South Wales (3 - 0)",
"Win":"3.05",
},
{
"Team":"Queensland (2 - 1)",
"Win":"3.30",
}
],
"TotalCompetitors":3,
"HasWinOdds":true
},
"EventStatus":"Open",
"IsSuspended":false,
"AllowBets":true
},
"3269132":{
"EventID":3269132,
"ParentEventID":0,
"MainEvent":"New South Wales v Queensland",
"Competitors":{
"Margin1Low":1,
"Competitors":[
{
"Name":"New South Wales",
"Win":"1.60",
},
{
"Name":"Queensland",
"Win":"2.35",
}
],
"HasWinOdds":true,
"TotalOddsColumns":2,
"MarketCount":1,
"PerformVideo":false
},
"EventStatus":"Open",
"IsSuspended":false,
"AllowBets":true
}
}
}
I am using JSON.Net and everything is working fine but in some of my data some element fields are missing for example i am getting Team element inside Competitors as
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"]
But in some data Team element is missing and i want to grap Name Element so i am getting Object reference not set to an instance of an object. Error.
This is my code
var query =
from JProperty ev in obj.AsJEnumerable()
from JProperty evid in ev.Value.AsJEnumerable()
let value = (JObject)evid.Value
select new Person
{
EventID = (string)value["EventID"],
Description = (string)value["MainEvent"],
OutcomeDateTime = (string)value["OutcomeDateTime"],
EventStatus = (string)value["EventStatus"],
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"]
};
foreach (var b in query)
{
string description = b.Description;
string OutcomeDateTime = b.OutcomeDateTime;
IEnumerable<string> _team = b.Teams;
foreach (var teams in _team)
{
string team = teams.ToString();
}
Console.WriteLine(description);
Console.WriteLine(OutcomeDateTime);
}
How can i get Name element value if Team element does not exist ?

You can deserialize your json to concrete classes
var obj = JsonConvert.DeserializeObject < Dictionary<string, Dictionary<string,RootObject>>>(json);
public class Competitor
{
public string Team { get; set; }
public string Win { get; set; }
}
public class CompetitorsClass
{
public int ActiveCompetitors { get; set; }
public List<Competitor> Competitors { get; set; }
public int TotalCompetitors { get; set; }
public bool HasWinOdds { get; set; }
}
public class RootObject
{
public int EventID { get; set; }
public int ParentEventID { get; set; }
public string MainEvent { get; set; }
public CompetitorsClass Competitors { get; set; }
public string EventStatus { get; set; }
public bool IsSuspended { get; set; }
public bool AllowBets { get; set; }
}
BTW: What is OutcomeDateTime? there is no such field in your json.

The following will work. Use the null-coalescing operator to grab "Name" if "Team" is null. http://msdn.microsoft.com/en-us/library/ms173224.aspx
Teams = from JObject comps in value["Competitors"]["Competitors"]
select (string)comps["Team"] ?? (string)comps["Name"]

Related

JSON deserialize throws exception

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; }
}

Represent string data to tree

I have the following data. This is a list of programs on my system.
[
{
"ID": 135,
"CODIGO": 139,
"NOME": "CADASTRO DE ANOS ATIVOS",
"VISAO": "VANOSATIVOSCONTABIL",
"CAMINHO": "Cadastros/Contabilidade/frm_AnosAtivosContabil.aspx, 139, ((VariaveisSistema)Session[VariaveisSistema]).UsuarioId.ToString().Trim(), frm_Visoes.aspx, , Nao"
},
{
"ID": 59,
"CODIGO": 35,
"NOME": "CADASTRO DE CENTRO DE CUSTO",
"VISAO": "VCENTROCUSTO",
"CAMINHO": "Cadastros/Contabilidade/frm_CadastroCentroCusto.aspx, 035, ((VariaveisSistema)Session[VariaveisSistema]).UsuarioId.ToString().Trim(), frm_Visoes.aspx, , Nao"
},
]
So, you can see that the program has a path like Cadastros/Contabilidade.
I need to conver the Cadastros/Contabilidade in a menu tree colapsable.
So the json data should look like this:
Cadastros
|
| Contabilidade
- frm_AnosAtivosContabil.aspx
- frm_CadastroCentroCusto.aspx
- frm_CadastroCFOP.aspx
- ...
| Globais
- frm_AlteraFormacaoArvore.aspx
- frm_AssociacaoCalendario.aspx
- frm_AssociacaoItemTransferencia.aspx
- ...
I am using C#. I managed to separate the programs along the way (group them). But I have not managed to separate them into menus.
The node structure is:
public class Node
{
public IList<Programa> Programs { get; set; }
public string Name { get; set; }
public string FullName { get; set; }
public Node Parent { get; set; }
public IList<Node> Childrens { get; set; }
}
Program structure:
public class Programa
{
public int Id { get; set; }
public int Codigo { get; set; }
public string Nome { get; set; }
public string Visao { get; set; }
public IList<UsuarioPrograma> UsuariosPrograma { get; set; }
public string Caminho { get; set; }
}
I can create the root node. But i dont kno how to proceed.
private void CreateNode(Programa programa)
{
var paths = programa.Caminho.Split('/');
// Verifica se já é o pai
if (paths.Length == 1)
{
// Verifica se o nó já existe
var node = Menu.FirstOrDefault(x => x.Name == paths[0]);
if (node == null)
{
node = new Node();
node.Name = paths[0];
node.Programs = new List<Programa> { programa };
Menu.Add(node);
}
else Menu.First(x => x.Name == paths[0]).Programs.Add(programa);
}
}
#augusto-henrique bit tricky but managed to bring the json object however you expecting to serialize, have a look this code and see whether this works for your requirements,
first I created a class to serialize the JSON you have
public class Page
{
public int ID { get; set; }
public int CODIGO { get; set; }
public string NOME { get; set; }
public string VISAO { get; set; }
public string CAMINHO { get; set; }
}
Then I am grouping the values and adding into dictionary objects as nested collection
var json1 = JsonConvert.DeserializeObject<List<Page>>
(File.ReadAllText(#"c:\temp\test1.json"));
var root1 = json1.Select(x => x.CAMINHO)
.Select(x => x.Split(",")[0])
.Select(x => x.Split("/"))
.Select(x => new
{
level1 = x.First(),
level2 = x.Skip(1).First(),
level3 = x.Skip(2).First()
})
.GroupBy(x => new { x.level1, x.level2, x.level3 }, (key, grp) => new
{
Level1 = key.level1,
Level2 = key.level2,
Level3 = key.level3,
groups = grp
});
var jsonObject = new Dictionary<string, object>();
foreach (var level1 in root1)
{
if (!jsonObject.ContainsKey(level1.Level1))
{
jsonObject.Add(level1.Level1, new Dictionary<string, object[]>());
}
if (!((Dictionary<string, object[]>)jsonObject[level1.Level1]).ContainsKey(level1.Level2))
((Dictionary<string, object[]>)jsonObject[level1.Level1]).Add(level1.Level2, new[] { level1.Level3 });
else
{
var list = (((Dictionary<string, object[]>)jsonObject[level1.Level1])[level1.Level2]).ToList();
list.Add(level1.Level3);
((Dictionary<string, object[]>)jsonObject[level1.Level1])[level1.Level2] = list.ToArray();
}
}
var jsonText = JsonConvert.SerializeObject(jsonObject);
the result of jsonText would look like, hope from this you can develop further., may require some refactoring,

Returning a List<> inheritance C#

class cuentaBancaria
{
public cuentaBancaria()
{
}
public cuentaBancaria(string nombreCliente, string numCuenta, double tipoInteres, double saldo)
{
this.nombreCliente = nombreCliente;
this.numCuenta = numCuenta;
this.tipoInteres = tipoInteres;
this.saldo = saldo;
}
public string nombreCliente { get; set; }
public string numCuenta { get; set; }
public double tipoInteres { get; set; }
public double saldo { get; set; }
public static List<cuentaBancaria> cuentas = new List<cuentaBancaria>()
{
new cuentaBancaria ("John Doe", "123456", 1.5, 159),
new Tarjeta ("John Doe", "123456" , 1.5, 159, "123456789012", "John Doe", TipoTarjeta.CREDITO)
};
}
TipoTarjeta:
enum TipoTarjeta
{
CREDITO,
DEBITO,
MONEDERO,
FINANCIACION
}
Tarjeta:
class Tarjeta : cuentaBancaria
{
public Tarjeta()
{
}
public Tarjeta(string nombreCliente, string numCuenta, double tipoInteres, double saldo, string numTarjeta, string nombre, TipoTarjeta tipoTarjeta)
{
base.nombreCliente = nombreCliente;
base.numCuenta = numCuenta;
base.tipoInteres = tipoInteres;
base.saldo = saldo;
this.numTarjeta = numTarjeta;
this.nombre = nombre;
this.tipoTarjeta = tipoTarjeta;
}
public string numTarjeta { get; set; }
public string nombre { get; set; }
public TipoTarjeta tipoTarjeta { get; set; }
}
I want to return the elements that has a TipoTarjeta.XXX but when I try the
cuentas.Where(c => c.tipoTarjeta == tipo)
I get the error that is an element of the child (Tarjeta) not cuentaBancaria.
How can I only get those elements with that type?
You have a type mismatch.
Your function is declared such that it returns List<cuentaBancaria>, but Where is a LINQ extension method that returns an IEnumerable<cuentBancaria>.
To resolve your issue, add a call to the ToList() extension method as follows:
cuentas.Where(c => c.tipoTarjeta == tipo).ToList()
UPDATE
I copied your code to VSCode and this version of Main works for me. From what I could tell, you needed to reference cuentas through cuentaBancaria; also, the property you were referencing in the Where clause was incorrect, based on the class definition.
public static void Main()
{
var tipo = 3.15;
var result = cuentaBancaria.cuentas.Where(c => c.tipoInteres == tipo).ToList();
foreach (var item in result)
{
Console.WriteLine(item.tipoInteres);
}
}
You first need to filter the list to only the types of Tarjeta, and then you can filter by properties of Tarjeta. You can do this using .OfType<T>() in LINQ:
cuentas.OfType<Tarjeta>().Where(c => c.tipoTarjeta == tipo)

how to get Json nested properties to primary one

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.

Issue getting required output using LINQ query

I need to get data as per this json format.
series: [{
name: 'Marriage',
data: [1, 2, 3] // Sample Data
}, {
name: 'Chess',
data: [2, 2, 3]
}, {
name: 'Ludo',
data: [3, 4, 4]
}]
I need to create chart as here in http://jsfiddle.net/gh/get/library/pure/highcharts/highcharts/tree/master/samples/highcharts/demo/bar-stacked/
What I have tried is using group by from device id and and using for loop to get the result. But I am quite stuck here getting required output.
Here is what I have tried so far.
void Main()
{
DateTime currentDate = DateTime.UtcNow.Date.AddDays(-30);
var currentMonthData = Device_GameDevices.Where(x => x.CreatedDate >= currentDate).ToList();
// Get total game list
var gamesList = currentMonthData.Select(x => x.GameName).Distinct();
// Group the data as per the device id
var groupedData = from gameData in currentMonthData
group gameData by gameData.DeviceID
into egroup
select new {
Game = egroup.Key,
Data = from bug in egroup
group bug by bug.GameName into g2
select new { Name = g2.Key, HoursPlayed = g2.Sum(x => (x.EndTime - x.StartTime).TotalMinutes/60) }
};
Console.Write(groupedData);
List<DashboardVM.ChartData> chartDatas = new List<DashboardVM.ChartData>();
List<double> hourResultList = new List<double>();
foreach(var item in groupedData)
{
var chart = new DashboardVM.ChartData();
foreach(var gameItem in gamesList)
{
chart.GameNameResult = gameItem;
foreach(var groupedDataItem in item.Data)
{
if(gameItem == groupedDataItem.Name)
{
hourResultList.Add(groupedDataItem.HoursPlayed);
}
else
{
hourResultList.Add(0.0);
}
}
chart.HoursPlayed = hourResultList;
}
chartDatas.Add(chart);
}
Console.Write(chartDatas);
}
public class DashboardVM{
public class ChartData{
public string GameNameResult{get;set;}
public List<double> HoursPlayed{get;set;}
}
}
public class Chart
{
public string type { get; set; }
}
public class Title
{
public string text { get; set; }
}
public class XAxis
{
public List<string> categories { get; set; }
}
public class Title2
{
public string text { get; set; }
}
public class YAxis
{
public int min { get; set; }
public Title2 title { get; set; }
}
public class Legend
{
public bool reversed { get; set; }
}
public class Series
{
public string stacking { get; set; }
}
public class PlotOptions
{
public Series series { get; set; }
}
public class Series2
{
public string name { get; set; }
public List<double> data { get; set; }
}
public class RootObject
{
public Chart chart { get; set; }
public Title title { get; set; }
public XAxis xAxis { get; set; }
public YAxis yAxis { get; set; }
public Legend legend { get; set; }
public PlotOptions plotOptions { get; set; }
public List<Series2> series { get; set; }
}
void Main()
{
var Device_GameDevices = new[] {
new {ID=1,CreatedDate=DateTime.Parse("8/23/2017 06:07:30"),DeviceID="Desktop12",EndTime=DateTime.Parse("8/23/2017 06:06:30"),GameName="CyberGunner",StartTime=DateTime.Parse("8/23/2017 06:03:45")},
new {ID=2,CreatedDate=DateTime.Parse("8/23/2017 07:14:01"),DeviceID="A12" ,EndTime=DateTime.Parse("8/23/2017 11:14:01"),GameName="Marriage" ,StartTime=DateTime.Parse("8/23/2017 07:14:01")},
new {ID=3,CreatedDate=DateTime.Parse("8/23/2017 07:14:02"),DeviceID="A12" ,EndTime=DateTime.Parse("8/23/2017 08:14:01"),GameName="Marriage" ,StartTime=DateTime.Parse("8/23/2017 07:14:02")},
new {ID=4,CreatedDate=DateTime.Parse("8/23/2017 09:14:01"),DeviceID="A12" ,EndTime=DateTime.Parse("8/23/2017 09:14:01"),GameName="Chess" ,StartTime=DateTime.Parse("8/23/2017 07:14:03")},
new {ID=5,CreatedDate=DateTime.Parse("8/23/2017 07:14:03"),DeviceID="A12" ,EndTime=DateTime.Parse("8/23/2017 10:14:01"),GameName="Marriage" ,StartTime=DateTime.Parse("8/23/2017 07:14:03")},
new {ID=6,CreatedDate=DateTime.Parse("8/23/2017 09:57:28"),DeviceID="B12" ,EndTime=DateTime.Parse("8/23/2017 10:57:28"),GameName="Marriage" ,StartTime=DateTime.Parse("8/23/2017 09:57:28")},
};
DateTime currentDate=DateTime.UtcNow.Date.AddDays(-30);
var currentMonthData=Device_GameDevices
.Where(x=>x.CreatedDate>=currentDate)
.ToList();
// Get total game list
var gamesList=currentMonthData
.Select(x=>x.GameName)
.Distinct()
.ToList();
var chart=new RootObject
{
chart=new Chart{ type="bar"},
title=new Title{ text="My title" },
xAxis=new XAxis { categories=gamesList },
yAxis=new YAxis { min=0, title=new Title2 {text="Total Game Time"}},
legend=new Legend {reversed=true},
plotOptions=new PlotOptions { series=new Series {stacking="normal"}},
series=currentMonthData
.GroupBy(d=>new {d.DeviceID,d.GameName})
.Select(d=>new {
DeviceID=d.Key.DeviceID,
GameName=d.Key.GameName,
HoursPlayed=d.Sum(x=>(x.EndTime - x.StartTime).TotalMinutes)/60
})
.GroupBy(d=>d.DeviceID)
.Select(d=>new Series2 {
name=d.Key,
data=gamesList
.GroupJoin(d,a=>a,b=>b.GameName,(a,b)=>new {GameName=a,HoursPlayed=b.Sum(z=>z.HoursPlayed)})
.OrderBy(x=>gamesList.IndexOf(x.GameName))
.Select(x=>x.HoursPlayed)
.ToList()
}).ToList()
};
chart.Dump();
}
This is how the series looks:

Categories