如何防止XmlSerializer杀死字符串中的换行符?

问题描述 投票:41回答:5

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

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
5个回答
61
投票

不是XmlSerializer,而是删除您的CR的XmlWriter。要保留它,我们必须让编写者将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编码为其字符实体。


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

}

1
投票

public class BinarySerialize其中T:new(){公共静态字符串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;

        }
    }

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

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
© www.soinside.com 2019 - 2024. All rights reserved.