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

Posted

技术标签:

【中文标题】格式化 XML 字符串以打印友好的 XML 字符串【英文标题】:Format XML string to print friendly XML string 【发布时间】:2010-11-10 13:22:50 【问题描述】:

我有一个这样的 XML 字符串:

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

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

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

不用自己手动编写格式化函数,有没有什么.Net库或者代码sn-p可以随便用?

【问题讨论】:

props 到 CMS,问题是重复的 ***.com/questions/203528 不是重复的。那个指定了XmlDocument,这将取消对该问题投票最高的答案。 【参考方案1】:

您必须以某种方式解析内容……我发现使用 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 是的。不会对实际数据进行任何更改。只有标签会被格式化和缩进。 我注意到它适用于 UTF8,但不适用于 Unicode XML 文件内容。 @SteveWellens,您可以通过doc.Declaration.ToString() + doc.ToString() 或使用doc.Save 而不是doc.ToString 访问声明。有关详细信息,请参阅this link。 建议包括命名空间,因为它可以防止用户不得不去查找一个他们以前可能不经常使用的类的命名空间。使用 System.Xml.Linq;效果很好,谢谢!【参考方案2】:

使用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;

【讨论】:

如果您正在处理旧版本的 .NET 框架 pre-LINQ 上的代码,这很有效,但另一个示例更简洁。 澄清 Mike 的评论:LINQ 是在 .NET 3.5 中引入的。因此,如果您使用的 .NET 版本早于该版本(.NET 1、1.1、2 或 3.0),则必须使用此答案。但如果您使用的是 .NET 3.5 或更高版本,Charles Prakash Dasari 的答案要简单得多。 @SM Kamran 我正在使用您的代码,但在 writer.Close(); 上出现的错误看起来像 "Cannot access a closed Stream.";请给出解决方案。 @JatinGadhiya 我遇到了同样的问题,我通过在定义流时使用 using block 解决了这个问题。这样你就不需要手动关闭流,当到达 using 块的末尾时,流将自动关闭。【参考方案3】:

This one, from kristopherjohnson 更好:

    它也不需要 XML 文档标题。 有更清晰的异常 添加额外的行为选项:OmitXmlDeclaration = true, NewLineOnAttributes = true

    代码行数更少

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

【讨论】:

托德,你能澄清一下“不需要 XML 文档标题”的意思吗?我已经尝试过 Charles Prakash Dasari 的解决方案,只是传入了一个没有 xml 声明的 XML 片段(即顶部没有 &lt;?xml version="1.0" encoding="UTF-8" ?&gt; 行),它运行良好。 与接受的答案相比。与Charles相比,这个具有更好的可配置性。不过我自己以后可能会使用 Charlies 方法,这样的可配置性将是一个罕见的要求。 这个更好更短【参考方案4】:

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

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

【讨论】:

这将创建一个带有 作为其标题的 xml 文件。这不是由 XmlSerializer 解析的,错误是“没有 Unicode 字节顺序标记”。修复方法是删除 encoding="utf-16",参见:***.com/questions/29915467/…。【参考方案5】:

检查以下链接:How to pretty-print 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;

【讨论】:

