格式化XML字符串以打印友好的XML字符串


187

我有这样的XML字符串:

<?xml version='1.0'?><response><error code='1'> Success</error></response>

一个元素和另一个元素之间没有线条,因此很难阅读。我想要一个格式化上述字符串的函数:

<?xml version='1.0'?>
<response>
<error code='1'> Success</error>
</response> 

无需自己动手编写格式函数,是否有任何我可以立即使用的.Net库或代码段?


1
CMS的道具,问题是重复的stackoverflow.com/questions/203528
Spence

2
不能重复。那个具体说明XmlDocument哪些将取消对该问题的最高票数答案。
sirdank

Answers:


191

使用XmlTextWriter...

public static string PrintXML(string xml)
{
    string result = "";

    MemoryStream mStream = new MemoryStream();
    XmlTextWriter writer = new XmlTextWriter(mStream, Encoding.Unicode);
    XmlDocument document = new XmlDocument();

    try
    {
        // Load the XmlDocument with the XML.
        document.LoadXml(xml);

        writer.Formatting = Formatting.Indented;

        // Write the XML into a formatting XmlTextWriter
        document.WriteContentTo(writer);
        writer.Flush();
        mStream.Flush();

        // Have to rewind the MemoryStream in order to read
        // its contents.
        mStream.Position = 0;

        // Read MemoryStream contents into a StreamReader.
        StreamReader sReader = new StreamReader(mStream);

        // Extract the text from the StreamReader.
        string formattedXml = sReader.ReadToEnd();

        result = formattedXml;
    }
    catch (XmlException)
    {
        // Handle the exception
    }

    mStream.Close();
    writer.Close();

    return result;
}

7
如果您要处理的是旧版.NET Framework LINQ之前的代码,则此方法有效,但是另一个示例要干净得多。
Mike

8
为了澄清Mike的评论:.NET 3.5中引入了LINQ。因此,如果您使用的是.NET的旧版本(.NET 1、1.1、2或3.0),则必须使用此答案。但是,如果您使用的是.NET 3.5或更高版本,则Charles Prakash Dasari的答案要简单得多。
西蒙·图西

1
@SM Kamran我正在使用您的代码,但是在writer.Close();上出现类似{“无法访问封闭的Stream。”}的错误。请给出解决方案。
贾廷·加迪亚

@JatinGadhiya我遇到了同样的问题,我通过在定义流中使用{using block}解决了这个问题。这样,您无需手动关闭流,并且在到达using块的末尾时,流将自动关闭。
Vahid Farahmandian

323

您将不得不以某种方式解析内容...我发现使用LINQ是最简单的方法。同样,这完全取决于您的实际情况。这是一个使用LINQ格式化输入XML字符串的工作示例。

string FormatXml(string xml)
{
     try
     {
         XDocument doc = XDocument.Parse(xml);
         return doc.ToString();
     }
     catch (Exception)
     {
         // Handle and throw if fatal exception here; don't just ignore them
         return xml;
     }
 }

[为了简洁起见,省略了使用语句]


这会严格影响换行和缩进吗?我不希望任何其他更改,例如将“ 0”更改为“ 0.0”等。当所有空格都被剥离时,我希望剥离的结果字符串与剥离的输入字符串完全相同。
Radim Cernej 2015年

3
@radim是的。不会对实际数据进行任何更改。只有标签会被格式化和缩进。
Charles Prakash Dasari

2
我注意到它在UTF8上很好用,但是在Unicode XML文件内容上却不行。

1
@SteveWellens,您可以通过doc.Declaration.ToString() + doc.ToString()或通过使用doc.Save代替来访问声明doc.ToString。有关更多详细信息,请参见此链接
David French

1
建议包括名称空间,因为它可以防止用户不得不为其以前未曾使用过很多的类查找名称空间。使用System.Xml.Linq; 效果很好,谢谢!
Scott Moniz

61

来自kristopherjohnson的这一堆更好:

  1. 它也不需要XML文档头。
  2. 有更明确的例外
  3. 添加了额外的行为选项:OmitXmlDeclaration = true,NewLineOnAttributes = true
  4. 更少的代码行

    static string PrettyXml(string xml)
    {
        var stringBuilder = new StringBuilder();
    
        var element = XElement.Parse(xml);
    
        var settings = new XmlWriterSettings();
        settings.OmitXmlDeclaration = true;
        settings.Indent = true;
        settings.NewLineOnAttributes = true;
    
        using (var xmlWriter = XmlWriter.Create(stringBuilder, settings))
        {
            element.Save(xmlWriter);
        }
    
        return stringBuilder.ToString();
    }
    

