【问题标题】:How to keep XmlSerializer from killing NewLines in Strings?如何防止 XmlSerializer 杀死字符串中的 NewLines?
【发布时间】:2011-01-21 08:42:06
【问题描述】:

假设我有一个简单的类,其中只有一个成员一个字符串。

public class Abc
{
    private String text;

    public String Text
    {
        get { return this.text; }
        set { this.text = value; }
    }
}

现在,当我使用有问题的 XmlSerializer 对其进行序列化然后反序列化时,任何包含换行符('\r\n' 或 Environment.NewLine)的文本都将转换为 '\n'。

如何保留换行符?

【问题讨论】:

标签: c# .net xml-serialization


【解决方案1】:

不是 XmlSerializer 而是 XmlWriter 正在删除您的 CR。要保留它,我们必须让作者将 CR 转换为其字符实体 

XmlWriterSettings ws = new XmlWriterSettings();
ws.NewLineHandling = NewLineHandling.Entitize;

XmlSerializer ser = new XmlSerializer( typeof( Abc ) );
using (XmlWriter wr = XmlWriter.Create( "abc.xml", ws )) {
    ser.Serialize( wr, s );
}

这和DataContractSerializer一模一样:

var ser = new DataContractSerializer( typeof( Abc ) );
using (XmlWriter wr = XmlWriter.Create( "abc.xml", ws )) {
    ser.Serialize( wr, s );
}

为什么我们需要这样做?

这是因为兼容的 XML 解析器必须在解析之前将 CRLF 和任何没有跟随 LF 的 CR 转换为单个 LF。此行为在 XML 1.0 规范的 End-of-Line handling 部分中定义。

由于在解析之前发生这种情况,如果您希望 CR 存在于文档中,则需要将 CR 编码为其字符实体。

【讨论】:

  • 我认为回车是 不是
  • @Lachlan Roche 我遇到了这个解决方案,它是 XML 如何从文本字符串中去除 CR 的唯一答案之一。不过,我的问题是它发生在 Web 服务上,这是自动生成的用于构建 wsdl 的代码。我想知道你对如何解决这个问题有什么建议吗?
【解决方案2】:
public class SerializeAny<TF> where TF : new()
{
    public static TF Deserialize(string serializedData)
    {
        try
        {
            var xmlSerializer = new XmlSerializer(typeof(TF));
            TF collection;
            using (var xmlReader = new XmlTextReader(serializedData, XmlNodeType.Document, null))
            {
                collection = (TF)xmlSerializer.Deserialize(xmlReader);
            }
            return collection;
        }
        catch (Exception)
        {


        }

        return new TF();
    }


    public static TF DeserializeZip(string path)
    {
        try
        {
            var bytes = File.ReadAllBytes(path);

            string serializedData = Unzip(bytes);

            TF collection = Deserialize(serializedData);


            return collection;
        }
        catch (Exception)
        {


        }

        return new TF();
    }

    public static string Serialize(TF options)
    {
        var xml = "";

        try
        {
            var xmlSerializer = new XmlSerializer(typeof(TF));
            using (var stringWriter = new StringWriter())
            {
                xmlSerializer.Serialize(stringWriter, options);
                xml = stringWriter.ToString();
            }
        }
        catch (Exception ex)
        {

            return ex.Message;
        }



        return xml;
    }

    public static string SerializeZip(TF options, string path)
    {
        var xml = "";

        try
        {
            xml = Serialize(options);
            var zip = Zip(xml);
            File.WriteAllBytes(path, zip);
        }
        catch (Exception ex)
        {

            return ex.Message;
        }



        return xml;
    }



    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")]
    internal static String SerializeObject<T>(T obj, Encoding enc)
    {
        using (var ms = new MemoryStream())
        {
            var xmlWriterSettings = new System.Xml.XmlWriterSettings()
            {
                // If set to true XmlWriter would close MemoryStream automatically and using would then do double dispose
                // Code analysis does not understand that. That's why there is a suppress message.
                CloseOutput = false,
                Encoding = enc,
                OmitXmlDeclaration = false,
                Indent = true
            };
            using (var xw = XmlWriter.Create(ms, xmlWriterSettings))
            {
                var s = new XmlSerializer(typeof(T));
                s.Serialize(xw, obj);
            }

            return enc.GetString(ms.ToArray());
        }
    }

