I have a js file with JSON in it (no code) something like that:
Name1 = {
p1:0,
p2:1,
p3:2
};
Name2 = {
p1:"None",
p2:"Snappy",
p3:"gzip"
};
and I want to parse it in C#, but the Newtonsoft.JSON doesn't know how to manage the "Name = ".
How can I do it?
Thanks in advance.
As mentioned in my comment, neither of those are valid JSON strings.
An example of your structure as valid JSON
{
"Name": {
"p1": 0,
"p2": 1,
"p3": 3
}
}
AND
{
"Name": {
"p1": "None",
"p2": "Snappy",
"p3": "gzip"
}
}
These would require a root object when deserializing.
E.g. your class structure would look something like:
public class RootObject {
public Name Name {get; set;}
}
public class Name {
public string p1 {get; set;}
public string p2 {get; set;}
public string p3 {get; set;}
}
And would be deserialized like this:
var json = ...; //Load from file or whatever.
var myObj = JsonConvert.DeserializeObject<RootObject>(json);
var p1 = myObj.Name.p1;
convert your file to legitimate JSON string and then parse it
string data = //get your data somehow - (ex.loading from file)
int indexStart;
data = data.Replace(";", String.Empty);
while ((indexStart = data.IndexOf("{")) > 0)
{
//convert the set of data to be legetimate JSON string
int indexEnd = data.IndexOf("}");
string temp = data.Substring(indexStart, indexEnd - indexStart + 1);
//Deserializ string
var obj = JsonConvert.DeserializeObject<SomeData>(temp);
//prepare the data for the next iteration
data = data.Substring(indexEnd + 1);
}
and the class that suits the JSON format
public class SomeData
{
public string p1 { get; set; }
public string p2 { get; set; }
public string p3 { get; set; }
}
this is a code to parse your string
class name {
public dynamic p1 { get; set; }
public dynamic p2 { get; set; }
public dynamic p3 { get; set; }
}
public static void Main(string[] args)
{
string code = #"Name1 = {
p1:0,
p2:1,
p3:2
};
Name2 = {
p1:""None"",
p2: ""Snappy"",
p3: ""gzip""
};";
List<name> l = new List<name>();
string[] partsBySamicolon = code.Split(';');
foreach(string s in partsBySamicolon){
if (!string.IsNullOrEmpty(s))
{
string[] partByBraces = s.Split('{');
name n = new name();
string[] partsbyComma = partByBraces[1].Split('}')[0].Split(',');
foreach (string ss in partsbyComma)
{
if (!string.IsNullOrEmpty(ss))
{
if (ss.Contains("p1"))
n.p1 = ss.Split(':')[1].Trim();
if (ss.Contains("p2"))
n.p2 = ss.Split(':')[1].Trim();
if (ss.Contains("p3"))
n.p3 = ss.Split(':')[1].Trim();
}
}
l.Add(n);
}
}
Console.Read();
}
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 am trying to create a log file in json format from a List.
my class for list is
public class ChunkItem
{
public int start { get; set; }
public int end { get; set; }
}
public class DownloadItem
{
public int id { get; set; }
public string fname { get; set; }
public string downloadPath { get; set; }
public int chunkCount { get; set; }
public ChunkItem[] chunks { get; set; }
public DownloadItem(int _id, string _fname, string _downloadPath, int _chunkCount, ChunkItem[] _chunks)
{
id = _id;
fname = _fname;
downloadPath = _downloadPath;
chunkCount = _chunkCount;
chunks = _chunks;
}
}
creating a json file from this class works fine
ChunkItem[] chunks = new ChunkItem[2];
chunks[0] = new ChunkItem();
chunks[0].start = 0;
chunks[0].end = 0;
chunks[1] = new ChunkItem();
chunks[1].start = 0;
chunks[1].end = 0;
List<DownloadItem> lst = new List<DownloadItem>();
lst.Add(new DownloadItem(0, "", "", 2, chunks));
lst.Add(new DownloadItem(1, "aaa", "sss", 2, chunks));
lst.Add(new DownloadItem(2, "bbb", "ddd", 2, chunks));
string json = JsonConvert.SerializeObject(lst);
System.IO.File.WriteAllText(logPath, json);
I want to read the file to same class list and do some updates or add new lines
I can read the file to a string but cannot create a new list
how can I convert string (read json file) to List<DownloadItem> new list
You need to read all the contends from the file and deserialize the json string to List<DownloadItem>
var jsonData = File.ReadAllText(filePath)
var list = JsonConvert.DeserializeObject<List<DownloadItem>>(jsonData);
Clas DownloadItem is missing a default parameterless constructor.
I use Newtonsoft, where creating the instances and filling them is simple
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<MyClass>(jsonString);
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 was trying to make a txt file, then rename the extension to .json, I have the encoding step and the WriteAllLines step done, but how do I encode the text?(I have the string needed to write)
Here's the code
string[] lines = { "{", "\"version\": 1,", "\"schema_version\": 2,", "",
$"\"id\": \"{textBox14.Text}\",", "", $"\"title\": \"{textBox7.Text}\",",
$"\"title_localized\": \"{textBox18.Text}\",", "", $"\"artist\": \"{textBox6.Text}\",",
$"\"artist_localized\": \"{textBox8.Text}\",", $"\"artist_source\": \"{textBox9.Text}\",",
$"", $"\"illustrator\": \"{textBox10.Text}\",", $"\"illustrator_source\": \"{textBox11.Text}\",",
$"", $"\"charter\": \"{textBox13.Text}\",", $"", "\"music\": {",
$"\"path\": \"{textBox4.Text}\"", "}", "\"music_preview\": {", $"\"path\": \"{textBox5.Text}\"", "}",
"\"background\": {", $"\"path\": \"{open3.FileName}\"", "}",
"\"charts\": [", "{", "\"type\": \"easy\",", $"\"name\": \"{textBox15.Text}\",",
$"\"difficulty\": {numericUpDown1.Value},", $"\"path\": \"textBox1.Text\"", "},",
"{", "\"type\": \"hard\",", $"\"name\": \"{textBox16.Text}\",", $"\"difficulty\": {numericUpDown2.Value},",
$"\"path\": \"{textBox2.Text}\"", "},", $"]", $"", "}" };
Encoding utf8WithoutBom = new UTF8Encoding(true);
File.WriteAllLines($#"C:\Users\Public\Desktop\level files\{textBox14.Text}\level.json", lines);
It was supposed to be something like this:
https://cytoid.io/level.json
Short answer:
Change this:
File.WriteAllLines($#"C:\Users\Public\Desktop\level files\{textBox14.Text}\level.json", lines);
to this:
File.WriteAllLines($#"C:\Users\Public\Desktop\level files\{textBox14.Text}\level.json", lines, utf8WithoutBom);
Long answer:
You shouldn't be generating JSON like this; you should be using a dedicated serializer. With your current solution, if a user enters an invalid character, your JSON will immediately become invalid. So, as a solution you could use Newtonsoft's JSON.Net. Here is an example:
Class definitions
public class Item
{
public int Version { get; set; }
public int SchemaVersion { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string TitleLocalized { get; set; }
public string Artist { get; set; }
public string ArtistLocalized { get; set; }
public string ArtistSource { get; set; }
public string Illustrator { get; set; }
public string IllustratorSource { get; set; }
public string Charter { get; set; }
public ItemMusic Music { get; set; }
public ItemMusicPreview MusicPreview { get; set; }
public ItemBackground Background { get; set; }
public List<ItemChart> Charts { get; set; }
}
public class ItemMusic
{
public string Path { get; set; }
}
public class ItemMusicPreview
{
public string Path { get; set; }
}
public class ItemBackground
{
public string Path { get; set; }
}
public class ItemChart
{
public string Type { get; set; }
public string Name { get; set; }
public int Difficulty { get; set; }
public string Path { get; set; }
}
Object initialization and serialization
var item = new Item
{
Version = 1,
SchemaVersion = 2,
Id = textBox14.Text,
Title = textBox7.Text,
TitleLocalized = textBox18.Text,
Artist = textBox6.Text,
ArtistLocalized = textBox8.Text,
ArtistSource = textBox9.Text,
Illustrator = textBox10.Text,
IllustratorSource = textBox11.Text,
Charter = textBox13.Text,
Music = new ItemMusic
{
Path = textBox4.Text
},
MusicPreview = new ItemMusicPreview
{
Path = textBox5.Text
},
Background = new ItemBackground
{
Path = open3.FileName
},
Charts = new List<ItemChart>
{
new ItemChart
{
Type = "easy",
Name = textBox15.Text,
Difficulty = numericUpDown1.Value,
Path = textBox1.Text
},
new ItemChart
{
Type = "hard",
Name = textBox16.Text,
Difficulty = numericUpDown2.Value,
Path = textBox2.Text
}
}
};
var settings = new JsonSerializerSettings()
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
}
};
var json = JsonConvert.SerializeObject(item, settings);
File.WriteAllText($#"C:\Users\Public\Desktop\level files\{textBox14.Text}\level.json", json, new UTF8Encoding(true));
You could also use an anonymous type instead of creating the full class definition, of course:
var item = new {
Version = 1,
SchemaVersion = 2,
Charts = new List<object>
{
new {
Type = "easy"
}
}
}
and then just serialize this.
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.