Quel est le moyen le plus simple d'obtenir du XML en retrait avec des sauts de ligne à partir de XmlDocument?

Lorsque je construis XML à partir de zéro avec XmlDocument, la propriété OuterXml a déjà tout bien indenté avec des sauts de ligne. Cependant, si j'appelle LoadXml sur un XML très "compressé" (pas de sauts de ligne ou d'indentation), la sortie de OuterXml reste ainsi. Si ...

Quel est le moyen le plus simple d'obtenir une sortie XML embellie à partir d'une instance de XmlDocument?

94
demandé sur Neil C. Obremski 2008-10-15 06:25:59

11 réponses

Sur la base des autres réponses, j'ai regardé dans XmlTextWriter et suis venu avec la méthode d'aide suivante:

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

C'est un peu plus de code que ce que j'espérais, mais ça marche juste peachy.

188
répondu Neil C. Obremski 2015-01-22 08:53:45

Comme adapté du blogD'Erika Ehrli, cela devrait le faire:

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);
}
43
répondu DocMax 2015-04-14 16:56:29

Ou encore plus facile si vous avez accès à 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);
}
36
répondu JFK 2012-07-20 15:49:09

Une version de méthode d'extension plus courte

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();
}
15
répondu Jonathan Mitchem 2016-07-13 13:08:31

Si la méthode D'embellissement ci-dessus est appelée pour un XmlDocument qui contient déjà un nœud enfant XmlProcessingInstruction, l'exception suivante est levée:

Impossible d'écrire une déclaration XML. WriteStartDocument méthode a déjà écrit-il.

C'est ma version modifiée de l'original pour se débarrasser de l'exception:

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

Cela fonctionne pour moi maintenant, vous devrez probablement analyser tous les nœuds enfants pour le nœud XmlProcessingInstruction, pas seulement le premier un?


Mise À Jour Avril 2015:

Comme j'avais un autre cas où l'encodage était incorrect, j'ai cherché comment appliquer UTF-8 sans nomenclature. J'ai trouvé Ce billet de blog et créé une fonction basée sur celui-ci:

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;
    }
}
10
répondu Uwe Keim 2015-04-19 13:14:12
XmlTextWriter xw = new XmlTextWriter(writer);
xw.Formatting = Formatting.Indented;
7
répondu benPearce 2008-10-15 02:28:53
    public static string FormatXml(string xml)
    {
        try
        {
            var doc = XDocument.Parse(xml);
            return doc.ToString();
        }
        catch (Exception)
        {
            return xml;
        }
    }
4
répondu rewrew 2014-11-17 00:39:09

Un moyen simple est d'utiliser:

writer.WriteRaw(space_char);

Comme cet exemple de code, ce code est ce que j'ai utilisé pour créer une arborescence comme structure en utilisant 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 cette façon, vous pouvez ajouter des sauts de tabulation ou de ligne de la manière habituelle, c'est-à-dire \t ou \n

2
répondu Munim Dibosh 2012-07-09 13:30:38

Lors de la mise en œuvre des suggestions postées ici, j'ai eu des problèmes avec l'encodage du texte. Il semble que l'encodage du XmlWriterSettings soit ignoré, et toujours remplacé par l'encodage du flux. Lorsque vous utilisez un StringBuilder, c'est toujours le codage de texte utilisé en interne en C#, à savoir UTF-16.

Voici donc une version qui prend également en charge d'autres encodages.

REMARQUE IMPORTANTE: Le formatage est complètement ignoré si votre objet XMLDocument a sa propriété preserveWhitespace activée lors du chargement du document. Cela m'avait perplexe pendant un moment, alors assurez-vous de ne pas permettre que.

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

Cela permet d'enregistrer le xml formaté sur le disque, avec l'encodage de texte donné.

1
répondu Nyerguds 2014-12-06 17:48:39

Si vous avez une chaîne de XML, plutôt qu'un document prêt à l'emploi, vous pouvez le faire de cette façon:

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();
}
1
répondu theJerm 2015-03-05 22:00:26

Une approche plus simplifiée basée sur la réponse acceptée:

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

Il n'est pas nécessaire de définir la nouvelle ligne. Indent characters a également les deux espaces par défaut, donc j'ai préféré ne pas le définir aussi.

1
répondu visualjoel 2017-08-31 13:56:55