    private static void CopyTo(Stream src, Stream dest)
    {
        byte[] bytes = new byte[4096];

        int cnt;

        while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
        {
            dest.Write(bytes, 0, cnt);
        }
    }

    private static byte[] Zip(string str)
    {
        var bytes = Encoding.UTF8.GetBytes(str);

        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        {
            using (var gs = new GZipStream(mso, CompressionMode.Compress))
            {
                //msi.CopyTo(gs);
                CopyTo(msi, gs);
            }

            return mso.ToArray();
        }
    }

    private static string Unzip(byte[] bytes)
    {
        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        {
            using (var gs = new GZipStream(msi, CompressionMode.Decompress))
            {
                CopyTo(gs, mso);
            }

            return Encoding.UTF8.GetString(mso.ToArray());
        }
    }

}

【讨论】:

    【解决方案3】:

    公共类 BinarySerialize where T : new() { 公共静态字符串序列化(T选项,字符串路径) {

                var xml = "";
                try
                {
                    File.Delete(path);
                }
                catch (Exception)
                {
    
    
                }
    
                try
                {
                    using (var fs = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))
                    {
                        var bf = new BinaryFormatter();
    
    
                        bf.Serialize(fs, options);
                    }
    
    
                }
                catch (Exception ex)
                {
    
                    return ex.Message;
                }
    
    
    
                return xml;
    
    
    
    
    
            }
    
            public static T Deserialize(string path)
            {
                T filteroptions;
                using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
                {
                    var bf = new BinaryFormatter();
                    filteroptions = (T)bf.Deserialize(fs);
                }
                return filteroptions;
    
            }
        }
    

    【讨论】:

      【解决方案4】:

      使用此代码:

      public static FilterOptions Deserialize(string serializedData)
      {
          try
          {
              var xmlSerializer = new XmlSerializer(typeof(FilterOptions));
              var xmlReader = new XmlTextReader(serializedData,XmlNodeType.Document,null);
              var collection = (FilterOptions)xmlSerializer.Deserialize(xmlReader);
              return collection;
          }
          catch (Exception)
          {
      
      
          }
      
          return new FilterOptions();
      }
      

      【讨论】:

      • 今天你应该使用XmlReader 而不是XmlTextReader。您也可以使用前者来实现相同的目的。不过答案很好。
      • @nawfal:你能解释一下如何用 XmlReader 来做吗?
      • @KaiHartmann 您可以使用静态调用 XmlReader.Create 来获取 XmlReader 实例。
      • @nawfal:这个也保留回车吗?
      • @KaiHartmann 我现在无法证明这一点。请亲自尝试看看。
      【解决方案5】:

      不错的解决方案,Lachlan Roche!

      下面的函数(在 VB.NET 中)使用 StringWriter 返回字符串,而不是使用 XmlWriter 将结果写入文件。

        ''' <summary>
        ''' Exports the object data to an XML formatted string.
        ''' Maintains CR characters after deserialization.
        ''' The object must be serializable to work.
        ''' </summary>
      
        Public Function ExportObjectXml(ByVal obj As Object) As String
          If obj Is Nothing Then
            Return String.Empty
          End If
      
          Dim serializer As New XmlSerializer(obj.GetType)
          Dim settings As New XmlWriterSettings With {.NewLineHandling = NewLineHandling.Entitize}
      
          Using output As New StringWriter
            Using writer As XmlWriter = XmlWriter.Create(output, settings)
              serializer.Serialize(writer, obj)
              Return output.ToString
            End Using
          End Using
        End Function
      

      【讨论】:

        猜你喜欢
        • 2014-09-21
        • 1970-01-01
        • 2013-04-25
        • 2022-01-18
        • 2013-04-01
        • 2014-02-22
        • 2011-05-29
        • 2019-06-17
        • 1970-01-01
        相关资源
        最近更新 更多