【问题标题】:C# XML Serializer cannot deserialize Celsius Degree SignC# XML Serializer 无法反序列化摄氏度符号
【发布时间】:2020-08-07 10:50:15
【问题描述】:

我有一堆需要反序列化并存储在数据库中的 xml 文件。 我发现了一个出色的 XML 反序列化器的通用实现。唯一不方便的是我无法反序列化摄氏度符号。

以下 XML 示例包含摄氏度符号,我无法对其进行反序列化:

<pt>
          <ch>1</ch>
          <type>Analog</type>
          <chtype>Temperature</chtype>
          <chunits>°C</chunits>
          <time>2020-05-03 22:10:00</time>
          <value>0</value>
        </pt>

或

 <pt>
          <ch>5</ch>
          <type>Analog</type>
          <chtype>Wind Direction</chtype>
          <chunits>°</chunits>
          <time>2020-05-03 22:10:00</time>
          <value>0</value>
        </pt>

我的反序列化器实现如下:

public class XmlConvert
    {
        public static string SerializeObject<T>(T dataObject)
        {
            if (dataObject == null)
            {
                return string.Empty;
            }
            try
            {
                using (StringWriter stringWriter = new System.IO.StringWriter())
                {
                    var serializer = new XmlSerializer(typeof(T));
                    serializer.Serialize(stringWriter, dataObject);
                    return stringWriter.ToString();
                }
            }
            catch (Exception ex)
            {
                return string.Empty;
            }
        }

        public static T DeserializeObject<T>(string xml)
            where T : new()
        {
            if (string.IsNullOrEmpty(xml))
            {
                return new T();
            }
            try
            {
                using (var stringReader = new StringReader(xml))
                {
                    var serializer = new XmlSerializer(typeof(T));
                    return (T)serializer.Deserialize(stringReader);
                }
            }
            catch (Exception ex)
            {
                return new T();
            }
        }
    }

我用来转换的类如下:

  /// <summary>
    /// Container for a single data point.
    /// </summary>
    public class MessageDataPoint
    {
        /// <summary>
        /// Channel number for data point.
        /// </summary>
        [System.Xml.Serialization.XmlElement("ch")]
        public string Ch { get; set; }

        /// <summary>
        /// Point type (Analog, Flow)
        /// </summary>
        [System.Xml.Serialization.XmlElement("type")]
        public string Type { get; set; }

        /// <summary>
        /// 
        /// </summary>
        [System.Xml.Serialization.XmlElement("chtype")]
        public string ChType { get; set; }

        /// <summary>
        /// Channel units
        /// </summary>
        [System.Xml.Serialization.XmlElement("chunits")]
        public string ChUnits { get; set; }

        /// <summary>
        /// Point timestamp. 
        /// </summary>
        [System.Xml.Serialization.XmlElement("time")]
        public string Time { get; set; }

        [System.Xml.Serialization.XmlIgnore]
        public DateTime? TimeParsed
        {
            get
            {
                DateTime.TryParse(Time, CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt);
                return dt;
            }
            private set { }
        }

        /// <summary>
        /// Channel Value
        /// </summary>
        [System.Xml.Serialization.XmlElement("value")]
        public string Value { get; set; }

    }

反序列化器实现如下:

 public async Task<string> GetFileAsStream(string key)
 {
            
 var content = string.Empty;
            
try
{
   GetObjectRequest request = new GetObjectRequest
                {
                    BucketName = bucketName,
                    Key = key
                };

   using (GetObjectResponse response = await client.GetObjectAsync(request))
   {
    using (StreamReader reader = new StreamReader(response.ResponseStream))
    {
        content = await reader.ReadToEndAsync();
                        
        var logger = XmlConvert.DeserializeObject<Logger>(content);

        // code removed for brevity
     }
  }
 }
}

结果如下:

<pt>
          <ch>1</ch>
          <type>Analog</type>
          <chtype>Temperature</chtype>
          <chunits>�C</chunits>
          <time>2020-05-03 22:10:00</time>
          <value>0</value>
        </pt>
        <pt>
          <ch>2</ch>
          <type>Analog</type>
          <chtype>Wind Chill</chtype>
          <chunits>�C</chunits>
          <time>2020-05-03 22:10:00</time>
          <value>0</value>
        </pt>

有什么想法吗?

这是一个示例文件:

