I'd like parse JSON string and use the token.Type property to detect values of type JTokenType.TimeSpan.
I can't work out how to express the TimeSpan in my input string, everything seems to be interpreted as JTokenType.String.
var timeSpanString = TimeSpan.FromHours(1).ToString();
testString = string.Format(#"{{""Value"": ""{0}"" }}", timeSpanString);
var statObject = JObject.Parse(testString);
JToken token = statObject["Value"];
var tokenValue = token.ToString();
var tokenType = token.Type; // JTokenType.String
I even tried:
JValue jValue = new JValue("test");
jValue.Value = TimeSpan.FromHours(1);
bool isTimeSpan = jValue.Type == JTokenType.TimeSpan; // true!
testString = string.Format(#"{{""Value"": ""{0}"" }}", jValue.Value);
var statObject = JObject.Parse(testString);
JToken token = statObject["Value"];
var tokenValue = token.ToString();
var tokenType = token.Type; // JTokenType.String
Which at least produces a JValue object of tokenType JTokenType.TimeSpan, but still shows up as a JTokenType.String when I parse it.
This works perfectly for DateTime objects.
How can I express the input string such that the parsed value type is JTokenType.TimeSpan ?
Based on what I've seen while using JSON.NET for a while now, you will never, with the default settings, parse a string and retrieve a token with type JTokenType.TimeSpan (same for some other types as well, such as Guid or Uri). I have a pretty good guess of why this is the case (based on my experience working a few years ago with the DataContractJsonSerializer).
Basically, it's a matter of how much information the parser can retrieve out of the input. JSON is a very simple syntax which only knows about numbers, boolean and strings (in addition to arrays and objects). Many CLR types don't have a native JSON type (Uri, DateTime, DateTimeOffset, TimeSpan, and so on), so when any JSON parser is reading the data, it will try to use the best match.
If you're deserializing the JSON string into a CLR data type, then the serializer has some additional information that it can use to disambiguate what a JSON string maps to - the type of the field / property that value is being deserialized to. However, when you're deserializing a JSON data to a JToken object graph, there's no additional information, and JSON.NET has to choose one type. The most natural type to deserialize a JSON string is, well, a CLR string.
But why do dates are deserialized correctly as JTokenType.Date? IIRC, the JSON.NET reader has a special code for dates (controlled by the DateParseHandling enumeration), which tries to match the parsed strings to some predefined formats (either ISO 8601 or the old Microsoft ASP.NET AJAX format), and if it finds a string which match it, it will read it as a DateTime (or DateTimeOffset) instead of a string. I don't know whether it's possible to extend that behavior to also support TimeSpan or other types, but I wouldn't be surprised, since the extensibility in JSON.NET is quite good.
If you are trying to parse a TimeSpan it needs to be surrounded in quotations:
'"12:00:00"'
If you serialize a TimeSpan and look at the string result it looks like:
"\"12:00:00\""
At least this worked for me using NewtonSoft.JsonConvert. The string in my DB "12:00:00" (including the quotes).
And using JsonConvert.DeserializeObject(dbString) returns fine.
Just ran into the same problem and was able to do it this way:
string json = "{ \"span\": \"00:00:15\"}";
JToken token = JToken.Parse(json);
TimeSpan span = token["span"].ToObject<TimeSpan>();
Related
I'm trying to learn c# Json.net and I want to create a JSON multiline string that includes string declarations, but the first curly bracket which is meant to be part of the JSON dictionary is including itself in the declaration. It errors me on the 'name', if anyone can please give me a solution that would be great.
here is the code.
string Name = "'Name'";
string Is_Airing = "True";
string Genre_One = "'Yes'";
string Genre_Two = "'No'";
string Json_String = $#"{
'Name': '{Name}',
'Is_Airing': {Is_Airing},
'Genres': [
'{Genre_One}',
'{Genre_Two}'
]
}";
If your heart is set on DIY, double up the brackets to escape {{, but you're really [doing a poor job of] reinventing the wheel compared to using a serializer and chucking something like an anonymous or proper type into it:
//newtonsoft
JsonConvert.SerializeObject(new {
Name, //gets name of property from name of variable
Is_Airing = MyIsAiringVariableName, //specifies name of property in anonymous type
Genres = new []{
Genre_One,
Genre_Two
}
});
'Name': '{Name}',
JSON uses double quotes, by the way.. And typically uses camelCase names. Usign a serializer will ensure better compliance with standard JSON ("be strict in what you send and liberal in what you accept")
For more control over how the output JSON appears, you set options on the serializer (such as passing Formatting.Indented as the second argument to SerializeObject), or decorate your properties with attributes
The Newtonsoft documentation is quite comprehensive and includes useful samples to get you going: https://www.newtonsoft.com/json/help/html/SerializeObject.htm
Is there a way to get the raw/original JSON value from a JToken?
The problem:
var data = JObject.Parse(#"{
""SimpleDate"":""2012-05-18T00:00:00Z"",
""PatternDate"":""2012-11-07T00:00:00Z""
}");
var value = data["SimpleDate"].Value<string>();
The value is now 05/18/2012 00:00:00 but I need the original string 2012-05-18T00:00:00Z.
Is there a way to get this original value? Also, I cannot change the way how the JObject is created (e.g. change settings), because it is passed as parameter into my class...
(Reference: The original NJsonSchema issue)
You cannot get the original string, date strings are recognized and converted to DateTime structs inside the JsonReader itself. You can see this if you do:
Console.WriteLine(((JValue)data["SimpleDate"]).Value.GetType()); // Prints System.DateTime
You can, however, extract the dates in ISO 8601 format by doing:
var value = JsonConvert.SerializeObject(data["SimpleDate"]);
// value is "2012-05-18T00:00:00Z"
This will always output a JValue in a JSON-appropriate string format. Since your original dates are in this format, this may meet your needs.
(Honestly, I'm surprised JValue.ToString() outputs dates in non-ISO format, given that JObject.ToString() does output contained dates in ISO format.)
If you were able to change you settings while reading your JObject, you could use JsonSerializerSettings.DateParseHandling = DateParseHandling.None to disable DateTime recognition:
var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };
var data = JsonConvert.DeserializeObject<JObject>(#"{
""SimpleDate"":""2012-05-18T00:00:00Z"",
""PatternDate"":""2012-11-07T00:00:00Z""
}", settings);
var value = data["SimpleDate"].Value<string>();
Debug.WriteLine(value); // Outputs 2012-05-18T00:00:00Z
There's no overload to JObject.Parse() that takes a JsonSerializerSettings, so use DeserializeObject. This setting eventually gets propagated to JsonReader.DateParseHandling.
Related Newtonsoft docs:
Json.NET interprets and modifies ISO dates when deserializing to JObject #862
Serializing Dates in JSON.
There's a solution I found in Json.NET Disable the deserialization on DateTime:
JsonReader reader = new JsonTextReader(new StringReader(j1.ToString()));
reader.DateParseHandling = DateParseHandling.None;
JObject o = JObject.Load(reader);
another approach - that would work - Regex
SimpleDate(?:.*):(?:.*?)\"([0-9|-]{1,}T[0-9|:]+Z)
it is a regex pattern to extract the data you look for - you just wanted the string, so here it is .
it is not the JSON parsing approach - but it indeed extracts the string.
here is a sample of how it works
Say I have a string representing an array of objects in JSON form:
string s = "[{\"name\":\"Person1\"},{\"name\":\"Person2\"}]";
What I want is an array of strings, each string being the string representation of a JSON object - NOT the object itself. It should look something like this:
string[] s = new string[]
{
"{\"name\":\"Person1\"}",
"{\"name\":\"Person2\"}"
};
1) Almost every search I attempt pulls up millions of results on how to simply deserialize a JSON string using (eg) Json.NET. This is not what I want to do.
2) I have tried building a class representing the objects to temporarily loop through a deserialize/serialize mapping each to a string in an array, but the schema for the objects is variable (hence why I only need a string representation).
3) I have attempted a few regex to try and do this, but my JSON string can contain fields that contain JSON strings as their value (icky, but out of my control) and so nested character escaping etc drove me partially mad before I decided to beg for help here.
Surely this should be simple? Anybody got any pointers?
You'll need to deserialize it, and then serialize each object independently.
For example (using Newtonsoft.Json):
string json = "[{\"name\":\"Person1\"},{\"name\":\"Person2\"}]";
var objects = JsonConvert.DeserializeObject<List<object>>(json);
var result = objects.Select(obj => JsonConvert.SerializeObject(obj)).ToArray();
Yields (as a string[]):
{"name":"Person1"}
{"name":"Person2"}
If you try to avoid deserializing and serializing, you're almost certain to run into an edge case that will break your code.
string s = "[{\"name\":\"Person1\"},{\"name\":\"Person2\"}]";
var Json = JsonConvert.DeserializeObject<List<object>>(s);
string[] Jsonn = Json.Select(x => x.ToString()).ToArray();
[] Jsonn returns string array instead of object array with JObject formatted.
Hope this one help you.
Why don't you just use this
string s = "[{\"name\":\"Person1\"},{\"name\":\"Person2\"}]";
string[] t = s.Split(',');
I tried it. It simply gives you string array as you want it....
Is there a way to get the raw/original JSON value from a JToken?
The problem:
var data = JObject.Parse(#"{
""SimpleDate"":""2012-05-18T00:00:00Z"",
""PatternDate"":""2012-11-07T00:00:00Z""
}");
var value = data["SimpleDate"].Value<string>();
The value is now 05/18/2012 00:00:00 but I need the original string 2012-05-18T00:00:00Z.
Is there a way to get this original value? Also, I cannot change the way how the JObject is created (e.g. change settings), because it is passed as parameter into my class...
(Reference: The original NJsonSchema issue)
You cannot get the original string, date strings are recognized and converted to DateTime structs inside the JsonReader itself. You can see this if you do:
Console.WriteLine(((JValue)data["SimpleDate"]).Value.GetType()); // Prints System.DateTime
You can, however, extract the dates in ISO 8601 format by doing:
var value = JsonConvert.SerializeObject(data["SimpleDate"]);
// value is "2012-05-18T00:00:00Z"
This will always output a JValue in a JSON-appropriate string format. Since your original dates are in this format, this may meet your needs.
(Honestly, I'm surprised JValue.ToString() outputs dates in non-ISO format, given that JObject.ToString() does output contained dates in ISO format.)
If you were able to change you settings while reading your JObject, you could use JsonSerializerSettings.DateParseHandling = DateParseHandling.None to disable DateTime recognition:
var settings = new JsonSerializerSettings { DateParseHandling = DateParseHandling.None };
var data = JsonConvert.DeserializeObject<JObject>(#"{
""SimpleDate"":""2012-05-18T00:00:00Z"",
""PatternDate"":""2012-11-07T00:00:00Z""
}", settings);
var value = data["SimpleDate"].Value<string>();
Debug.WriteLine(value); // Outputs 2012-05-18T00:00:00Z
There's no overload to JObject.Parse() that takes a JsonSerializerSettings, so use DeserializeObject. This setting eventually gets propagated to JsonReader.DateParseHandling.
Related Newtonsoft docs:
Json.NET interprets and modifies ISO dates when deserializing to JObject #862
Serializing Dates in JSON.
There's a solution I found in Json.NET Disable the deserialization on DateTime:
JsonReader reader = new JsonTextReader(new StringReader(j1.ToString()));
reader.DateParseHandling = DateParseHandling.None;
JObject o = JObject.Load(reader);
another approach - that would work - Regex
SimpleDate(?:.*):(?:.*?)\"([0-9|-]{1,}T[0-9|:]+Z)
it is a regex pattern to extract the data you look for - you just wanted the string, so here it is .
it is not the JSON parsing approach - but it indeed extracts the string.
here is a sample of how it works
I am converting from XML to JSON using SerializeXmlNode. Looks the expected behavior is to convert all XML values to strings, but I'd like to emit true numeric values where appropriate.
// Input: <Type>1</Type>
string json = JsonConvert.SerializeXmlNode(node, Newtonsoft.Json.Formatting.Indented, true);
// Output: "Type": "1"
// Desired: "Type": 1
Do I need to write a custom converter to do this, or is there a way to hook into the serialization process at the appropriate points, through delegates perhaps? Or, must I write my own custom JsonConverter class to manage the transition?
Regex Hack
Given the complexity of a proper solution, here is another (which I'm not entirely proud of, but it works...).
// Convert to JSON, and remove quotes around numbers
string json = JsonConvert.SerializeXmlNode(node, Newtonsoft.Json.Formatting.Indented, true);
// HACK to force integers as numbers, not strings.
Regex rgx = new Regex("\"(\\d+)\"");
json = rgx.Replace(json, "$1");
XML does not have a way to differentiate primitive types like JSON does. Therefore, when converting XML directly to JSON, Json.Net does not know what types the values should be, short of guessing. If it always assumed that values consisting only of digits were ordinal numbers, then things like postal codes and phone numbers with leading zeros would get mangled in the conversion. It is not surprising, then, that Json.Net takes the safe road and treats all values as string.
One way to work around this issue is to deserialize your XML to an intermediate object, then serialize that to JSON. Since the intermediate object has strongly typed properties, Json.Net knows what to output. Here is an example:
class Program
{
static void Main(string[] args)
{
string xml = #"<root><ordinal>1</ordinal><postal>02345</postal></root>";
XmlSerializer xs = new XmlSerializer(typeof(Intermediary));
using (TextReader reader = new StringReader(xml))
{
Intermediary obj = (Intermediary)xs.Deserialize(reader);
string json = JsonConvert.SerializeObject(obj , Formatting.Indented);
Console.WriteLine(json);
}
}
}
[XmlRoot("root")]
public class Intermediary
{
public int ordinal { get; set; }
public string postal { get; set; }
}
Output of the above:
{
"ordinal": 1,
"postal": "02345"
}
To make a more generic solution, yes, you'd have to write your own converter. In fact, the XML-to-JSON conversion that takes place when calling SerializeXmlNode is done using an XmlNodeConverter that ships with Json.Net. This converter itself does not appear to be very extensible, but you could always use its source code as a starting point to creating your own.