How to parse unreadable json? - c#

{
"12": {
"_agicId": 2,
"_index_": "",
"_seq": 1
},
"11": {
"_agicId": 1,
"_index_": "",
"_seq": 2
},
"10": {
"_agicId": 0,
"_index_": "",
"_seq": 3
}
}
I get a json string like above, but i don't know "12""11""10", how can i parser this json get _seq & agicId?
var Name = JObject.Parse(r);
int Count = Name.Count;
for (int i = 0; i < Name.Count; i++)
{
// how can i get "11"{"agicId":0}
}

For this create a model class like below:
class Test
{
public int _agicId { get; set; }
public string _index_ { get; set; }
public string _seq { get; set; }
}
And then read the json like below. I have read from file . you can read from string also. In the key you will get 11, 12 etc...and in value you will get the Text class having values for "agicId" etc...
using (StreamReader r = new StreamReader("data.json"))
{
string jsonString = r.ReadToEnd();
JObject jsonObj = JObject.Parse(jsonString);
var k = JsonConvert.DeserializeObject<Dictionary<string, Test>>(jsonString);
/*
A very good suggestion by Jon Skeet. No need of this foreach loop. Instead of criticising he has suggested a better solution.
foreach(var item in jsonObj)
{
string key = item.Key;
var value = JsonConvert.DeserializeObject<Test>(item.Value.ToString());
}*/
}

Related

Serialize Json in c# with special character in variable name

I need to serialize the following json
{
"searchText": "masktl_TABLE_GetMissingTables",
"$skip": 0,
"$top": 1,
"includeFacets": true
}
I've tried this
string payload = JsonConvert.SerializeObject(new
{
searchText = "masktl_TABLE_GetMissingTables",
$skip = 0,
$top = 1,
includeFacets = true
});
But we can not put $ in the name of a variable. Can anyone please suggest me any other way to serialize the json?
Create a Dictionary<string, object> instead:
var dictionary = new Dictionary<string, object>
{
["searchText"] = "masktl_TABLE_GetMissingTables",
["$skip"] = 0,
["$top"] = 1,
["includeFacets"] = true
};
string payload = JsonConvert.SerializeObject(dictionary);
Alternatively, if you need to do this from more than just the one place, create a class with the relevant properties and use the JsonProperty attribute to specify the name within the JSON.
For example:
public class SearchRequest
{
[JsonProperty("searchText")]
public string SearchText { get; set; }
[JsonProperty("$skip")]
public int Skip { get; set; }
[JsonProperty("$top")]
public int Top { get; set; }
[JsonProperty("includeFacets")]
public bool IncludeFacets { get; set; }
}
var request = new SearchRequest
{
SearchText = "masktl_TABLE_GetMissingTables",
Skip = 0,
Top = 1,
IncludeFacets = true
};
string payload = JsonConvert.SerializeObject(request);
Instead of Anonymous object, have you tried using dictionary,
string payload = JsonConvert.SerializeObject(new Dictionary<string, object>()
{
{ "searchText", "masktl_TABLE_GetMissingTables" },
{ "$skip", 0 },
{ "$top", 1 },
{ "includeFacets", true }
});
Try Online
If you have any defined model class for given json format then you can JsonPropertyAttribute to change the name of property at the time of serialization.
Declare:
public class Pagination
{
[JsonProperty("searchText")]
public string SearchText{ get; set; }
[JsonProperty("$skip")]
public int Skip { get; set; }
[JsonProperty("$top")]
public int Top { get; set; }
[JsonProperty("includeFacets")]
public bool IncludeFacets { get; set; }
}
Usage:
var paginationObj = new Pagination()
{
SearchText = "masktl_TABLE_GetMissingTables",
Skip = 0,
Top = 1,
IncludeFacets = true
};
string payload = JsonConvert.SerializeObject(paginationObj);
Try online

I have serialized nested objects with JSON, how do I deserialize them?

