Decimal values getting modify while parse string into JObject - c#

Input json
{
"ErrorMessage":"Transaction has been authorized successfully",
"ControlId":1000.00,
"Authorizations":[
{
"RMATranUUID":"1c1a88f7-d6cf-4ae8-87d3-ba06e9d9fe36",
"Payments":[
{
"PaymentNumber":"1",
"TotalPaymentsNumber":24,
"AmountDue":1000.0,
"AmountPaid":0.00
}
],
"Term":24,
"OTBReleaseAmount":null
},
{
"RMATranUUID":"b012ba9c-2dbd-4961-8959-ec0afbafbe13",
"OTBReleaseAmount":null
}
]
}
Output json, after parsing
JObject jsonPacket = JObject.Parse(inputString);
//Line no second changes 1000.00 to 1000.0
{
"ErrorMessage":"Transaction has been authorized successfully",
"ControlId":1000.0,
"Authorizations":[
{
"RMATranUUID":"1c1a88f7-d6cf-4ae8-87d3-ba06e9d9fe36",
"Payments":[
{
"PaymentNumber":"1",
"TotalPaymentsNumber":24,
"AmountDue":1000.0,
"AmountPaid":0.00
}
],
"Term":24,
"OTBReleaseAmount":null
},
{
"RMATranUUID":"b012ba9c-2dbd-4961-8959-ec0afbafbe13",
"OTBReleaseAmount":null
}
]
}

The reason is JObject at parsing doubles executes like this under the hood:
double data;
double.TryParse("1214.00", NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out data);
As data is of type double and double is floating point number, you didn't get the value you expect.
Either, you create a POCO and parse it into it, or you can do this:
string json = "{ \"ErrorMessage\":\"Transaction has been authorized successfully\", \"ControlId\":1000.00, \"Authorizations\":[ { \"RMATranUUID\":\"1c1a88f7-d6cf-4ae8-87d3-ba06e9d9fe36\", \"Payments\":[ { \"PaymentNumber\":\"1\", \"TotalPaymentsNumber\":24, \"AmountDue\":1000.0, \"AmountPaid\":0.00 } ], \"Term\":24, \"OTBReleaseAmount\":null }, { \"RMATranUUID\":\"b012ba9c-2dbd-4961-8959-ec0afbafbe13\", \"OTBReleaseAmount\":null } ]}";
var jsonReader = new JsonTextReader(new StringReader(json));
jsonReader.FloatParseHandling = FloatParseHandling.Decimal;
var jObject = JObject.Load(jsonReader);
Console.WriteLine(jObject["ControlId"].Value<decimal>()); // 1000.00
Console.WriteLine(jObject); // prints your actual json

Related

Remove Node From JSON dynamically in C#

