2008-10-15 45 views

Respuesta

184

Sobre la base de las otras respuestas, miré en XmlTextWriter y se acercó con el siguiente método de ayuda:

static public string Beautify(this XmlDocument doc) 
{ 
    StringBuilder sb = new StringBuilder(); 
    XmlWriterSettings settings = new XmlWriterSettings 
    { 
     Indent = true, 
     IndentChars = " ", 
     NewLineChars = "\r\n", 
     NewLineHandling = NewLineHandling.Replace 
    }; 
    using (XmlWriter writer = XmlWriter.Create(sb, settings)) { 
     doc.Save(writer); 
    } 
    return sb.ToString(); 
} 

Es un código un poco más de lo que esperaba, pero funciona de maravilla.

+5

Incluso podría considerar crear su método de utilidad como un método de extensión para la clase XmlDocument. – Oppositional

+15

¿Qué tal un bloque 'using' alrededor de' XmlWriter'? Solo para estar 100% seguro ... –

+5

Por extraño que parezca, para mí esto no hace más que establecer la codificación del encabezado xml en UTF-16. Curiosamente, lo hace incluso si establezco explícitamente 'settings.Encoding = Encoding.UTF8;' – Nyerguds

44

Como una adaptación de Erika Ehrli's blog, esto debe hacerlo:

XmlDocument doc = new XmlDocument(); 
doc.LoadXml("<item><name>wrench</name></item>"); 
// Save the document to a file and auto-indent the output. 
using (XmlTextWriter writer = new XmlTextWriter("data.xml", null)) { 
    writer.Formatting = Formatting.Indented; 
    doc.Save(writer); 
} 
+3

Y luego no olvides 'writer.Close();' ;-) – Edward

+9

el cierre de la instrucción 'using' cerrará automáticamente el escritor cuando se llame a 'Dispose()'. –

+1

Para mí, esto solo sangra una línea. Todavía tengo docenas de otras líneas que no están sangradas. –

7
XmlTextWriter xw = new XmlTextWriter(writer); 
xw.Formatting = Formatting.Indented; 
10

Si el método anterior Embellecer está siendo llamado para una XmlDocument que ya contiene un nodo XmlProcessingInstruction niño se lanza la siguiente excepción:

No se puede escribir declaración XML. El método WriteStartDocument ya lo ha escrito .

Esta es mi versión modificada de la original para deshacerse de la excepción:

private static string beautify(
    XmlDocument doc) 
{ 
    var sb = new StringBuilder(); 
    var settings = 
     new XmlWriterSettings 
      { 
       Indent = true, 
       IndentChars = @" ", 
       NewLineChars = Environment.NewLine, 
       NewLineHandling = NewLineHandling.Replace, 
      }; 

    using (var writer = XmlWriter.Create(sb, settings)) 
    { 
     if (doc.ChildNodes[0] is XmlProcessingInstruction) 
     { 
      doc.RemoveChild(doc.ChildNodes[0]); 
     } 

     doc.Save(writer); 
     return sb.ToString(); 
    } 
} 

Funciona para mí ahora, probablemente, lo que se necesita para escanear todos los nodos hijos del nodo XmlProcessingInstruction, no solo el primero?


Update Abril 2015:

Como no tenía otro caso en el que la codificación estaba mal, me buscado cómo hacer cumplir UTF-8 sin BOM. He encontrado this blog post y creé una función basada en ella:

private static string beautify(string xml) 
{ 
    var doc = new XmlDocument(); 
    doc.LoadXml(xml); 

    var settings = new XmlWriterSettings 
    { 
     Indent = true, 
     IndentChars = "\t", 
     NewLineChars = Environment.NewLine, 
     NewLineHandling = NewLineHandling.Replace, 
     Encoding = new UTF8Encoding(false) 
    }; 

    using (var ms = new MemoryStream()) 
    using (var writer = XmlWriter.Create(ms, settings)) 
    { 
     doc.Save(writer); 
     var xmlString = Encoding.UTF8.GetString(ms.ToArray()); 
     return xmlString; 
    } 
} 
13

Un método de extensión más corta versión

public static string ToIndentedString(this XmlDocument doc) 
{ 
    var stringWriter = new StringWriter(new StringBuilder()); 
    var xmlTextWriter = new XmlTextWriter(stringWriter) {Formatting = Formatting.Indented}; 
    doc.Save(xmlTextWriter); 
    return stringWriter.ToString(); 
} 
+0

Esto funciona muy bien y no implica la creación de archivos innecesarios en el disco –

2

Una forma sencilla es utilizar:

writer.WriteRaw(space_char); 

Al igual que este código de ejemplo, este código es lo que utilicé para crear una estructura de vista de árbol usando XMLWriter:

private void generateXML(string filename) 
     { 
      using (XmlWriter writer = XmlWriter.Create(filename)) 
      { 
       writer.WriteStartDocument(); 
       //new line 
       writer.WriteRaw("\n"); 
       writer.WriteStartElement("treeitems"); 
       //new line 
       writer.WriteRaw("\n"); 
       foreach (RootItem root in roots) 
       { 
        //indent 
        writer.WriteRaw("\t"); 
        writer.WriteStartElement("treeitem"); 
        writer.WriteAttributeString("name", root.name); 
        writer.WriteAttributeString("uri", root.uri); 
        writer.WriteAttributeString("fontsize", root.fontsize); 
        writer.WriteAttributeString("icon", root.icon); 
        if (root.children.Count != 0) 
        { 
         foreach (ChildItem child in children) 
         { 
          //indent 
          writer.WriteRaw("\t"); 
          writer.WriteStartElement("treeitem"); 
          writer.WriteAttributeString("name", child.name); 
          writer.WriteAttributeString("uri", child.uri); 
          writer.WriteAttributeString("fontsize", child.fontsize); 
          writer.WriteAttributeString("icon", child.icon); 
          writer.WriteEndElement(); 
          //new line 
          writer.WriteRaw("\n"); 
         } 
        } 
        writer.WriteEndElement(); 
        //new line 
        writer.WriteRaw("\n"); 
       } 

       writer.WriteEndElement(); 
       writer.WriteEndDocument(); 

      } 

     } 