I keep getting "Additional text encountered after finished reading JSON content" when deserializing. I've tried placing the whole "output" into square brackets, didn't work out.
Full error message
Newtonsoft.Json.JsonReaderException:
'Error reading JObject from JsonReader. Current JsonReader item is not an object:
StartArray. Path '', line 1, position 1.'
These are my 2 objects. NOTE: Values are currently commented for easier "output" reading.
class ItemSerObj
{
public string ItemName { get; set; }
/*
public string Value { get; set; }
public string Quality { get; set; }
public string TimeStamp { get; set; }*/
}
.
class GroupSerObj
{
public string GroupName { get; set; }
/*
public string UpdateRate { get; set; }
public string Active { get; set; }*/
public List<ItemSerObj> Items { get; set; }
}
How I serilzed them.
JsonSerializer serializer = new JsonSerializer();
using (StreamWriter sw = new StreamWriter(path + "\\data.txt"))
{
using (JsonWriter writer = new JsonTextWriter(sw))
{
foreach (ListViewItem group in lV_groups.Items)
{
List<ItemSerObj> itemsObj = new List<ItemSerObj>();
tempOPCServer.opcGroup = tempOPCServer.opcServer.OPCGroups.GetOPCGroup(group.SubItems[0].Text);
foreach (OPCItem item in tempOPCServer.opcGroup.OPCItems)
{
ListViewItem listViewItem = new ListViewItem();
listViewItem.Name = item.ItemID.Substring(item.ItemID.LastIndexOf('.') + 1);
itemsObj.Add(
new ItemSerObj
{
ItemName = listViewItem.Name
/*ItemName = item.SubItems[0].Text/*,
Value = item.SubItems[1].Text,
Quality = item.SubItems[2].Text,
TimeStamp = item.SubItems[3].Text*/
});
}
GroupSerObj serializeGroup = new GroupSerObj
{
GroupName = group.SubItems[0].Text,/*
UpdateRate = group.SubItems[1].Text,
Active = group.SubItems[2].Text,*/
Items = itemsObj
};
serializer.Serialize(writer, serializeGroup);
}
}
}
The output.
{"GroupName":"Group0","Items":[{"ItemName":"Int1"},{"ItemName":"Money"},{"ItemName":"Int4"},{"ItemName":"Int2"}]}{"GroupName":"Group1","Items":[]}{"GroupName":"Group2","Items":[]}
More readable sorting
{"GroupName":"Group0","Items":[
{"ItemName":"Int1"},
{"ItemName":"Money"},
{"ItemName":"Int4"},
{"ItemName":"Int2"}]}
{"GroupName":"Group1","Items":[
]}
{"GroupName":"Group2","Items":[
]}
What I've tried to deserialize it.
string fromJson;
using (StreamReader sr = new StreamReader(path + "\\data.txt"))
{
fromJson = #sr.ReadLine();
}
JObject fromJsonObject = JObject.Parse(fromJson); //Where exeption occurs.
IList<JToken> results = fromJsonObject["Items"]["ItemName"].Children().ToList();
IList<GroupSerObj> deserResults = new List<GroupSerObj>();
foreach(JToken result in results)
{
GroupSerObj deserResult = result.ToObject<GroupSerObj>();
deserResults.Add(deserResult);
}
For me it looks like your output is wrong. Its an array of objects (multiple groups) so it should be surrounded by [ and ] and each object separated by a comma (,).
Your output should look like this:
[{"GroupName":"Group0","Items":[{"ItemName":"Int1"},{"ItemName":"Money"},{"ItemName":"Int4"},{"ItemName":"Int2"}]},{"GroupName":"Group1","Items":[]},{"GroupName":"Group2","Items":[]}]
You are using a JObject to Parse the Array, but when paring an array we need the JArray, so it should be:
JArray fromJsonObject = JArray.Parse(fromJson); //Where exeption occurs.
for (int i = 0; i < fromJsonObject.Count; i++)
{
IList<GroupSerObj> deserResults = new List<GroupSerObj>();
var deserResult = fromJsonObject[i].ToObject<GroupSerObj>();
deserResults.Add(deserResult);
}

C# JSON Serialize/Deserialize - INPUT problem