对我来说很好用,我只是把它变成了字符串的扩展方法。那个网站也关闭了,所以你抢到一个副本真是太好了...... 重复答案。 @S M Kamran 也发布了相同的答案。 @VahidFarahmandian 是的。我对此无能为力,因为我比他早 1 分钟发布 :) 顺便说一句,我试图添加答案的来源,以将功劳归功于博客海报。不幸的是,链接现在被破坏了:(。 与 Charles (FormatXml) 和 Todd (PrettyXml) 的答案相比,我最喜欢这个答案,因为这个答案没有去掉 &lt;?xml...?&gt; 行。这个答案得到了我最初的想法。唯一的缺点是我更喜欢制表符而不是本机使用的空格。我设置了Indentation = 1IndentChar = '\t' 来得到我想要的。 @CHICoder007 感谢您对扩展方法的评论。你教会了我一些新东西。添加(this String XML) 效果很好。【参考方案6】:

我试过了:

internal static void IndentedNewWSDLString(string filePath)

    var xml = File.ReadAllText(filePath);
    XDocument doc = XDocument.Parse(xml);
    File.WriteAllText(filePath, doc.ToString());

一切正常。

【讨论】:

但这会删除顶部的 标记【参考方案7】:

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

【讨论】:

【参考方案8】:

带有 UTF-8 XML 声明的可自定义 Pretty XML 输出

以下类定义提供了一个简单的方法,用于将输入 XML 字符串转换为格式化的输出 XML,xml 声明为 UTF-8。它支持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://***.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;

【讨论】:

【参考方案9】:

查看以下链接:Format an XML file so it looks nice in C#

// Format the XML text.
StringWriter string_writer = new StringWriter();
XmlTextWriter xml_text_writer = new XmlTextWriter(string_writer);
xml_text_writer.Formatting = Formatting.Indented;
xml_document.WriteTo(xml_text_writer);

// Display the result.
txtResult.Text = string_writer.ToString();

【讨论】:

【参考方案10】:

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

但是这是为了调试吗?以这样的方式发送它的原因是占用更少的空间(即从 XML 中去除不必要的空白)。

【讨论】:

【参考方案11】:

可以通过带有XmlWriter.WriteNode(XmlReader, true)流转换 漂亮地打印XML 字符串。这个方法

将所有内容从读取器复制到写入器,并将读取器移动到下一个兄弟的开头。

定义以下扩展方法:

public static class XmlExtensions

    public static string FormatXml(this string xml, bool indent = true, bool newLineOnAttributes = false, string indentChars = "  ", ConformanceLevel conformanceLevel = ConformanceLevel.Document) => 
        xml.FormatXml( new XmlWriterSettings  Indent = indent, NewLineOnAttributes = newLineOnAttributes, IndentChars = indentChars, ConformanceLevel = conformanceLevel );

    public static string FormatXml(this string xml, XmlWriterSettings settings)
    
        using (var textReader = new StringReader(xml))
        using (var xmlReader = XmlReader.Create(textReader, new XmlReaderSettings  ConformanceLevel = settings.ConformanceLevel  ))
        using (var textWriter = new StringWriter())
        
            using (var xmlWriter = XmlWriter.Create(textWriter, settings))
                xmlWriter.WriteNode(xmlReader, true);
            return textWriter.ToString();
        
    

现在你可以做到:

var inXml = @"<?xml version='1.0'?><response><error code='1'> Success</error></response>";
var newXml = inXml.FormatXml(indentChars : "", newLineOnAttributes : false); // Or true, if you prefer
Console.WriteLine(newXml);

打印出来的

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

注意事项:

其他答案将 XML 加载到一些 Document Object Model 中,例如 XmlDocumentXDocument/XElement,然后在启用缩进的情况下重新序列化 DOM。

这种流式解决方案完全避免了 DOM 增加的内存开销。

在您的问题中,您没有为嵌套的&lt;error code='1'&gt; Success&lt;/error&gt; 节点添加任何缩进,所以我设置了indentChars : ""。通常每层嵌套缩进两个空格。

如果当前是单引号,属性分隔符将无条件地转换为双引号。 (我相信其他答案也是如此。)

传递 conformanceLevel : ConformanceLevel.Fragment 允许格式化包含 XML 片段序列的字符串。

除了ConformanceLevel.Fragment,输入的 XML 字符串必须格式正确。如果不是,XmlReader 会抛出异常。

演示小提琴here.

【讨论】:

【参考方案12】:

嗨,你为什么不试试这个:

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = false;
....
....
xmlDoc.Save(fileName);

PreserveWhitespace = false;该选项也可以用于 xml 美化器。

【讨论】:

请在您的回答中提供更多详细信息。正如目前所写的那样,很难理解您的解决方案。

以上是关于格式化 XML 字符串以打印友好的 XML 字符串的主要内容,如果未能解决你的问题,请参考以下文章

以 XML 格式格式化字符串并删除无效的属性字符

任务备忘:用python写一个格式化xml字符串的程序

XML 名称不能以“=”字符开头

Java WSDL以xml格式返回字符串

Java:以 XML 或 JSON 格式请求正文而不使用字符串

PHP(或其他 linux 友好)等效于 .Net System.Xml.Linq