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

当我使用XmlDocument从头开始构buildXML时, OuterXml属性已经具有用换行符OuterXml缩进的所有内容。 但是,如果我在一些非常“压缩的”XML(不换行或缩进)上调用LoadXml ,那么OuterXml的输出将保持这种状态。 所以…

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

基于其他的答案,我看着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(); } 

这是比我所希望的更多的代码,但它只是桃色。

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

如果您有权访问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); } 

较短的扩展方法版本

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

如果调用上述Beautify方法的XmlDocument已经包含XmlProcessingInstruction子节点,则会引发以下exception:

不能写入XML声明。 WriteStartDocument方法已经写入它。

这是我原来的修改版本来摆脱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(); } } 

它现在适用于我,可能你需要扫描XmlProcessingInstruction节点的所有子节点,而不是第一个?


2015年4月更新:

由于我有另外一个编码错误的案例,我search了如何在没有BOM的情况下执行UTF-8。 我发现这个博客文章,并创build了一个基于它的function:

 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; } } 
 XmlTextWriter xw = new XmlTextWriter(writer); xw.Formatting = Formatting.Indented; 
  public static string FormatXml(string xml) { try { var doc = XDocument.Parse(xml); return doc.ToString(); } catch (Exception) { return xml; } } 

一个简单的方法是使用:

 writer.WriteRaw(space_char); 

像这个示例代码一样,这个代码就是我用XMLWriter创build类似结构的树视图:

 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

在实施这里发布的build议时,我遇到了文本编码问题。 看来XmlWriterSettings的编码被忽略,并且总是被stream的编码覆盖。 当使用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保存到磁盘。

如果你有一串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(); } 

基于接受的答案的更简化的方法:

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

设置新行是没有必要的。 缩进字符也有默认的两个空格,所以我最好不要设置它。