Todd,您能否阐明“不需要XML文档头”的含义?我已经尝试过Charles Prakash Dasari的解决方案,并且只是传入了一个XML片段而没有xml声明(即<?xml version="1.0" encoding="UTF-8" ?>,顶部没有一行),并且运行良好。
西蒙·图西

3
与接受的答案相比。与Charles相比,这将具有更好的可配置性。但是我将来可能会自己使用Charlies方法,这样的可配置性将是很少见的要求。
2013年

1
这个更好又短得多
Alex Jolig 2015年

9

对我有用的简单解决方案:

        XmlDocument xmlDoc = new XmlDocument();
        StringWriter sw = new StringWriter();
        xmlDoc.LoadXml(rawStringXML);
        xmlDoc.Save(sw);
        String formattedXml = sw.ToString();

1
这将创建一个XML文件,其标题为<?xml version =“ 1.0” encoding =“ utf-16”?>。XmlSerializer未能解析此错误,错误为“没有Unicode字节顺序标记”。解决方法是删除encoding =“ utf-16”,请参阅:stackoverflow.com/questions/29915467/…
Declan Taylor

7

检查以下链接:如何漂亮地打印XML(不幸的是,该链接现在返回404 :()

链接中的方法将XML字符串作为参数,并返回格式正确(缩进)的XML字符串。

我只是从链接中复制了示例代码,以使此答案更全面,更方便。

public static String PrettyPrint(String XML)
{
    String Result = "";

    MemoryStream MS = new MemoryStream();
    XmlTextWriter W = new XmlTextWriter(MS, Encoding.Unicode);
    XmlDocument D   = new XmlDocument();

    try
    {
        // Load the XmlDocument with the XML.
        D.LoadXml(XML);

        W.Formatting = Formatting.Indented;

        // Write the XML into a formatting XmlTextWriter
        D.WriteContentTo(W);
        W.Flush();
        MS.Flush();

        // Have to rewind the MemoryStream in order to read
        // its contents.
        MS.Position = 0;

        // Read MemoryStream contents into a StreamReader.
        StreamReader SR = new StreamReader(MS);

        // Extract the text from the StreamReader.
        String FormattedXML = SR.ReadToEnd();

        Result = FormattedXML;
    }
    catch (XmlException)
    {
    }

    MS.Close();
    W.Close();

    return Result;
}

2
对我来说很棒,我只是将其作为字符串的扩展方法。那个网站也关闭了,所以最好您
抓住

1
重复的答案。@SM Kamran也发布了相同的答案。
Vahid Farahmandian

@VahidFarahmandian是的。我不能做太多,因为我比他早了1分钟发帖:)顺便说一句,我试图添加答案的来源,以赞扬博客的张贴者。不幸的是,该链接现在是打破:(。
Chansik林

与Charles(FormatXml)和Todd(PrettyXml)的答案相比,我最喜欢此答案,因为此答案不会使人脱颖而出<?xml...?>。这个答案得到了我最初的想法。唯一的负面影响是我更喜欢制表符,而不是本地使用的空格。我设定Indentation = 1IndentChar = '\t'得到我想要的。
莎拉·温伯格

@ CHICoder007感谢您对扩展方法的评论。你教我一些新东西。添加一个(this String XML)作品很棒。
莎拉·温伯格

4

我试过了:

internal static void IndentedNewWSDLString(string filePath)
{
    var xml = File.ReadAllText(filePath);
    XDocument doc = XDocument.Parse(xml);
    File.WriteAllText(filePath, doc.ToString());
}

它工作正常。


但这会删除顶部的<?xml?>标签
Juran

2

.NET 2.0忽略名称解析,并使用适当的资源处理,缩进,保留空白和自定义编码

public static string Beautify(System.Xml.XmlDocument doc)
{
    string strRetValue = null;
    System.Text.Encoding enc = System.Text.Encoding.UTF8;
    // enc = new System.Text.UTF8Encoding(false);

    System.Xml.XmlWriterSettings xmlWriterSettings = new System.Xml.XmlWriterSettings();
    xmlWriterSettings.Encoding = enc;
    xmlWriterSettings.Indent = true;
    xmlWriterSettings.IndentChars = "    ";
    xmlWriterSettings.NewLineChars = "\r\n";
    xmlWriterSettings.NewLineHandling = System.Xml.NewLineHandling.Replace;
    //xmlWriterSettings.OmitXmlDeclaration = true;
    xmlWriterSettings.ConformanceLevel = System.Xml.ConformanceLevel.Document;


    using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
    {
        using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(ms, xmlWriterSettings))
        {
            doc.Save(writer);
            writer.Flush();
            ms.Flush();

            writer.Close();
        } // End Using writer

        ms.Position = 0;
        using (System.IO.StreamReader sr = new System.IO.StreamReader(ms, enc))
        {
            // Extract the text from the StreamReader.
            strRetValue = sr.ReadToEnd();

            sr.Close();
        } // End Using sr

        ms.Close();
    } // End Using ms


    /*
    System.Text.StringBuilder sb = new System.Text.StringBuilder(); // Always yields UTF-16, no matter the set encoding
    using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(sb, settings))
    {
        doc.Save(writer);
        writer.Close();
    } // End Using writer
    strRetValue = sb.ToString();
    sb.Length = 0;
    sb = null;
    */

    xmlWriterSettings = null;
    return strRetValue;
} // End Function Beautify

