Format the nested property serialized json - json.net

I have a CSV string, and one of it's column value is json serialized.
"Id,Name,Seo\r\n13,SpecialCollections,\"{\"\"SeoUrl\"\":\"\"special-collections\"\",\"\"SeoPageTitle\"\":null,\"\"SeoKeywords\"\":null,\"\"SeoDescription\"\":null}\"\r\n";
I'm using a combination of JSON.NET and ServiceStack.Text to serialize and deserialize my data from json-csv and vice versa.
So, with the above CSVinput, I first convert it to .NET object using ServiceStack.Text helper method
var obj= csvInput.FromCsv<List<dynamic>>();
and that gives me an output in a form of Dictionary<string,string> for each row of csv
1) {[Id, 13]}
2) {[Name, SpecialCollections]}
3) {[Seo, {"SeoUrl":"special-collections","SeoPageTitle":null,"SeoKeywords":null,"SeoDescription":null}]}
Then I serialized the above output with JSON.NET helper method and write in a file which looks like this
var serializedJson = JsonConvert
.SerializeObject(obj, Formatting.Indented);
Result
[
{
"Id": "13",
"Name": "SpecialCollections",
"Seo": "{\"SeoUrl\":\"special-collections\",\"SeoPageTitle\":null,\"SeoKeywords\":null,\"SeoDescription\":null}"
}
]
The issue is with nested property 'Seo', although it's value is serialized json but that is because it is string, JSON.NET treat as a string and doesn't format it. Anyway, I can obtain the below expected result?
Expected Result:
[
{
"Id": "13",
"Name": "SpecialCollections",
"Seo": {
"SeoUrl": "special-collections",
"SeoPageTitle": null,
"SeoKeywords": null,
"SeoDescription": null
}
}
]
Any help on this would be highly appreciated.

Since your "Seo" value is already a JSON string, you'll need to deserialize it into a temporary object (such as a JObject) then recombine it with the other key-value pairs into a new container and serialize that to get the final result you want. Here is a simple way to do that.
First, create a helper method which can determine whether a string value is JSON or not, and return a JToken from it.
public static JToken ToJToken(string s)
{
if (s == null)
return JValue.CreateNull();
// if the string is already JSON, parse it into a JObject (or JArray)
if ((s.StartsWith("{") && s.EndsWith("}")) || (s.StartsWith("[") && s.EndsWith("]")))
return JToken.Parse(s);
// otherwise create a JValue from the non-JSON string
return JToken.FromObject(s);
}
Then, convert your List<Dictionary<string, string>> into a JArray using the above helper method like this:
JArray ja = new JArray(
obj.Select(
dict => new JObject(
((Dictionary<string, string>)dict).Select(
kvp => new JProperty(kvp.Key, ToJToken(kvp.Value))
)
)
)
);
Now, to get the formatted JSON you can simply call ToString() on the JArray:
string json = ja.ToString();
Fiddle: https://dotnetfiddle.net/VDzGao

Related

Rest Assured - Json - How to create a Map<time,count> from below JSON response?

API response json donot have any array name, it only has elements as time and count.
How can I store time and count in a Map.
Below is below Response JSON:
[ { "_time": "2021-10-28T00:00:00", "count": 10030.0 }, { "_time": "2021-10-29T00:00:00", "count": 7776.0 } ]
I have tried creating two list for _time and count , then storing it in a Map.
JsonPath js = new JsonPath(res.asString());
List<Float> count = js.getList("count");
List<String> time = js.getList("_time");
Map<String,Float> map = new LinkedHashMap<String,Float>();
Iterator<String> keyIter = time.iterator();
Iterator<Float> valIter = count.iterator();
while (keyIter.hasNext() && valIter.hasNext()) {
map.put(keyIter.next(), valIter.next());
}
But is there any other optimized way to do so?
I use this way.
Step 1: Deserialize response to POJO
import lombok.Data;
#Data
public class TimeObject {
private String _time;
private double count;
}
List<TimeObject> timeObjects = JsonPath.with(res.asString()).getList("", TimeObject.class);
Step2: Use java stream to collect a Map.
Map<String, List<Double>> collect = timeObjects.stream()
.collect(groupingBy(TimeObject::get_time,
mapping(TimeObject::getCount, toList())));
System.out.println(collect);
//{2021-10-28T00:00:00=[10030.0], 2021-10-29T00:00:00=[7776.0]}

I want to return id from a json list.But it gave a error

