i have a large json data and i want to get all paths from the root until getting value for the paths then storing the result to a string as i described bellow
here is my json for example
{
"root":{
"first":{
"first1":{
"value":"1"
},
"first2":{
"value":"2"
},
"first3":{
"value":"3"
}
},
"second":{
"second1":{
"value":"1"
},
"second2":{
"value":"2"
},
"second3":{
"value":"3"
}
},
"third":{
"third1":{
"value":"1"
},
"third2":{
"value":"2"
},
"third3":{
"value":"3"
}
},
"four":{
"value":"4"
},
"five":{
"five1":{
"five11":{
"value":"five11"
},
"five12":{
"value":"five12"
}
},
"five2":{
"five21":{
"five211":{
"value":"five211"
}
}
}
}
}
}
then i want to make each paths like bellow dynamically in c# and showing in screen please tell me a way to make this
root.first.first1.value
root.first.first2.value
root.first.first3.value
root.second.second1.value
......
root.four.value
root.five.five1.five11.value
root.five.five1.five12.value
....
root.five2.five21.five211.value
Use JSON.NET and iterate recursively through the Children property and check if the current token doesn't have HasValues set to true and if that's the case add the Path property of that token to a StringBuilder or what have you. Should give you exactly what you want.
Edith: Code Sample
I was lazy and just included the whole console application code.
Example on dotnetfiddle.net
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Text;
public class Program
{
public static void Main()
{
var json = #"
{
""root"":{
""first"":{
""first1"":{
""value"":""1""
},
""first2"":{
""value"":""2""
},
""first3"":{
""value"":""3""
}
}
}
}";
var jobject = JObject.Parse (json);
var sb = new StringBuilder ();
RecursiveParse (sb, jobject);
Console.WriteLine (sb.ToString());
}
public static void RecursiveParse(StringBuilder sb, JToken token)
{
foreach (var item in token.Children()) {
if (item.HasValues)
{
RecursiveParse (sb, item);
} else {
sb.AppendLine (item.Path);
}
}
}
}
Related
I am trying to deserialize a dictionary that I was able to already serialize into a .json file.
I made have a class 'Schedule' that is basically the following:
Dictionary<Dag, Stack<Training>>
In my data layer I have the following .json file:
{
"FullSchedule": {
"Maandag": [
{
"Name": "test",
"Description": "test",
"Trainingsort": 0,
"Hours": 1,
"Minutes": 0
}
],
"Dinsdag": [],
"Woensdag": [
{
"Name": "test",
"Description": "test",
"Trainingsort": 0,
"Hours": 0,
"Minutes": 30
}
],
"Donderdag": [],
"Vrijdag": [],
"Zaterdag": [],
"Zondag": []
}
}
As you can see it has the days with a stack of Training objects. But I am not able to deserialize it back to the dictionary as shown above.
It's a school project so I can't use the Newtonsoft and I have to use System.Text.JSON
This is the code i have at the moment:
public static Dictionary<string, Stack<Training>> ReadJSON(string path)
{
if (!Directory.Exists(path)) throw new ArgumentException("Path does not exist");
// First read the file in as a string, then parse it
string scheduleString = "";
try
{
using (StreamReader sr = new StreamReader($#"{path}.json"))
{
scheduleString = sr.ReadToEnd();
}
}
catch (Exception e) { throw new Exception(e.Message); }
var schedule = JsonSerializer.Deserialize<Dictionary<string, Stack<Training?>>>(scheduleString);
return schedule;
}
Thanks in advance!
you can parse json string and after this to deserialize a FullSchedule value
var jsonDocument = JsonDocument.Parse(scheduleString);
Dictionary<string, Stack<Training?>> schedule = jsonDocument.RootElement
.GetProperty("FullSchedule").Deserialize<Dictionary<string, Stack<Training?>>>();
According to how it looks, your json will be deserialized in such class:
public class SomeClass
{
public Dictionary<string, Stack<Training?>> FullSchedule { get; set; }
}
...
var schedule = System.Text.Json.JsonSerializer.Deserialize<SomeClass>(jsonString);
I have a Json as below
{
"name": "123",
"properties": {
"pcName-A": {
"model": "xyz"
}
}
}
I want to add a property as below
{
"name": "123",
"properties": {
"pcName-A": {
"model": "xyz"
},
"pcName-B": {
"model": "xyz"
}
}
}
I am using Newtonsoft library and do as below
var jsonObj = JObject.Parse("jsonString");
jsonObj.SelectToken("properties").Children().First().AddAfterSelf(
new JProperty(pcName-B,
new JObject(
new JProperty("model", xyz))));
Normally if I want to add property in top level I used to do as below
var propertyObjectToAdd = new JObject():
jsonObj.Add("property1", propertyObjectToAdd);
OR
jsonObj["property1"] = propertyObjectToAdd
Is this kind of easy way is not there for the above example?
You just need to get the properties value as a JObject via a cast - then you can call Add on it to add the new property:
using Newtonsoft.Json.Linq;
using System;
using System.IO;
class Program
{
static void Main()
{
string initialJson = File.ReadAllText("test.json");
var jsonObj = JObject.Parse(initialJson);
var properties = (JObject) jsonObj["properties"];
properties.Add(new JProperty("pcName-B", new JObject { ["model"] = "xyz" }));
Console.WriteLine(jsonObj);
}
}
Instead of Add you could use:
properties["pcName-B"] = new JObject { ["model"] = "xyz" };
... but I don't know whether there's any guarantee that the new property would come after the existing one.
I'm having an issue deserializing a JSON string into a RootObject class with 1 string property and a list of custom objects.
When I debug the application and the code deserializes the json I get my 'ErrorCode' property, "test", is populated in the RootObject class but the 'meets' property is always null.
The code sits in a cross platform Xamarin forms application currently, but I've pulled the code and class definitions out and ran them in a simple console application that worked first time with no issues. I'm struggling to figure out what I'm doing wrong.
My simple JSON object is the following:
{"meets": [
{
"VenueName": "O2"
},
{
"VenueName": "wembly"
},
{
"VenueName": "NEC"
}
],
"ErrorCode": "test"}
My class definitions:
[JsonObject(Id = "Meets")]
public class Meets
{
[JsonProperty(PropertyName = "VenueName")]
public string VenueName { get; set; }
}
public class RootObject
{
public List<Meets> Meets { get; set; }
public string ErrorCode { get; set; }
}
The code to hit the api and get the json object (which is blanked out and a smaller simple object in its place):
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
using EliteNfcBet.Models;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace EliteNfcBet.ViewModels
{
public class ItemsViewModel : BaseViewModel
{
public ObservableCollection<Meets> RaceMeets { get; set; }
public Command LoadItemsCommand { get; set; }
public ItemsViewModel ()
{
Title = "Select Meeting";
RaceMeets = new ObservableCollection<Meets>();
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
}
async Task ExecuteLoadItemsCommand()
{
if (IsBusy)
return;
IsBusy = true;
try
{
RaceMeets.Clear();
var result = await GetMeetingsAsync();
//RaceMeets = result;
//foreach (var meet in meets.Meets)
//{
// RaceMeets.Add(meet);
//}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
public static async Task<RootObject> GetMeetingsAsync()
{
RootObject meet = new RootObject();
//List<Meet> meets = new List<Meet>();
HttpClient client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
var uri = new Uri(string.Format(Constants.RestUrl, string.Empty) + "/api/GetAvailablemeetings");
try
{
var response = await client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
//var content = await response.Content.ReadAsStringAsync();
var content = "{\"meets\":[{\"VenueName\":\"O2\"},{\"VenueName\":\"wembly\"},{\"VenueName\":\"NEC\"}],\"ErrorCode\":\"test\"}";
if (!string.IsNullOrEmpty(content))
{
ITraceWriter traceWriter = new MemoryTraceWriter();
var settings = new JsonSerializerSettings
{
Error = (sender, args) =>
{
if (System.Diagnostics.Debugger.IsAttached)
{
System.Diagnostics.Debugger.Break();
}
},
TraceWriter = traceWriter
};
//result = JsonConvert.DeserializeObject<T>(json, settings);
meet = JsonConvert.DeserializeObject<RootObject>(content, settings);
Console.WriteLine(traceWriter);
}
//if (meets.Count > 0)
//{
// meet.MeetList = meets;
//}
}
}
catch (Exception ex)
{
meet.ErrorCode = "INTERNAL_ERROR";
}
return meet;
}
}
}
EDIT:
I've made some minor changes suggested which are below.
My Json string is now this:
"{\"Meets\":[{\"VenueName\":\"O2\"},{\"VenueName\":\"wembly\"},{\"VenueName\":\"NEC\"}],\"ErrorCode\":\"test\"}"
My classes are below. One thing to note is they are defined within a 'models' namespace in a seperate code file that is doing the deserializing.
namespace EliteNfcBet.Models
{
public class Meets
{
public string VenueName { get; set; }
}
public class RootObject
{
public List<Meets> Meets { get; set; }
public string ErrorCode { get; set; }
}
}
Again i have debugging output when deserializing which looks like it points to the fact that the Meets class member not being found?
{2018-05-28T23:12:22.987 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets', line 1, position 9.
2018-05-28T23:12:22.993 Info Started deserializing System.Collections.Generic.List`1[[NInterpret.InterpretedObject, NInterpret.Xamarin.Droid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Path 'Meets', line 1, position 10.
2018-05-28T23:12:22.994 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[0].VenueName', line 1, position 23.
2018-05-28T23:12:22.994 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[0].VenueName', line 1, position 23.
2018-05-28T23:12:22.994 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[0]', line 1, position 28.
2018-05-28T23:12:22.995 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[1].VenueName', line 1, position 42.
2018-05-28T23:12:22.995 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[1].VenueName', line 1, position 42.
2018-05-28T23:12:22.996 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[1]', line 1, position 51.
2018-05-28T23:12:22.997 Info Started deserializing EliteNfcBet.Models.RootObject. Path 'Meets[2].VenueName', line 1, position 65.
2018-05-28T23:12:22.997 Verbose Could not find member 'VenueName' on EliteNfcBet.Models.RootObject. Path 'Meets[2].VenueName', line 1, position 65.
2018-05-28T23:12:22.997 Info Finished deserializing EliteNfcBet.Models.RootObject. Path 'Meets[2]', line 1, position 71.
2018-05-28T23:12:22.998 Info Finished deserializing System.Collections.Generic.List`1[[NInterpret.InterpretedObject, NInterpret.Xamarin.Droid, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]. Path 'Meets', line 1, position 72.
2018-05-28T23:12:23.009 Info Finished deserializing EliteNfcBet.Models.RootObject. Path '', line 1, position 92.
2018-05-28T23:12:23.009 Verbose Deserialized JSON:
{
"Meets": [
{
"VenueName": "O2"
},
{
"VenueName": "wembly"
},
{
"VenueName": "NEC"
}
],
"ErrorCode": "test"
}}
edit 3:
I've just came across this post which explains a lot! Seems like xamarin.forms has a known problem currently with reflection and so certain packages may not work correctly.
JsonConvert.SerializeObject always return {} in XamarinForms
Does anyone have any insight as to why this happens and when this will be resolved. Also a work around that I could implement so I can use debugging. Thanks.
{"meets": [
{
"VenueName": "O2"
},
{
"VenueName": "wembly"
},
{
"VenueName": "NEC"
} ],
"ErrorCode": "test"}
Your problem is that you have an object called "meets" in javascript, and in your object in C# you have "Meets". Change it to "Meets" and it should work.
You also don't need the JsonObject attribute, I believe. .NET should be able to handle the serialization from JSON automatically:
public class Meets
{
public string VenueName { get; set; }
}
public class RootObject
{
public List<Meets> Meets { get; set; }
public string ErrorCode { get; set; }
}
Spend some time looking at these resources to understand why your error is occurring:
https://learn.microsoft.com/en-us/dotnet/standard/serialization/
EDIT
The above classes produces the following json:
Meets:
{
"VenueName": null
}
Root Object:
{
"Meets": [
{
"VenueName": null
},
{
"VenueName": null
},
{
"VenueName": null
}
],
"ErrorCode": null
}
i'm trying to update an item in voteResultList by matching item's 'voteId' field.
the document:
{
voteDocumentId: "....",
voteResultList: [
{
voteId: "....",
voteResult: "NA"
},
{
voteId: "....",
voteResult: "Against"
}
....
]
}
if in mongo i can use this command and it works correctly.
db.getCollection('VoteCollection').update({'voteDocumentId': '....', 'voteResultList.voteId': '....'},{'$set': {'voteResultList.$.voteResult': 'Approve'}})
in csharp code using csharp mongo driver, i generated a filter bson document from this json document
{'voteDocumentId': '....', 'voteResultList.voteId': '....'}
then i generated a update bson document by this code
Builders<BsonDocument>.Update.Set("voteResultList.$.voteResult", "Approve")
but apparently i'm not doing it correctly, because after calling MongoCollection.UpdateMany(filter, update), mongoUpdateResult.ModifiedCount = 0, and nothing changes in mongodb document.
so what is the correct way of doing this?
Thanks!
Here's a complete working example for your case based on the answer here: Mongo update array element (.NET driver 2.0)
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Linq;
namespace ConsoleApp1
{
public class VoteCollection
{
public ObjectId Id;
public string voteDocumentId;
public VoteResult[] voteResultList;
}
public class VoteResult
{
public string voteId;
public string voteResult;
}
public class Program
{
public static IMongoDatabase _db;
static void Main(string[] args)
{
var collection = new MongoClient().GetDatabase("test").GetCollection<VoteCollection>("VoteCollection");
collection.InsertOne
(
new VoteCollection
{
voteDocumentId = "foo",
voteResultList = new []
{
new VoteResult { voteId = "bar1", voteResult = "NA" },
new VoteResult { voteId = "bar2", voteResult = "Against" },
}
}
);
var filter = Builders<VoteCollection>.Filter.Where(voteCollection => voteCollection.voteDocumentId == "foo" && voteCollection.voteResultList.Any(voteResult => voteResult.voteId == "bar1"));
var update = Builders<VoteCollection>.Update.Set(voteCollection => voteCollection.voteResultList[-1].voteResult, "Approve");
collection.UpdateMany(filter, update);
Console.ReadLine();
}
}
}
I am using JSON.NET and C# 5. I need to serialize/de-serialize list of objects into line delimited json. http://en.wikipedia.org/wiki/Line_Delimited_JSON. Example,
{"some":"thing1"}
{"some":"thing2"}
{"some":"thing3"}
and
{"kind": "person", "fullName": "John Doe", "age": 22, "gender": "Male", "citiesLived": [{ "place": "Seattle", "numberOfYears": 5}, {"place": "Stockholm", "numberOfYears": 6}]}
{"kind": "person", "fullName": "Jane Austen", "age": 24, "gender": "Female", "citiesLived": [{"place": "Los Angeles", "numberOfYears": 2}, {"place": "Tokyo", "numberOfYears": 2}]}
Why I needed because its Google BigQuery requirement https://cloud.google.com/bigquery/preparing-data-for-bigquery
Update: One way I found is that serialize each object seperataly and join in the end with new-line.
You can do so by manually parsing your JSON using JsonTextReader and setting the SupportMultipleContent flag to true.
If we look at your first example, and create a POCO called Foo:
public class Foo
{
[JsonProperty("some")]
public string Some { get; set; }
}
This is how we parse it:
var json = "{\"some\":\"thing1\"}\r\n{\"some\":\"thing2\"}\r\n{\"some\":\"thing3\"}";
var jsonReader = new JsonTextReader(new StringReader(json))
{
SupportMultipleContent = true // This is important!
};
var jsonSerializer = new JsonSerializer();
while (jsonReader.Read())
{
Foo foo = jsonSerializer.Deserialize<Foo>(jsonReader);
}
If you want list of items as result simply add each item to a list inside the while loop to your list.
listOfFoo.Add(jsonSerializer.Deserialize<Foo>(jsonReader));
Note: with Json.Net 10.0.4 and later same code also supports comma separated JSON entries see How to deserialize dodgy JSON (with improperly quoted strings, and missing brackets)?)
To implement with .NET 5 (C# 9) and the System.Text.Json.JsonSerializer class, and for "big" data, I wrote code for streaming processing.
Using the System.IO.Pipelines extension package, this is quite efficient.
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipelines;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
class Program
{
static readonly byte[] NewLineChars = {(byte)'\r', (byte)'\n'};
static readonly byte[] WhiteSpaceChars = {(byte)'\r', (byte)'\n', (byte)' ', (byte)'\t'};
private static async Task Main()
{
JsonSerializerOptions jsonOptions = new(JsonSerializerDefaults.Web);
var json = "{\"some\":\"thing1\"}\r\n{\"some\":\"thing2\"}\r\n{\"some\":\"thing3\"}";
var contentStream = new MemoryStream(Encoding.UTF8.GetBytes(json));
var pipeReader = PipeReader.Create(contentStream);
await foreach (var foo in ReadItemsAsync<Foo>(pipeReader, jsonOptions))
{
Console.WriteLine($"foo: {foo.Some}");
}
}
static async IAsyncEnumerable<TValue> ReadItemsAsync<TValue>(PipeReader pipeReader, JsonSerializerOptions jsonOptions = null)
{
while (true)
{
var result = await pipeReader.ReadAsync();
var buffer = result.Buffer;
bool isCompleted = result.IsCompleted;
SequencePosition bufferPosition = buffer.Start;
while (true)
{
var(value, advanceSequence) = TryReadNextItem<TValue>(buffer, ref bufferPosition, isCompleted, jsonOptions);
if (value != null)
{
yield return value;
}
if (advanceSequence)
{
pipeReader.AdvanceTo(bufferPosition, buffer.End); //advance our position in the pipe
break;
}
}
if (isCompleted)
yield break;
}
}
static (TValue, bool) TryReadNextItem<TValue>(ReadOnlySequence<byte> sequence, ref SequencePosition sequencePosition, bool isCompleted, JsonSerializerOptions jsonOptions)
{
var reader = new SequenceReader<byte>(sequence.Slice(sequencePosition));
while (!reader.End) // loop until we've come to the end or read an item
{
if (reader.TryReadToAny(out ReadOnlySpan<byte> itemBytes, NewLineChars, advancePastDelimiter: true))
{
sequencePosition = reader.Position;
if (itemBytes.TrimStart(WhiteSpaceChars).IsEmpty)
{
continue;
}
return (JsonSerializer.Deserialize<TValue>(itemBytes, jsonOptions), false);
}
else if (isCompleted)
{
// read last item
var remainingReader = sequence.Slice(reader.Position);
ReadOnlySpan<byte> remainingSpan = remainingReader.IsSingleSegment ? remainingReader.First.Span : remainingReader.ToArray();
reader.Advance(remainingReader.Length); // advance reader to the end
sequencePosition = reader.Position;
if (!remainingSpan.TrimStart(WhiteSpaceChars).IsEmpty)
{
return (JsonSerializer.Deserialize<TValue>(remainingSpan, jsonOptions), true);
}
else
{
return (default, true);
}
}
else
{
// no more items in sequence
break;
}
}
// PipeReader needs to read more
return (default, true);
}
}
public class Foo
{
public string Some
{
get;
set;
}
}
Run at https://dotnetfiddle.net/M5cNo1