<?xml version="1.0" encoding="ISO-8859-15"?>
<logger>
   <id>111111</id>
   <mobileNumber>12345676</mobileNumber>
   <serialNumber>01404</serialNumber>
   <siteName>abcdef</siteName>
   <siteId>abcdef</siteId>
   <maintenanceflag>False</maintenanceflag>
   <messages>
     <message>
       <id>123456789</id>
       <number>123456</number>
       <dateReceived>2020-05-04 00:02:25.0</dateReceived>
       <dateCredited>2020-05-04 00:02:25.0</dateCredited>
       <message>        <siteId>abcdef</siteId>
        <type>data</type>
        <RST>2020-01-18 08:50:00</RST>
        <RTC>2020-05-03 23:02:24</RTC>
        <DST>2020-05-03 22:00:00</DST>
        <mode>0</mode>
        <SR>600</SR>
        <pt>
          <ch>1</ch>
          <type>Analog</type>
          <chtype>Temperature</chtype>
          <chunits>°C</chunits>
          <time>2020-05-03 23:00:00</time>
          <value>0</value>
        </pt>
      
        <pt>
          <ch>5</ch>
          <type>Analog</type>
          <chtype>Wind Direction</chtype>
          <chunits>°</chunits>
          <time>2020-05-03 23:00:00</time>
          <value>0</value>
        </pt>
     
     
      </message>
       <format>BINARY</format>
       <source>FTP</source>
       <batteryCondition>123</batteryCondition>
       <signalStrength>12</signalStrength>
    </message>
  </messages>
</logger>

【问题讨论】:

  • 您遇到的错误是什么?
  • 您是否拥有正确的字符集和 XML 文档类型以使“°”符号成为有效字符?
  • 嗨,亚历山大。感谢您调查它。我没有收到任何错误。我在 xml 上有这个编码
  • StreamReader 不做编码检测,其编码默认为UTF-8。您最好的选择可能是将文件作为 ascii 读取,从 "&lt;?xml" 部分直到第一次遇到 '&gt;',从中取出 encoding= 位,然后使用它来解析带有 StreamReader 的整个文件。
  • 实际上,由于您是从 Stream 开始的...首先将整个内容作为字节接收。这将使对内容进行任何类型的检测变得更加容易。

标签: c# xml deserialization special-characters


【解决方案1】:

将流提供给序列化程序。这将大大简化代码。
此外,您可以完全删除您的 XmlConvert 类。

using (GetObjectResponse response = await client.GetObjectAsync(request))
using (var stream = response.ResponseStream)
{
    var serializer = new XmlSerializer(typeof(Logger));
    var logger = (Logger)serializer.DeserializeObject(stream);
}

但如果你认为XmlConvert 类是必要的,例如它做了一些额外的工作,那么至少在其中使用Stream 而不是string。

public static T DeserializeObject<T>(Stream stream)
    where T : new()
{
    try
    {
        var serializer = new XmlSerializer(typeof(T));
        return (T)serializer.Deserialize(stream);
    }
    catch (Exception ex)
    {
        return new T();
    }
}

【讨论】:

  • 感谢亚历山大·彼得罗夫。我现在就试试。
【解决方案2】:

我通过查看 Stackoverflow 上的以下帖子找到了解决方案

Using .NET how to convert ISO 8859-1 encoded text files that contain Latin-1 accented characters to UTF-8

感谢 Nyerguds 和 Alexander Haas 为我指明了正确的方向

我的解决方案是

public async Task<string> GetFileAsStream(string key)
 {
            
 var content = string.Empty;
            
try
{
   GetObjectRequest request = new GetObjectRequest
                {
                    BucketName = bucketName,
                    Key = key
                };

   using (GetObjectResponse response = await client.GetObjectAsync(request))
   {
    using (StreamReader reader = new StreamReader(response.ResponseStream, Encoding.GetEncoding("iso-8859-1")))
    {
        content = await reader.ReadToEndAsync();
                        
        var logger = XmlConvert.DeserializeObject<Logger>(content);

        // code removed for brevity
     }
  }
 }
}

【讨论】:

  • 欢迎提供解决方案链接,但请确保您的答案在没有它的情况下有用:add context around the link 这样您的其他用户就会知道它是什么以及为什么会出现,然后引用最相关的您链接到的页面的一部分,以防目标页面不可用。 Answers that are little more than a link may be deleted.
  • 您不需要在文本编码之间进行转换。您只需要确保首先使用 xml 标头中设置的编码对其进行解释。
  • 感谢@Daniil 的反馈。我已按照您的建议更新了答案
猜你喜欢
  • 2023-03-03
  • 1970-01-01
  • 2015-12-21
  • 1970-01-01
  • 1970-01-01
  • 2011-03-19
  • 1970-01-01
  • 1970-01-01
  • 2013-08-30
相关资源
最近更新 更多