【问题标题】:How to prevent "Date & Time" conversion while converting a json string to XML doc如何在将 json 字符串转换为 XML 文档时防止“日期和时间”转换
【发布时间】:2020-02-20 04:19:51
【问题描述】:

我想将 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>

【问题讨论】:

    标签: c# json xml json.net jsonconvert


    【解决方案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.

    【讨论】:

      【解决方案2】:

      我会将节点读取为字符串并将其写入字符串。这是唯一确定的方法。

      玩具示例解决方案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>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-06-04
        • 1970-01-01
        • 2011-09-08
        • 2017-02-22
        • 2018-02-19
        相关资源
        最近更新 更多