从XmlDocument用换行符缩进XML的最简单方法是什么?


105

当我从头开始构建XML时 XmlDocument,该OuterXml属性已经包含了所有带有换行符的缩进。但是,如果我调用LoadXml一些非常“压缩”的XML(没有换行或缩进),则OuterXml保持输出。所以...

从的实例获取美化的XML输出的最简单方法是什么 XmlDocument什么?

Answers:


209

根据其他答案,我研究XmlTextWriter并提出了以下帮助方法:

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

它的代码比我期望的要多,但它的工作方式只是桃花心木。


5
您甚至可以考虑将实用程序方法创建为XmlDocument类的扩展方法。
反对党

5
奇怪的是,对我来说,除了将xml标头的编码设置为UTF-16外,它什么都不做。足够奇怪的是,即使我明确设定,它也settings.Encoding = Encoding.UTF8;
会这样做

3
可以通过使用带有指定编码的MemoryStream+ StreamWriter而不是来解决编码问题StringBuilder,并使用来获取文本enc.GetString(memstream.GetBuffer(), 0, (int)memstream.Length);。但是,最终结果仍未格式化。我要从已经格式化的阅读文档开始吗?我只希望新节点也被格式化。
Nyerguds

2
我很想将修改"\r\n"Environment.Newline
法拉普

2
doc.PreserveWhitespace不应该设置为true。否则,如果它已经包含部分缩进,它将失败。
DJon大师19年

48

根据Erika Ehrli的博客改编而成,应该这样做:

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

10
在收盘using时,语句将自动关闭作家Dispose()被调用。
泰勒·李

3
对我来说,这只会缩进一行。我还有许多其他行没有缩进。
C约翰逊

40

甚至可以轻松访问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);
}

非常好!与公认的答案相比,竖起大拇指的好处是它不会产生XML注释,因此更适合XML片段
Umar Farooq Khawaja 2014年

3
奇怪的是,这从XML中删除了<?xml ...?><!DOCTYPE ...>。可以使用片段,但不需要完整的文档。
杰西·奇斯霍尔姆

这是对我有用的唯一方法。使用xmltextwriter的所有其他方法,Formatting = Formatting.Indented和XmlWriterSettings都不会重新格式化文本,但是此方法可以。
kexx

16

较短的扩展方法版本

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

这非常有效,并且不涉及在磁盘上创建不必要的文件
Zain Rizvi 2013年

13

如果正在针对XmlDocument已经包含XmlProcessingInstruction子节点的调用上述Beautify方法,则会引发以下异常:

无法编写XML声明。WriteStartDocument方法已经编写了它。

这是我对原始版本的修改后的版本,以消除该异常:

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

现在它对我有效,可能您需要扫描该XmlProcessingInstruction节点的所有子节点,而不仅仅是第一个节点?


2015年4月更新:

由于还有另一种编码错误的情况,因此我搜索了如何在没有BOM的情况下强制执行UTF-8。我找到了此博客文章,并基于它创建了一个函数:

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

如果将cdata节放在父节点内且在子节点前则不起作用
Sasha Bond

2
似乎不需要MemoryStream,至少在我这一边。在设置中,我设置了:Encoding = Encoding.UTF8OmitXmlDeclaration = true
DJ大师19年

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

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

下面的答案肯定可以做一些解释,但是对我有用,并且比其他解决方案简单得多。
CarlR 2015年

看来你需要组装进口system.link.XML这个工作在PS 3
CarlR

2

一种简单的方法是使用:

writer.WriteRaw(space_char);

像此示例代码一样,此代码是我用来使用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();

            }

        }

这样,您可以按照通常的方式添加制表符或换行符,即\ t或\ n


1

在实施此处发布的建议时,我在文本编码方面遇到了麻烦。似乎的编码已XmlWriterSettings被忽略,并且始终被流的编码所覆盖。当使用StringBuilder,这始终是C#内部使用的文本编码,即UTF-16。

所以这是一个也支持其他编码的版本。

重要说明:如果您的XMLDocument对象具有其格式,则格式将被完全忽略preserveWhitespace在加载文档时属性已启用,。这让我难过了一段时间,所以请确保不要启用它。

我的最终代码:

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

这将使用给定的文本编码将格式化的xml保存到磁盘。


1

如果您有XML字符串,而不是可以使用的文档,则可以通过以下方式实现:

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

基于公认答案的更简化方法:

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

无需设置新行。缩进字符也具有默认的两个空格,因此我也不想设置它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.