Какой самый простой способ получить отступ XML с разрывом строки из XmlDocument?
Когда я создаю XML с нуля с XmlDocument
, OuterXml
Свойство уже имеет все хорошо с отступами строки. Однако, если я позвоню LoadXml
в каком-то очень "сжатом" XML (без разрывов строк и отступов), тогда вывод OuterXml
остается таким. Так...
Каков самый простой способ получить изящный вывод XML из экземпляра XmlDocument
?
13 ответов
Основываясь на других ответах, я изучил 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();
}
Это немного больше кода, чем я ожидал, но он работает просто замечательно.
Как адаптировано из блога Эрики Эрли, это должно сделать это:
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
дочерний узел выдается следующее исключение:
Невозможно написать объявление 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:
Так как у меня был другой случай, когда кодировка была неправильной, я искал, как применить 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;
}
}
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:
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
При реализации предложений, размещенных здесь, у меня были проблемы с кодировкой текста. Кажется, кодировка 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 на диск с заданной кодировкой текста.
Если у вас есть строка 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();
}
Установка новой строки не обязательна. Символы отступа также имеют два пробела по умолчанию, поэтому я предпочел не устанавливать их.
using System;
using System.Xml;
using System.Xml.Linq;
class Program
{
static void Main()
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\Customers.xml");
/* another function of XDocument.Parse() is formatting XML code which gived as string: */
Console.WriteLine(XDocument.Parse(xmlDoc.InnerXml));
}
}
Установите для PreserveWhitespace значение true перед Load.
var document = new XmlDocument();
document.PreserveWhitespace = true;
document.Load(filename);