Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep XmlSerializer from killing NewLines in Strings?

Suppose I have a simple Class with just one Member a String.

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

Now when I serialize and then deserialize it with the questionable XmlSerializer any text containing newlines ('\r\n' or Environment.NewLine) are transformed to '\n'.

How do I keep the newlines?

like image 469
Thomas Avatar asked Feb 26 '10 07:02

Thomas


People also ask

Is XmlSerializer thread safe?

4 Answers. Show activity on this post. This type is thread safe.

Can I make XmlSerializer ignore the namespace on Deserialization?

Yes, you can tell the XmlSerializer to ignore namespaces during de-serialization.

What is DataContractSerializer and how its different from XmlSerializer?

DataContractSerializer can able to serialize types that implements Idictionary whereas XML serializer not. DataContractSerializer serializes all members which are marked with [DataMember] attribute even if member is marked private. XML serializer serialize only public members.

How does the XmlSerializer work C#?

The XmlSerializer creates C# (. cs) files and compiles them into . dll files in the directory named by the TEMP environment variable; serialization occurs with those DLLs. These serialization assemblies can be generated in advance and signed by using the SGen.exe tool.


2 Answers

It is not the XmlSerializer but the XmlWriter which is removing your CR. To retain it we must have the writer convert CR to its character entity 
.

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

This is exactly the same with DataContractSerializer:

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

Why do we need to do this?

This is because compliant XML parsers must, before parsing, translate CRLF and any CR not followed by a LF to a single LF. This behavior is defined in the End-of-Line handling section of the XML 1.0 specification.

As this happens before parsing, you need to encode CR as its character entity if you want the CR to exist in the document.

like image 135
Lachlan Roche Avatar answered Sep 21 '22 11:09

Lachlan Roche


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());         }     }  } 
like image 36
user2757577 Avatar answered Sep 22 '22 11:09

user2757577