Error:
Cannot deserialize the current JSON object (e.g. {\"name\":\"value\"}) into type 'System.Collections.Generic.List`1[System.Object]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.\r\nTo fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object.\r\nPath 'exception', line 1, position 13
MY code:
using (WebClient wc = new WebClient())
{
wc.QueryString.Add("wstoken", "49345fa96c58118326b874bxxxxxx");
wc.QueryString.Add("wsfunction", "core_user_create_users");
wc.QueryString.Add("moodlewsrestformat", "json");
wc.QueryString.Add("users[0][username]", member.uname);
wc.QueryString.Add("users[0][auth]", "manual");
wc.QueryString.Add("users[0][password]", member.password);
wc.QueryString.Add("users[0][firstname]", member.fname);
wc.QueryString.Add("users[0][lastname]", member.lname);
wc.QueryString.Add("users[0][email]", member.email);
wc.QueryString.Add("users[0][timezone]", member.timezone);
wc.QueryString.Add("users[0][description]", member.tag);//tag for group name
var response_data = wc.UploadValues(URI, "POST", wc.QueryString);
var response = Encoding.ASCII.GetString(response_data);
var k = JsonConvert.DeserializeObject<List<dynamic>>(response);
foreach (var a in k)
{
id = (a["id"]);
}
return id;
}
I want to return id from below output:
[{\"id\":38,\"username\":\"newuser30\"}]
I did this and it just worked for me:
string json = "[{\"id\":38,\"username\":\"newuser30\"}]";
dynamic [] stuff = JsonConvert.DeserializeObject<dynamic []>(json);
var id = stuff[0].id;

When converting Json to Bson Document fails to correctly convert date value

I am trying to convert Json Object to MongoDb BsonDocument, however after conversion date valued from Json object is converted to string instead of date. Following examples output BsonValueType as string.
Is there any way to correctly convert to Bson Date value?
var newObject = new JObject {
{ "name", "John" },
{ "age", 25 },
{ "registeredDate" , "2017-05-09T09:14:06+00:00"},
};
BsonDocument bsonObj = BsonDocument.Parse(newObject.ToString());
Console.WriteLine(bsonObj["registeredDate"].BsonType);
//Outputs String
This isn't too surprising, since your JSON object's registeredDate property has a string value to begin with (even though it contains a value that is formatted like an ISO date).
Try one of the following:
If you want to keep newObject as type JObject:
var newObject = new JObject
{
{ "name", "John" },
{ "age", 25 },
{ "registeredDate" , new JRaw(#"new ISODate(""2017-05-09T09:14:06+00:00"")") },
}; // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This gives MongoDB's BsonDocument.Parse a hint that the string value contains an ISO timestamp and should be converted as a date/time type.
If you're OK with using a (strongly-typed) anonymous C# type for newObject instead:
var newObject = new
{
name = "John",
age = 25,
registeredDate = DateTime.Parse("2017-05-09T09:14:06+00:00"),
};
BsonDocument bsonObj = BsonDocument.Parse(newObject.ToJson());
This completely takes Json.NET out of the loop and lets MongoDB do all the work.
I admit that I don't know whether these solutions are how things are supposed to be done. I don't know the involved libraries well enough to demonstrate other (and possibly better) options.

Returning Dictionary using webservice

I'm looking for a bit of help with populating a Dictionary using a csv file within a WebService however Im unable to return the results.
Im tring to seperate the dictionary into two seperate columns which seemingly works but I cannot return the values as there are two and not one.
Here is the code:
{
StreamReader streamReader = new StreamReader("T:/4 Year WBL/Applications Development/Coursework 2/2b/Coursework2bwebservice/abrev.csv");
[WebMethod]
public string Dictionary()
{
string line;
Dictionary<string, string> dictionary = new Dictionary<string,string>();
while ((line = streamReader.ReadLine()) !=null)
{
string[] columns = line.Split(',');
dictionary.Add(columns[0], columns[1]);
return dictionary;
}
}
I am getting the error "cannot implicitly convert type System.Collections.Generic.Dictionary<string,string to string>"
Any ideas would be great and thank you for your time.
public string Dictionary()
is returning the wrong signature. You need to return an actual dictionary:
public Dictionary<string, string> Dictionary()
Also, this
while ((line = streamReader.ReadLine()) !=null)
seems a bit hinky. You're also returning your dictionary inside the loop. Let's try instead:
line = streamReader.Readline();
while (line !=null)
{
string[] columns = line.Split(',');
dictionary.Add(columns[0], columns[1]);
line = streamReader.Readline();
}
return dictionary;
All that said, returning an actual dictionary object in a web method probably doesn't make much sense. What you really want is an XML-serialized dictionary or list. See here: https://www.google.com/search?q=return+dictionary+in+web+method for more information.

ASP.NET: How to check the value of a cached dictionary?

Not really sure how to do this but i can cache the dictionary like this:
Cache.Insert("CacheName", Dictionary)
need some direction. the dictionary is two string values taken from a database. The user will input a string and i need to compare it against the values in the cached dictionary.
In general you need to access the object from the cache, cast it, and the use the ContainsKey property. Here is an example:
First add the dictionary to the Cache:
IDictionary<string, string> testDict = new Dictionary<string, string>();
testDict.Add("Test", "test");
Cache.Insert("dict", testDict);
Then, when you need to do so, access the cached object and use it ContainsKey property to determine whether it contains the searched key or not.
var dict = Cache["dict"] as IDictionary<string, string>;
if (dict != null)
{
string testValue = "test";
if(dict.ContainsKey(testValue))
{
/* some logic here */
}
}
You can access the value the following way:
if (dict != null)
{
string testValue = "test";
if(dict.ContainsKey(testValue))
{
/* some logic here */
string value = dict[testValue];
}
}
You can get the dictionary out of the cache by writing
var dict = (Dictionary<X, Y>) cache["CacheName"];

Resources