如何防止XmlSerializer在字符串中杀死NewLines?

时间:2010-02-26 07:55:14

标签: c# .net xml-serialization

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

public class Abc
{
    private String text;

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

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

如何保留换行符?

5 个答案:

答案 0 :(得分:56)

不是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编码为其字符实体。

答案 1 :(得分: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());
        }
    }

}

答案 2 :(得分:1)

public class BinarySerialize其中T:new()         {             public static string Serialize(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;

        }
    }

答案 3 :(得分:0)

使用此代码:

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();
}

答案 4 :(得分:0)

很好的解决方案,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
相关问题