2010-02-26 15 views
34

Załóżmy, że mam prostą klasę z jednym członkiem i ciągiem.Jak zabezpieczyć XmlSerializer przed zabijaniem nowych linii w łańcuchach?

public class Abc 
{ 
    private String text; 

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

Kiedy teraz serializacji i deserializowania to wątpliwej XmlSerializer dowolny tekst zawierający nowe linie ('\ r \ n' lub Environment.NewLine) przeprowadza się do '\ n'.

Jak zachować nowe linie?

+0

Ty serializować go gdzie? Jaki strumień lub autor tekstu? –

+0

Zrobiłem aplikację demo, aby pokazać mój problem: http://c0065612.cdn.cloudfiles.rackspacecloud.com/XmlDeSerTextBox.zip – Thomas

+0

Aplikacja pokazuje dwa pola tekstowe i przycisk. Po wprowadzeniu tekstu z podziałami linii w górnym polu tekstowym i naciśnięciu "Ok" XmlSerializer niszczy dla ciebie podziały wierszy. – Thomas

Odpowiedz

52

To nie XmlSerializer, ale XmlWriter usuwa CR. Aby go zachować, musimy przekonwertować CR na jego jednostkę znaków 
.

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

To jest dokładnie to samo z DataContractSerializer:

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

Dlaczego musimy to zrobić?

Dzieje się tak dlatego, że zgodne analizatory składni XML muszą, przed analizą, przetłumaczyć CRLF i dowolny CR, a nie LF na pojedynczy LF. To zachowanie jest zdefiniowane w sekcji End-of-Line handling specyfikacji XML 1.0.

Tak jak to się dzieje przed analizą, należy zakodować CR jako jego encję znaków, jeśli chcesz, aby CR istniała w dokumencie.

+0

Tak! To działa. Dziękuję Ci. – Thomas

+2

Myślę, że powrót karetki to nie – Juan

+0

@Lachlan Roche Znalazłem to rozwiązanie jako jedną z niewielu odpowiedzi na pytanie, jak XML usuwa CR z ciągu tekstowego. Mój problem polega jednak na tym, że dzieje się to za pośrednictwem usługi internetowej, kodu, który jest generowany automatycznie, aby zbudować wsdl. Zastanawiałem się, czy miałeś jakieś sugestie, jak rozwiązać problem? – htm11h

0

użyć tego kodu:

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

Dzisiaj należy używać 'XmlReader', a nie' XmlTextReader'. Możesz osiągnąć to samo używając byłego. Dobra odpowiedź. – nawfal

+0

Dobrze, czy mógłbyś wyjaśnić, co robi twój kod? –

+0

@nawfal: czy możesz wyjaśnić, jak to zrobić z XmlReader? –

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 gdzie T: new() { public static ciąg Serializować (opcje T, ścieżka string) {

  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; 

     } 
    } 
Powiązane problemy