I need to remove the nodes from the JSON dynamically in C# without knowing the actual path of the node in josn. Just using the value comes in the query parameter of URL remove the node and and return the json after removing the node.
public IHttpActionResult mockErrorCandidateResponse()
{
HttpContext currentContext = HttpContext.Current;
KeysCollection keys = currentContext.Request.QueryString.Keys;
string key = keys[0];
string node = currentContext.Request.QueryString[key];
//creating the final response
HttpResponseMessage result = new HttpResponseMessage();
result.StatusCode = HttpStatusCode.BadRequest;
string pathToContent = "~/mockCandidateResponse.json"; //relative path to fetch the file
string actualStrContent = null;
if (!String.IsNullOrEmpty(pathToContent))
{
actualStrContent = Util.getResource(pathToContent);
result.Content = new StringContent(actualStrContent, Encoding.UTF8, "application/json");
}
JObject data = JObject.Parse(actualStrContent); //parsing the json dynamically
data.SelectToken(node).Remove();
actualStrContent = data.ToString();
return ResponseMessage(result);
}
Here the sample JSON
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
When I query GET http://basecandidateurl.com?nodename=**GlossDiv** then it should remove everything under the
GlossDiv and return
{
"glossary": {
"title": "example glossary"}
}
Anyhelp is apprreciated. Thanks in advance!
This worked for me:
var json = #"{
'glossary': {
'title': 'example glossary',
'GlossDiv': {
'title': 'S',
'GlossList': {
'GlossEntry': {
'ID': 'SGML',
'SortAs': 'SGML',
'GlossTerm': 'Standard Generalized Markup Language',
'Acronym': 'SGML',
'Abbrev': 'ISO 8879:1986',
'GlossDef': {
'para': 'A meta-markup language, used to create markup languages such as DocBook.',
'GlossSeeAlso': ['GML', 'XML']
},
'GlossSee': 'markup'
}
}
}
}
}";
var nodeToRemove = "GlossDef";
// Step 01: Parse json text
JObject jo = JObject.Parse(json);
// Step 02: Find Token in JSON object
JToken tokenFound = jo.Descendants()
.Where(t => t.Type == JTokenType.Property && ((JProperty)t).Name == nodeToRemove)
.Select(p => ((JProperty)p).Value)
.FirstOrDefault();
// Step 03: if the token was found select it and then remove it
if (tokenFound != null)
{
var token = jo.SelectToken(tokenFound.Path);
token.Parent.Remove();
}
json = jo.ToString();
which returns the json string:
{
"glossary": {
"title": "example glossary"
}
}
I used the Json.Net library which you can nuget into your project by searching for Newtonsoft.Json

JObject in C# for independent data fetching of JSON

