问题
I want to convert a JSON response to an equivalent XML document but while doing so, I also want to preserve current date and time format along with the offset e.g., DateTime in JSON is "2019-10-25T07:00:00-05:00" and after conversion I want it to remain the same. But after conversion into XML, the DateTime value becomes "2019-10-25T08:00:00-04:00"
I tried to search about it in Microsoft docs but I didn't find my answer for the following questions:
- How to determine the time zone of a given date time string (e.g., "2019-10-25T07:00:00-05:00")?
- How can I convert a date time string (e.g., "2019-10-25T08:00:00-04:00") into a date time of the desired time-zone (e.g., into the time zone of "2019-10-25T07:00:00-05:00")
// C# Code Snippet
// Step 1: Reading JsonResponse from a file
string jsonString = System.IO.File.ReadAllText(@"C:\TestDateTimeConvertJSONResponse.txt");
// Step 2: Converting jsonString to XMLDoc
System.Xml.XmlDocument xmlDoc = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(jsonString);
Console.WriteLine();
Console.WriteLine("EQUIVALENT XML RESPONSE");
Console.WriteLine(xmlDoc.InnerXml);
Input JSON string:
{
"Flight": {
"FlightNumber": "747",
"Source": "JFK",
"Destination": "LAS",
"Status": "ON TIME",
"DepDateTime": "2019-10-25T07:00:00-05:00",
"Terminal": "2"
}
}
Expected:
<Flight>
<FlightNumber>747</FlightNumber>
<Source>JFK</Source>
<Destination>LAS</Destination>
<Status>ON TIME</Status>
<DepDateTime>2019-10-25T07:00:00-05:00</DepDateTime>
<Terminal>2</Terminal>
</Flight>
Actual:
<Flight>
<FlightNumber>747</FlightNumber>
<Source>JFK</Source>
<Destination>LAS</Destination>
<Status>ON TIME</Status>
<DepDateTime>2019-10-25T08:00:00-04:00</DepDateTime>
<Terminal>2</Terminal>
</Flight>
回答1:
Your problem is that Json.NET's automatic DateTime recognition recognizes that the string "2019-10-25T07:00:00-05:00"
is a valid ISO 8601 date and time and parses it to a DateTime -- which unfortunately does not have support for timezone specification. Thus the value gets converted (correctly) to the local timezone on your computer during deserialization and subsequently formatted as such in the XML.
To prevent this, you need to parse the JSON using DateParseHandling.None or DateParseHandling.DateTimeOffset, however JsonConvert.DeserializeXmlNode has no overload that allows this setting to be passed in. Thus you will need to create an extension method with the necessary argument:
public static partial class JsonExtensions
{
public static XmlDocument DeserializeXmlNode(string json, DateParseHandling dateParseHandling,
string deserializeRootElementName = null, bool writeArrayAttribute = false, bool encodeSpecialCharacters = false)
{
var settings = new JsonSerializerSettings
{
Converters =
{
new Newtonsoft.Json.Converters.XmlNodeConverter()
{
DeserializeRootElementName = deserializeRootElementName,
WriteArrayAttribute = writeArrayAttribute,
EncodeSpecialCharacters = encodeSpecialCharacters
}
},
DateParseHandling = dateParseHandling,
};
return JsonConvert.DeserializeObject<XmlDocument>(json, settings);
}
}
Then use it as follows:
var xmlDoc = JsonExtensions.DeserializeXmlNode(jsonString, DateParseHandling.None);
Note that both DateParseHandling.None
and DateParseHandling.DateTimeOffset
meet your needs, as the former disables ISO 8601 date recognition while the latter parses such strings into DateTimeOffset which does support time zone specification.
Incidentally, the equivalent method for those who prefer the newer XDocument is:
public static partial class JsonExtensions
{
public static XDocument DeserializeXNode(string json, DateParseHandling dateParseHandling,
string deserializeRootElementName = null, bool writeArrayAttribute = false, bool encodeSpecialCharacters = false)
{
var settings = new JsonSerializerSettings
{
Converters =
{
new Newtonsoft.Json.Converters.XmlNodeConverter()
{
DeserializeRootElementName = deserializeRootElementName,
WriteArrayAttribute = writeArrayAttribute,
EncodeSpecialCharacters = encodeSpecialCharacters
}
},
DateParseHandling = dateParseHandling,
};
return JsonConvert.DeserializeObject<XDocument>(json, settings);
}
}
Demo fiddle here.
回答2:
I would read the node as string and write it as a string. That's the only sure way.
Toy example solution JsonConvert.DefaultSetting
// Setting the default settings is the only way I know to affect settings
// for DeserializeXmlNode, there may be a better way
Newtonsoft.Json.JsonConvert.DefaultSettings =
() => new Newtonsoft.Json.JsonSerializerSettings() {
DateParseHandling = Newtonsoft.Json.DateParseHandling.None };
Beware! Changing Newtonsoft.Json.JsonConvert.DefaultSettings
can affect other parts of your solution!
Test
var json = @"
{
""Flight"": {
""FlightNumber"": ""747"",
""Source"": ""JFK"",
""Destination"": ""LAS"",
""Status"": ""ON TIME"",
""DepDateTime"": ""2019-10-25T07:00:00-05:00"",
""Terminal"": ""2""
}
}
";
Newtonsoft.Json.JsonConvert.DefaultSettings = () => new Newtonsoft.Json.JsonSerializerSettings() { DateParseHandling = Newtonsoft.Json.DateParseHandling.None };
System.Xml.XmlDocument xmlDoc = Newtonsoft.Json.JsonConvert.DeserializeXmlNode(json);
Console.WriteLine(xmlDoc.InnerXml);
Output
(...)<DepDateTime>2019-10-25T07:00:00-05:00</DepDateTime><Terminal>2</Terminal></Flight>
Output without setting the settings
(...)<DepDateTime>2019-10-25T22:00:00+10:00</DepDateTime><Terminal>2</Terminal></Flight>
来源:https://stackoverflow.com/questions/58530977/how-to-prevent-date-time-conversion-while-converting-a-json-string-to-xml-do