I have problem with serialization and deserialization in JSON
I've made 2 tasks to read from JSON file which looks like this:
[
{
"ID": 1,
"OIB": 123456789,
"ime": "name",
"prezime": "surname",
"grad": "city"
}
]
Now I have to add another client with ID 2, with new user informations.
I can read this JSON file with no problems, but I am stuck on writing into the same file.
public struct Klijent
{
public int ID { get; set; }
public long OIB { get; set; }
public string ime { get; set; }
public string prezime { get; set; }
public string grad { get; set; }
}
"FetchClient" from JSON
public static List<Klijent> DohvatiKlijente()
{
List<Klijent> lKlijent = new List<Klijent>();
StreamReader klijent = new StreamReader("x");
string sJson = "";
using (klijent)
{
sJson = klijent.ReadToEnd();
lKlijent = JsonConvert.DeserializeObject<List<Klijent>>(sJson);
}
return lKlijent;
}
"AddClient" to JSON
OIB -> personal identificator
ID -> should go +1 with every entry of client
grad -> city
ime -> name
prezime -> surname
public static void DodavanjeKlijenata()
{
Console.Write("Unesite OIB klijenta: ");
string pOIB = Console.ReadLine();
long nullOIB = 0;
long.TryParse(pOIB, out nullOIB);
int id = 0;
Console.Write("Unesite ime klijenta: ");
string ime1 = Console.ReadLine();
Console.Write("Unesite prezime klijenta: ");
string prezime1 = Console.ReadLine();
Console.Write("Unesite grad klijenta: ");
string grad1 = Console.ReadLine();
List<Klijent> lKlijent = DohvatiKlijente();
foreach (var Klijent in lKlijent)
{
id = Klijent.ID + 1;
}
Klijent dKlijent = new Klijent()
{
ID = id,
OIB = nullOIB,
ime = ime1,
prezime = prezime1,
grad = grad1
};
var serializer = new JsonSerializer();
using (var sw = new StreamWriter("x"))
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, dKlijent);
}
}
This code does work, but it seems to delete every time my JSON file and it's format is in one line only, I would like to have it in multiple lines.
Thank you :)
There are two things that you need to do here
Ensure new Client is appended to existing list
For this you can add the new client to the List
lKlijent.Add(dKlijent);
Now you need to serialize the List, instead of lKlijent
using (JsonWriter writer = new JsonTextWriter(sw))
{
serializer.Serialize(writer, lKlijent);
}
Formatting
For formatting you can use Formatting Settings. For example,
var serializer = new JsonSerializer() { Formatting = Formatting.Indented} ;
Additional Comments
1. Calculation of ID
Instead of calculating the new ID using the following loop,
foreach (var Klijent in lKlijent)
{
id = Klijent.ID + 1;
}
You could use Enumerable.Last() to get the last client in the list. For example,
var id = lKlijent?.Any()!=true? 0:lKlijent.Last().ID;
2. Rewriting DohvatiKlijente method
The DohvatiKlijente method could rewritten as
public static List<Klijent> DohvatiKlijente()
{
return JsonConvert.DeserializeObject<List<Klijent>>(File.ReadAllText("C:\\Users\\Hrvoje\\Desktop\\Polica Osiguranja MAIN\\Polica Osiguranja\\klijent.json"));
}
Similarly, writing back to file can be simplified as
var jsonString = JsonConvert.SerializeObject(lKlijent,Newtonsoft.Json.Formatting.Indented);
File.WriteAllText(outputFilePath,jsonString);

C# How to iterate through list for individual API calls

From the following JSON data I want to put the station_code variables into a list. After this I want to use each station_code variable into a API URL call.
{
"request_time": "2015-02-19T08:33:39+00:00",
"stations": [
{
"station_code": "HWV",
"atcocode": null
},
{
"station_code": "HXX",
"atcocode": null
},
{
"station_code": "HAF",
"atcocode": null
}
]
}
This is the C# code I have attempting this
dynamic array = JsonConvert.DeserializeObject(json);
dynamic stations = array.stations;
var test = JObject.Parse(json);
var services = test.SelectTokens("stations[*].station_code").Select(t => (string)t).ToList();
JArray items = new JArray();
foreach (JObject station in stations)
{
items.Add(station["station_code"]);
}
int stationLength = 3;
for (int i = 0; i < stationLength; i++)
{
string localJson = get_local_departs("http://transportapi.com/v3/uk/train/station/"+ items[i] + "/live.json?app_id=03bf8009&app_key=d9307fd91b0247c607e098d5effedc97&train_status=passenger");
dynamic localStationArray = JsonConvert.DeserializeObject(localJson);
dynamic departures = localStationArray.departures;
dynamic localStationDeparts = departures.all;
foreach (var depart in localStationDeparts)
{
//info put into data tables
}
}
}
Well why can't you convert that to a strong type and use that instead like
public class stations
{
public string station_code { get; set; }
public string atcocode {get; set; }
}
public class Data
{
public DateTime request_time {get; set; }
public IEnumerable<stations> Stations {get; set; }
}
var result = JsonConvert.DeserializeObject<Data>(json);
foreach(stations s in result.Stations)
{
Console.WriteLine(s.station_code);
}

Extracting a key-value pair from inside a string