I am using Json.Net to parse my JSON
This is my JSON:
"OptionType": {
"C": [
"C",
"Call"
],
"P": [
"P",
"Put"
]
}
Before this step, when processed, as a result, I would get a value from any of this.
For example Option Type: Call
Whatever value I get, I need it to be transcodified according to the above JSON.
Example: Option Type: C
First of all your sample data is not a valid JSON. You need to wrap it to the curvy braces.
If your sample is a part of the JSON object, you can map OptionType to the Dictionary<string, List<string>>.
To find valid option you will need to iterate this dictionary like in the sample below:
var valueToCheck = "Call";
string type = null;
foreach (var kvp in optionTypes)
{
if (kvp.Value.Contains(valueToCheck))
{
type = kvp.Key;
break;
}
}
Same using JObject with fixed JSON data:
var json = #"{
""OptionType"":{
""C"": [
""C"",
""Call""
],
""P"": [
""P"",
""Put""
]
}
}";
var valueToCheck = "Call";
string type = null;
var ot = JObject.Parse(json);
var objectType = ot["OptionType"];
foreach (var token in objectType)
{
var prop = token.ToObject<JProperty>();
var key = prop.Name;
var values = prop.Value.ToObject<List<string>>();
if (values.Contains(valueToCheck))
{
type = key;
break;
}
}
Code is not perfect but it is just an idea what to do.
You need to iterate over properties of JObject and then search your option type and then replace your search option with its parent key.
This is custom function can do above task.
public static JObject GetJObject(JObject jObject, List<string> optionType)
{
foreach (var type in jObject["OptionType"])
{
var key = type.ToObject<JProperty>().Name;
var values = type.ToObject<JProperty>().Value.ToObject<List<string>>();
foreach (var option in optionType)
{
if (values.Contains(option))
{
int index = values.IndexOf(option);
values.RemoveAt(index);
values.Insert(index, key);
}
}
JToken jToken = JToken.FromObject(values);
jObject.SelectToken("OptionType." + key).Replace(jToken);
}
return jObject;
}
And you can use above custom function this like
string json = File.ReadAllText(#"Path to your json file");
JObject jObject = JObject.Parse(json);
List<string> optionType = new List<string> { "Call", "Put" };
JObject result = GetJObject(jObject, optionType);
Output:

Customizing the JSON received from Web API

I need to add one more node to Json string.
Following is the code from where I am reading the data.
var url = "https://xyz_12232_abc/0908978978979.json";
var sys = new WebClient();
var content = sys.DownloadString(url);
I received following output from above code:
{
"2312312312313":
{
"emailId":"abc#gmail.com",
"model":"XYZ001",
"phone":"+654784512547",
"userName":"User1"
},
"23456464512313":
{
"emailId":"abcd#gmail.com",
"model":"XYZ002",
"phone":"+98745114474",
"userName":"User2"
},
"45114512312313":
{
"emailId":"abcde#gmail.com",
"model":"XYZ3",
"phone":"+214784558741",
"userName":"User3"
}
}
But, I want this output like below:
{
"Records": [
{
"UID":"2312312312313":,
"emailId":"abc#gmail.com",
"model":"XYZ001",
"phone":"+654784512547",
"userName":"User1"
},
{
"UID":"23456464512313":,
"emailId":"abcd#gmail.com",
"model":"XYZ002",
"phone":"+98745114474",
"userName":"User2"
},
{
"UID":"45114512312313":,
"emailId":"abcde#gmail.com",
"model":"XYZ3",
"phone":"+214784558741",
"userName":"User3"
}
]
}
Now, how can it be achieved ?
You can use Json.NET to massage the data into your desired output:
var jsonStr = #"..."; // your JSON here
var obj = JsonConvert.DeserializeObject<Dictionary<string, JObject>>(jsonStr);
var formattedObj = new
{
Records = obj.Select(x =>
{
x.Value.AddFirst(new JProperty("UID", x.Key));
return x.Value;
})
};
// serialize back to JSON
var formattedJson = JsonConvert.SerializeObject(formattedObj);

JSON parsing takes way too long

I am using Newtonsoft JSON to parse some output from an API. However, the API result is nearly 2.5 MB, and parsing out the entire file just to find the data I need takes a long time. Here is a snippet of the API output:
{
"response": {
"success": 1,
"current_time": 1416085203,
"raw_usd_value": 0.2,
"usd_currency": "metal",
"usd_currency_index": 5002,
"items": {
"A Brush with Death": {
"defindex": [
30186
],
"prices": {
"6": {
"Tradable": {
"Craftable": [
{
"currency": "metal",
"value": 3,
"last_update": 1414184620,
"difference": -0.165
}
]
}
}
}
},
My code is supposed to find the only object that is a child of the items object with the number '5021' in the defindex array, and pull out the currency and value data. Here is the code I use to find the data:
dynamic result = Newtonsoft.Json.JsonConvert.DeserializeObject(priceFile);
int keyprice = 0;
foreach(var items in result.response.items){
foreach(var item in items){
string indexstr = item.defindex.ToString();
if (indexstr.Contains(defindex))
{
foreach(var price in item.prices){
foreach (var quality in price)
{
Console.WriteLine("{0} {1}", quality.Tradable.Craftable[0].value, quality.Tradable.Craftable[0].currency);
keyprice = quality.Tradable.Craftable[0].value;
return keyprice;
}
}
}
}
}
Ideally, the code should only take up to 10 seconds to run.
I would create an class for response object, and then use code similar to the following. I tested on a 2.8MB json file and it averaged about 1.2 second, also try using fastJSON (there is a nuget package) - it is the fastest parser I have found.
string fileName = #"c:\temp\json\yourfile.json";
string json;
using (StreamReader sr = new StreamReader(fileName))
{
json = sr.ReadToEnd();
}
response myResponse = fastJSON.JSON.ToObject<response>(json);
var item = myResponse.First(i => i.defindex == "5051");
foreach (var price in item.prices)
{
foreach (var quality in price)
{
Console.WriteLine("{0} {1}", quality.Tradable.Craftable[0].value, quality.Tradable.Craftable[0].currency);
keyprice = quality.Tradable.Craftable[0].value;
return keyprice;
}
}

Parsing through JSON in JSON.NET with unknown property names

I have some JSON Data which looks like this:
{
"response":{
"_token":"StringValue",
"code":"OK",
"user":{
"userid":"2630944",
"firstname":"John",
"lastname":"Doe",
"reference":"999999999",
"guid":"StringValue",
"domainid":"99999",
"username":"jdoe",
"email":"jdoe#jdoe.edu",
"passwordquestion":"",
"flags":"0",
"lastlogindate":"2013-02-05T17:54:06.31Z",
"creationdate":"2011-04-15T14:40:07.22Z",
"version":"3753",
"data":{
"aliasname":{
"$value":"John Doe"
},
"smsaddress":{
"$value":"5555555555#messaging.sprintpcs.com"
},
"blti":{
"hideemail":"false",
"hidefullname":"false"
},
"notify":{
"grades":{
"$value":"0"
},
"messages":{
"$value":"1"
}
},
"beta_component_courseplanexpress_1":{
"$value":"true"
}
}
}
}
I am using C# with JSON.NET to parse through the data. I've been able to sucessfully get data using this algorithm:
User MyUser = new User();
JToken data = JObject.Parse(json);
MyUser.FirstName = (string) data.SelectToken("response.user.firstname");
//The same for all the other properties.
The problem is with the data field. This field is based on user preferences mostly and data is only inserted as it is used. The fields are all custom and developers can put in as many as they want without restrictions. Essentially, it's all free form data. Also as you notice they can be nested really far with data.
I've tried to run:
MyUser.Data = JsonConvert.DeserializeObject<List<JToken>>((string) data.SelectToken("response.user.data");
which doesn't work.
How would you go about converting it to be used in a C# object?
You can access it via the JToken / JArray / JObject methods. For example, this will list all of the keys under the data:
public class StackOverflow_14714085
{
const string JSON = #"{
""response"": {
""_token"": ""StringValue"",
""code"": ""OK"",
""user"": {
""userid"": ""2630944"",
""firstname"": ""John"",
""lastname"": ""Doe"",
""reference"": ""999999999"",
""guid"": ""StringValue"",
""domainid"": ""99999"",
""username"": ""jdoe"",
""email"": ""jdoe#jdoe.edu"",
""passwordquestion"": """",
""flags"": ""0"",
""lastlogindate"": ""2013-02-05T17:54:06.31Z"",
""creationdate"": ""2011-04-15T14:40:07.22Z"",
""version"": ""3753"",
""data"": {
""aliasname"": {
""$value"": ""John Doe""
},
""smsaddress"": {
""$value"": ""5555555555#messaging.sprintpcs.com""
},
""blti"": {
""hideemail"": ""false"",
""hidefullname"": ""false""
},
""notify"": {
""grades"": {
""$value"": ""0""
},
""messages"": {
""$value"": ""1""
}
},
""beta_component_courseplanexpress_1"": {
""$value"": ""true""
}
}
}
}
}";
public static void Test()
{
var jo = JObject.Parse(JSON);
var data = (JObject)jo["response"]["user"]["data"];
foreach (var item in data)
{
Console.WriteLine("{0}: {1}", item.Key, item.Value);
}
}
}
Json.NET can actually parse to a dynamic if that is useful to you.
Which means you can do something like.
dynamic parsedObject = JsonConvert.DeserializeObject("{ test: \"text-value\" }");
parsedObject["test"]; // "text-value"
parsedObject.test; // "text-value"
parsedObject.notHere; // null
Edit: might be more suitable for you to iterate the values if you don't know what you are looking for though.
dynamic parsedObject = JsonConvert.DeserializeObject("{ test: { inner: \"text-value\" } }");
foreach (dynamic entry in parsedObject)
{
string name = entry.Name; // "test"
dynamic value = entry.Value; // { inner: "text-value" }
}

Categories