2009-04-10 12 views
51

¿Hay alguna manera fácil de hacer que DataContractSerializer escuche XML formateado en lugar de una cadena larga? No quiero cambiar las etiquetas o el contenido de ninguna manera, solo tiene que agregar saltos de línea y sangría para hacer que el XML sea más legible.Formateo de XML creado por DataContractSerializer

<tagA> 
    <tagB>This is</tagB> 
    <tagC>Much</tagC> 
    <tagD> 
     <tagE>easier to read</tagE> 
    </tagD> 
</tagA> 


<tagA><tagB>This is</tagB><tagC>Much</tagC><tagD><tagE>harder to read</tagE></tagD></tagA> 
+0

Se ha retrasado un poco, pero he agregado una actualización a mi publicación. – bendewey

Respuesta

83

Como dice bendewey, XmlWriterSettings es lo que necesita, por ejemplo algo así como

var ds = new DataContractSerializer(typeof(Foo)); 

var settings = new XmlWriterSettings { Indent = true }; 

using (var w = XmlWriter.Create("fooOutput.xml", settings)) 
    ds.WriteObject(w, someFoos); 
19

Echa un vistazo a la propiedad Indent de la actualización de XmlWriterSettings

: Aquí es un buen enlace de MSDN en How to: Specify the Output format on the XmlWriter

Además, a continuación se muestra un ejemplo:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var Mark = new Person() 
     { 
      Name = "Mark", 
      Email = "[email protected]" 
     }; 

     var serializer = new DataContractSerializer(typeof(Person)); 

     var settings = new XmlWriterSettings() 
     { 
      Indent = true, 
      IndentChars = "\t" 
     }; 

     using (var writer = XmlWriter.Create(Console.Out, settings)) 
     { 
      serializer.WriteObject(writer, Mark); 
     } 
     Console.ReadLine(); 
    } 
} 
public class Person 
{ 
    public string Name { get; set; } 
    public string Email { get; set; } 
} 
2
public static string SerializeEntity<T>(T source) 
    { 
     using (MemoryStream ms = new MemoryStream()) 
     { 

       NetDataContractSerializer serializer = new NetDataContractSerializer(); 
       serializer.Serialize(ms, source); 
       return System.Text.Encoding.ASCII.GetString(ms.ToArray()); 

     } 
    } 

    public static T DeSerializeEntity<T>(string xml) 
    { 
     using (MemoryStream ms = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(xml))) 
     { 
       NetDataContractSerializer serializer = new NetDataContractSerializer(); 
       return (T)serializer.Deserialize(ms); 
     } 
    } 
+5

¿No debería ser UTF8, no ASCII? –

7

Tenga cuidado sobre el ajuste de los espacios en blanco en los documentos XML! Ajustar el espacio en blanco hará que el XML sea más legible para nosotros los humanos, pero puede interferir con el análisis de la máquina.

De acuerdo con XML standard, el espacio en blanco es significativo por defecto. En otras palabras, en lo que respecta a XML, espacio en blanco es contenido.

Si introduce su XML bien formateado en un objeto de documento XML, obtendrá un resultado diferente que la versión que no tiene espacios ni saltos de línea. Obtendrá nodos de texto adicionales agregados a la versión que se ha formateado.

Este artículo de MSDN en XML White Space tiene varios ejemplos que muestran cuán difícil puede ser el espacio en blanco.

Si está formateando el XML solo para consumo humano, no importa. Pero si intentas pasar el documento formateado, podrías tener problemas.

Dado que uno de los principales beneficios de usar DataContractSerializer es la capacidad de serializar objetos y deserializar XML perfectamente, generalmente es mejor dejar solo el feo resultado.

Normalmente pego la salida en NotePad ++ y ejecuto una macro XML-tidy sobre ella cuando quiero leerla para depuración.

+0

Acceso directo para NotePad ++ una macro XML-tidy ver http://stackoverflow.com/questions/8170740/reindent-xml-via-keyboard-shortcut –

+0

El espacio en blanco que se produce en los elementos "externos" no es un espacio en blanco significativo; se vuelve complicado según el modelo de contenido (por ejemplo, elemento versus contenido mixto) y, con seguridad, el espacio en blanco dentro de un elemento o atributo _es_ significativo, ¡por lo que no se aplica indentación al contenido de elemento de varias líneas!Me parece que 'DataContractSerializer' no tiene problemas para deserializar documentos" sangrados "de su propia creación. –

0

según las otras muestras publicadas aquí que usan XmlWriter, aquí hay una versión (de http://ClipFlair.codeplex.com) que funciona con streams (y biblioteca Ionic.Zip en específico) y también muestra cómo es el código cuando no aplica el formateo (utilizando la compilación condicional - simplemente comente el #define para hacer que escriba un XML sin formato)

#define WRITE_FORMATTED_XML 

using System.Xml; 

namespace ClipFlair.Windows 
{ 

    public partial class BaseWindow : FloatingWindow 
    { 

    //... 

    #if WRITE_FORMATTED_XML 
    private static XmlWriterSettings XML_WRITER_SETTINGS = new XmlWriterSettings() { Indent=true, IndentChars=" "}; 
    #endif 

    //... 

    public virtual void SaveOptions(ZipFile zip, string zipFolder = "") //THIS IS THE CORE SAVING LOGIC 
    { 
     if (SavingOptions != null) SavingOptions(this, null); //notify any listeners 

     View.Busy = true; 
     try 
     { 
     ZipEntry optionsXML = zip.AddEntry(zipFolder + "/" + View.GetType().FullName + ".options.xml", 
      new WriteDelegate((entryName, stream) => 
      { 
      DataContractSerializer serializer = new DataContractSerializer(View.GetType()); //assuming current View isn't null 
      #if WRITE_FORMATTED_XML 
      using (XmlWriter writer = XmlWriter.Create(stream, XML_WRITER_SETTINGS)) 
       serializer.WriteObject(writer, View); 
      #else 
      serializer.WriteObject(stream, View); 
      #endif 
      })); 
     } 
     catch (Exception e) 
     { 
     MessageBox.Show("ClipFlair options save failed: " + e.Message); //TODO: find the parent window 
     } 
     finally 
     { 
     View.Busy = false; //in any case (error or not) clear the Busy flag 
     } 

     if (SavedOptions != null) SavedOptions(this, null); //notify any listeners 
    } 

    //... 

    } 

} 
Cuestiones relacionadas