在将json字符串转换为XML文档时如何防止“日期和时间”转换

时间:2019-10-23 21:06:27

标签: c# json xml json.net jsonconvert

我想将JSON响应转换为等效的XML文档,但同时我也想保留当前日期和时间格式以及偏移量,例如JSON中的DateTime为“ 2019-10-25T07:00:00 -05:00”,转换后我希望它保持不变。但是转换为XML后,DateTime值变为“ 2019-10-25T08:00:00-04:00”

我试图在Microsoft文档中进行搜索,但找不到以下问题的答案:

  1. 如何确定给定日期时间字符串的时区(例如“ 2019-10-25T07:00:00-05:00”)?
  2. 如何将日期时间字符串(例如,“ 2019-10-25T08:00:00-04:00”)转换为所需时区的日期时间(例如,转换为“ 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);

输入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>

2 个答案:

答案 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.NoneDateParseHandling.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>