I have the following string:
string myString = "{'gridObject':'[1,2,3,4],[5,6,7,8]'}";
How do I process this into an object so that I can do this:
charts[0] //=> [1,2,3,4]
charts[0][1] //=> 2
If I can convert it to this object, even better:
public class gridObject {
public int datarow {get; set;}
public int datacol {get; set;}
public int datasizex {get; set;}
public int datasizey {get; set;}
}
This is what I would do.
Create your classes first,
public class GridObject
{
public int datarow { get; set; }
public int datacol { get; set; }
public int datasizex { get; set; }
public int datasizey { get; set; }
}
public class GridObjectCollection
{
public GridObject[] GridObjects { get; set; }
}
Then, to see what JSON you need, serialize it once: (JsonConvert is part of Json.NET, you can get it with NuGet)
GridObjectCollection gridObjects = new GridObjectCollection();
gridObjects.GridObjects = new GridObject[]
{
new GridObject() { datacol = 1, datarow = 2, datasizex = 3, datasizey = 4 },
new GridObject() { datacol = 5, datarow = 6, datasizex = 7, datasizey = 8 }
};
Console.WriteLine
(
JsonConvert.SerializeObject
(
gridObjects,
new JsonSerializerSettings() { Formatting = Formatting.Indented }
)
);
Here you can see that the valid JSON content which will produce these classes when deserialized is like:
{
"GridObjects": [
{
"datarow": 2,
"datacol": 1,
"datasizex": 3,
"datasizey": 4
},
{
"datarow": 6,
"datacol": 5,
"datasizex": 7,
"datasizey": 8
}
]
}
Then, just try a deserialization just to make sure:
var f = JsonConvert.DeserializeObject<GridObjectCollection>
(
"{'GridObjects':[{'datarow':2,'datacol':1,'datasizex':3,'datasizey':4},{'datarow':6,'datacol':5,'datasizex':7,'datasizey':8}]}"
);
Here is one way to do it:
public static gridObject[] Parse(string str)
{
int first = str.IndexOf("[");
int last = str.LastIndexOf("]");
str = str.Substring(first, last - first + 1);
string[] big_parts = str.Split(new string[] {"[", "],[", "]"} , StringSplitOptions.RemoveEmptyEntries);
return big_parts.Select(x =>
{
string[] small_parts = x.Split(',');
return new gridObject()
{
datarow = Convert.ToInt32(small_parts[0]),
datacol = Convert.ToInt32(small_parts[1]),
datasizex = Convert.ToInt32(small_parts[2]),
datasizey = Convert.ToInt32(small_parts[3]),
};
}).ToArray();
}
It first searches for the the first [ and the last ] and trims anything before [ and after ].
Then, it splits the string based on [, ],[, ].
This will give us 1,2,3,4 and 5,6,7,8 for your example.
Then for each one of them, we split based on , and convert the results into a gridObject object.
Done with custom parsing:
public class GridObject
{
public int datarow { get; set; }
public int datacol { get; set; }
public int datasizex { get; set; }
public int datasizey { get; set; }
}
/// <summary>
/// MySuperObject class which holds a reference to inner array of integers
/// </summary>
public class MySuperObject
{
public List<int> Items { get; set; } // Inner array of list of integers
public MySuperObject()
{
Items = new List<int>();
}
public override string ToString()
{
// Need to override ToString to return something like "[1,2,3,4]"
var result = "";
foreach (var item in Items)
{
if (result.Length > 0)
result += ",";
result += item.ToString();
}
return string.Format("[{0}]", result);
}
/// <summary>
/// Function to generate GridObject from existing set of integers
/// </summary>
public GridObject GetGridObject()
{
var result = new GridObject();
if (Items.Count >= 1) result.datarow = Items[0];
if (Items.Count >= 2) result.datacol = Items[1];
if (Items.Count >= 3) result.datasizex = Items[2];
if (Items.Count >= 4) result.datasizey = Items[3];
return result;
}
}
// Parse functions
public List<MySuperObject> Parse(string value)
{
if (string.IsNullOrEmpty(value))
throw new ArgumentException("value cannot be null or empty!", "value");
var result = new List<MySuperObject>();
// First get the indexes of first [ and last ]
var idxStart = value.IndexOf("[");
var idxEnd = value.LastIndexOf("]");
// Check validity
if (idxStart < 0 || idxEnd < 0 || idxEnd <= idxStart)
return result; // Return empty list
value = value.Substring(idxStart, idxEnd - idxStart + 1).Trim();
// Split by [] after replacing spaces with empty strings (and removing first and last [ and ])
var arr = value.Replace(" ", "").Trim('[',']').Split(new[] { "],[" }, StringSplitOptions.RemoveEmptyEntries);
foreach (var str in arr)
{
// Construct list of integers with a help of LINQ
var nums = str.Split(',').Select(t => Convert.ToInt32(t)).ToList();
// Create and add MySuperObject to existing list which will be returned
result.Add(new MySuperObject
{
Items = new List<int>(nums),
});
}
return result;
}
And here is the usage of such parsing:
var myString = "{'gridObject':'[1,2,3,4],[5,6,7,8]'}";
var value = Parse(myString);
// Get all grid objects
var allGridObjects = value.Select(t => t.GetGridObject()).ToList();
Of course, this could need a little bit more of error checking but basically, this MySuperObject is used to use any number of integers you desire, while providing you with a helper method of "GetGridObject" to fill you grid object with appropriate numbers from array of numbers.

Categories