我想将JSON响应转换为等效的XML文档,但同时我也想保留当前日期和时间格式以及偏移量,例如JSON中的DateTime为“ 2019-10-25T07:00:00 -05:00”,转换后我希望它保持不变。但是转换为XML后,DateTime值变为“ 2019-10-25T08:00:00-04:00”
我试图在Microsoft文档中进行搜索,但找不到以下问题的答案:
// 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);
输入JSON字符串:
{
"Flight": {
"FlightNumber": "747",
"Source": "JFK",
"Destination": "LAS",
"Status": "ON TIME",
"DepDateTime": "2019-10-25T07:00:00-05:00",
"Terminal": "2"
}
}
预期:
<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>
实际:
<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>
答案 0 :(得分:1)
您的问题是Json.NET的automatic DateTime
recognition识别出字符串"2019-10-25T07:00:00-05:00"
是有效的ISO 8601日期和时间,并将其解析为DateTime
-不幸的是,不支持时区规范。因此,该值会在反序列化过程中(正确)转换为计算机上的本地时区,并随后以XML格式进行格式化。
为防止这种情况,您需要使用DateParseHandling.None
or DateParseHandling.DateTimeOffset
来解析JSON,但是JsonConvert.DeserializeXmlNode
没有允许该设置传入的重载。因此,您将需要创建一个带有必要方法的扩展方法参数:
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);
}
}
然后按以下方式使用它:
var xmlDoc = JsonExtensions.DeserializeXmlNode(jsonString, DateParseHandling.None);
请注意,DateParseHandling.None
和DateParseHandling.DateTimeOffset
都可以满足您的需求,因为前者禁用ISO 8601日期识别,而后者将此类字符串解析为支持时区规范的DateTimeOffset
。
顺便说一下,对于喜欢较新的XDocument
的人来说,等效的方法是:
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);
}
}
演示小提琴here。
答案 1 :(得分:0)
我将节点读取为字符串并将其写入字符串。那是唯一确定的方法。
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 };
当心!更改Newtonsoft.Json.JsonConvert.DefaultSettings
可能会影响解决方案的其他部分!
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);
(...)<DepDateTime>2019-10-25T07:00:00-05:00</DepDateTime><Terminal>2</Terminal></Flight>
(...)<DepDateTime>2019-10-25T22:00:00+10:00</DepDateTime><Terminal>2</Terminal></Flight>