用法:

System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
xmlDoc.XmlResolver = null;
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("C:\Test.svg");
string SVG = Beautify(xmlDoc);

1

使用UTF-8 XML声明可自定义的Pretty XML输出

以下类定义提供了一种简单的方法,该方法将输入XML字符串转换为xml声明为UTF-8的格式化输出XML。它支持XmlWriterSettings类提供的所有配置选项。

using System;
using System.Text;
using System.Xml;
using System.IO;

namespace CJBS.Demo
{
    /// <summary>
    /// Supports formatting for XML in a format that is easily human-readable.
    /// </summary>
    public static class PrettyXmlFormatter
    {

        /// <summary>
        /// Generates formatted UTF-8 XML for the content in the <paramref name="doc"/>
        /// </summary>
        /// <param name="doc">XmlDocument for which content will be returned as a formatted string</param>
        /// <returns>Formatted (indented) XML string</returns>
        public static string GetPrettyXml(XmlDocument doc)
        {
            // Configure how XML is to be formatted
            XmlWriterSettings settings = new XmlWriterSettings 
            {
                Indent = true
                , IndentChars = "  "
                , NewLineChars = System.Environment.NewLine
                , NewLineHandling = NewLineHandling.Replace
                //,NewLineOnAttributes = true
                //,OmitXmlDeclaration = false
            };

            // Use wrapper class that supports UTF-8 encoding
            StringWriterWithEncoding sw = new StringWriterWithEncoding(Encoding.UTF8);

            // Output formatted XML to StringWriter
            using (XmlWriter writer = XmlWriter.Create(sw, settings))
            {
                doc.Save(writer);
            }

            // Get formatted text from writer
            return sw.ToString();
        }



        /// <summary>
        /// Wrapper class around <see cref="StringWriter"/> that supports encoding.
        /// Attribution: http://stackoverflow.com/a/427737/3063884
        /// </summary>
        private sealed class StringWriterWithEncoding : StringWriter
        {
            private readonly Encoding encoding;

            /// <summary>
            /// Creates a new <see cref="PrettyXmlFormatter"/> with the specified encoding
            /// </summary>
            /// <param name="encoding"></param>
            public StringWriterWithEncoding(Encoding encoding)
            {
                this.encoding = encoding;
            }

            /// <summary>
            /// Encoding to use when dealing with text
            /// </summary>
            public override Encoding Encoding
            {
                get { return encoding; }
            }
        }
    }
}

进一步改进的可能性:

  • GetPrettyXml(XmlDocument doc, XmlWriterSettings settings)可以创建允许调用者自定义输出的其他方法。
  • GetPrettyXml(String rawXml)可以添加其他方法来支持解析原始文本,而不是让客户端使用XmlDocument。就我而言,我需要使用XmlDocument来操纵XML,因此没有添加它。

用法:

String myFormattedXml = null;
XmlDocument doc = new XmlDocument();
try
{
    doc.LoadXml(myRawXmlString);
    myFormattedXml = PrettyXmlFormatter.GetPrettyXml(doc);
}
catch(XmlException ex)
{
    // Failed to parse XML -- use original XML as formatted XML
    myFormattedXml = myRawXmlString;
}

0

如果您加载XMLDoc,我很确定.ToString()函数对此会造成重载。

但这是用于调试吗?像这样发送它的原因是占用更少的空间(即从XML中删除不必要的空格)。

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.