De esta forma puede agregar tabulaciones o saltos de línea de la manera en que normalmente está acostumbrado, es decir\ To \ n

34

O incluso más fácil si usted tiene acceso a LINQ

try 
{ 
    RequestPane.Text = System.Xml.Linq.XElement.Parse(RequestPane.Text).ToString(); 
} 
catch (System.Xml.XmlException xex) 
{ 
      displayException("Problem with formating text in Request Pane: ", xex); 
} 
+0

¡muy bonito! * thumbs up * ventaja sobre la respuesta aceptada es que no producirá un comentario XML, por lo que funciona mejor para un fragmento XML –

+3

Curiosamente, esto elimina el '' y el '' del XML. Aceptar para un fragmento, pero no es deseable para un documento completo. –

+0

Esta es la única manera que funcionó para mí. Todos los demás métodos que usan xmltextwriter, Formatting = Formatting.Indented y XmlWriterSettings NO reformatean el texto, pero este método sí lo hace. – kexx

1

Al aplicar las sugerencias incluidas en este documento, que tenían problemas con la codificación de texto. Parece que la codificación del XmlWriterSettings se ignora, y siempre se reemplaza por la codificación de la secuencia. Cuando se utiliza un StringBuilder, esta es siempre la codificación de texto utilizada internamente en C#, es decir, UTF-16.

Así que aquí hay una versión que también admite otras codificaciones.

NOTA IMPORTANTE: El formato se ignora por completo si su objeto XMLDocument tiene habilitada su propiedad al cargar el documento. Esto me dejó perplejo por un tiempo, así que asegúrate de no habilitar eso.

Mi código final:

public static void SaveFormattedXml(XmlDocument doc, String outputPath, Encoding encoding) 
{ 
    XmlWriterSettings settings = new XmlWriterSettings(); 
    settings.Indent = true; 
    settings.IndentChars = "\t"; 
    settings.NewLineChars = "\r\n"; 
    settings.NewLineHandling = NewLineHandling.Replace; 

    using (MemoryStream memstream = new MemoryStream()) 
    using (StreamWriter sr = new StreamWriter(memstream, encoding)) 
    using (XmlWriter writer = XmlWriter.Create(sr, settings)) 
    using (FileStream fileWriter = new FileStream(outputPath, FileMode.Create)) 
    { 
     if (doc.ChildNodes.Count > 0 && doc.ChildNodes[0] is XmlProcessingInstruction) 
      doc.RemoveChild(doc.ChildNodes[0]); 
     // save xml to XmlWriter made on encoding-specified text writer 
     doc.Save(writer); 
     // Flush the streams (not sure if this is really needed for pure mem operations) 
     writer.Flush(); 
     // Write the underlying stream of the XmlWriter to file. 
     fileWriter.Write(memstream.GetBuffer(), 0, (Int32)memstream.Length); 
    } 
} 

Esto ahorrará el formato XML en el disco, con la codificación de texto dado.

1

Si usted tiene una cadena de XML, en lugar de un documento listo para su uso, puede hacerlo de esta manera:

var xmlString = "<xml>...</xml>"; // Your original XML string that needs indenting. 
xmlString = this.PrettifyXml(xmlString); 

private string PrettifyXml(string xmlString) 
{ 
    var prettyXmlString = new StringBuilder(); 

    var xmlDoc = new XmlDocument(); 
    xmlDoc.LoadXml(xmlString); 

    var xmlSettings = new XmlWriterSettings() 
    { 
     Indent = true, 
     IndentChars = " ", 
     NewLineChars = "\r\n", 
     NewLineHandling = NewLineHandling.Replace 
    }; 

    using (XmlWriter writer = XmlWriter.Create(prettyXmlString, xmlSettings)) 
    { 
     xmlDoc.Save(writer); 
    } 

    return prettyXmlString.ToString(); 
} 
3
public static string FormatXml(string xml) 
    { 
     try 
     { 
      var doc = XDocument.Parse(xml); 
      return doc.ToString(); 
     } 
     catch (Exception) 
     { 
      return xml; 
     } 
    } 
+0

La respuesta a continuación definitivamente podría hacer con alguna explicación, sin embargo, funcionó para mí y es mucho más simple que las otras soluciones. – CarlR

+0

Parece que necesita importar el ensamblado system.link.XML para que esto funcione en la PS 3. – CarlR

1

Un enfoque más simplificado basado en la respuesta aceptada:

static public string Beautify(this XmlDocument doc) { 
    StringBuilder sb = new StringBuilder(); 
    XmlWriterSettings settings = new XmlWriterSettings 
    { 
     Indent = true 
    }; 

    using (XmlWriter writer = XmlWriter.Create(sb, settings)) { 
     doc.Save(writer); 
    } 

    return sb.ToString(); 
} 

No es necesario configurar la nueva línea. Los caracteres de sangría también tienen los dos espacios predeterminados, así que prefiero no configurarlo también.

Cuestiones relacionadas