Ответ 1
Как использовать XmlReader для чтения xml в качестве узлов xml?
string xml = ExternalMethod();
XmlReader reader = XmlReader.Create(new StringReader(xml));
xw.WriteNode(reader, true);
У меня есть запись XmlTextWriter в файл и XmlWriter с использованием этого текстового редактора. Этот текстовый редактор настроен на вывод XML с записями с табуляцией:
XmlTextWriter xtw = new XmlTextWriter("foo.xml", Encoding.UTF8);
xtw.Formatting = Formatting.Indented;
xtw.IndentChar = '\t';
xtw.Indentation = 1;
XmlWriter xw = XmlWriter.Create(xtw);
Изменена ссылка для MSDN Джеффа:
XmlWriterSettings set = new XmlWriterSettings();
set.Indent = true;
set.IndentChars = "\t";
set.Encoding = Encoding.UTF8;
xw = XmlWriter.Create(f, set);
Это не изменяет конечный результат.
Теперь я произвольная глубина в своем XmlWriter, и я получаю строку XML из другого места (которую я не могу контролировать), который представляет собой однострочный, без отступа XML. Если я вызову xw.WriteRaw(), тогда эта строка будет введена дословно и не будет следовать моему отступу, который я хочу.
...
string xml = ExternalMethod();
xw.WriteRaw(xml);
...
По сути, мне нужен WriteRaw, который будет анализировать XML-строку и проходить через все WriteStartElement и т.д., чтобы она переформатировалась в соответствии с настройками XmlTextWriter.
Мое предпочтение - это способ сделать это с установкой, которую у меня уже есть, и сделать это, не перезагружая окончательный XML, чтобы переформатировать его. Я также предпочел бы не разбирать XML-строку с подобными XmlReader, а затем имитировать то, что она находит в моем XmlWriter (очень ручной процесс).
В конце этого я предпочел бы простое решение, чем тот, который следует моим предпочтениям. (Лучшее решение, естественно, было бы простым и следовать моим предпочтениям.)
Как использовать XmlReader для чтения xml в качестве узлов xml?
string xml = ExternalMethod();
XmlReader reader = XmlReader.Create(new StringReader(xml));
xw.WriteNode(reader, true);
Нельзя использовать XmlTextWriter
, как указано в MSDN, где указано:
В .NET Framework версии 2.0 релиз, рекомендуемая практика для создания экземпляров XmlWriter с использованием метод XmlWriter.Create и Класс XmlWriterSettings. Это позволяет вы должны в полной мере воспользоваться всеми новые функции, представленные в этом выпуск. Для получения дополнительной информации см. Создание XML-писателей.
Вместо этого вы должны использовать XmlWriter.Create, чтобы получить своего автора. Затем вы можете использовать класс XmlWriterSettings
, чтобы указать такие вещи, как отступ.
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
Я думаю, вы можете просто использовать WriteNode. Вы берете строку xml и загружаете ее в XDocument или XmlReader, а затем используйте node, чтобы записать ее в свой XmlWriter.
Это лучшее, что я получил до сих пор. Очень ручной процесс, который поддерживает только то, что написано. Мой строковый XML - это не что иное, как теги, атрибуты и текстовые данные. Если он поддерживает пространства имен, CDATA и т.д., Тогда это должно будет расти соответственно.
Очень ручная, очень грязная и очень склонная к ошибкам, но она выполняет мои настройки.
private static void PipeXMLIntoWriter(XmlWriter xw, string xml)
{
byte[] dat = new System.Text.UTF8Encoding().GetBytes(xml);
MemoryStream m = new MemoryStream();
m.Write(dat, 0, dat.Length);
m.Seek(0, SeekOrigin.Begin);
XmlReader r = XmlReader.Create(m);
while (r.Read())
{
switch (r.NodeType)
{
case XmlNodeType.Element:
xw.WriteStartElement(r.Name);
if (r.HasAttributes)
{
for (int i = 0; i < r.AttributeCount; i++)
{
r.MoveToAttribute(i);
xw.WriteAttributeString(r.Name, r.Value);
}
}
if (r.IsEmptyElement)
{
xw.WriteEndElement();
}
break;
case XmlNodeType.EndElement:
xw.WriteEndElement();
break;
case XmlNodeType.Text:
xw.WriteString(r.Value);
break;
default:
throw new Exception("Unrecognized node type: " + r.NodeType);
}
}
}
составляя ответы выше, я нашел, что это работает:
private static string FormatXML(string unformattedXml) {
// first read the xml ignoring whitespace
XmlReaderSettings readeroptions= new XmlReaderSettings {IgnoreWhitespace = true};
XmlReader reader = XmlReader.Create(new StringReader(unformattedXml),readeroptions);
// then write it out with indentation
StringBuilder sb = new StringBuilder();
XmlWriterSettings xmlSettingsWithIndentation = new XmlWriterSettings { Indent = true};
using (XmlWriter writer = XmlWriter.Create(sb, xmlSettingsWithIndentation)) {
writer.WriteNode(reader, true);
}
return sb.ToString();
}
Я искал ответ на этот вопрос, но на VB.net.
Благодаря Колину Бернетту я решил это. Я сделал две поправки: во-первых, XmlReader
должен игнорировать пробелы (settings.IgnoreWhiteSpaces
); во-вторых, читатель должен вернуться в элемент после чтения атрибутов. Ниже вы можете увидеть, как выглядит код.
Также я пробовал решение GreyCloud, но в сгенерированном XML были некоторые раздражающие атрибуты опустошений (xlmns).
Private Sub PipeXMLIntoWriter(xw As XmlWriter, xml As String)
Dim dat As Byte() = New System.Text.UTF8Encoding().GetBytes(xml)
Dim m As New MemoryStream()
m.Write(dat, 0, dat.Length)
m.Seek(0, SeekOrigin.Begin)
Dim settings As New XmlReaderSettings
settings.IgnoreWhitespace = True
settings.IgnoreComments = True
Dim r As XmlReader = XmlReader.Create(m, settings)
While r.Read()
Select Case r.NodeType
Case XmlNodeType.Element
xw.WriteStartElement(r.Name)
If r.HasAttributes Then
For i As Integer = 0 To r.AttributeCount - 1
r.MoveToAttribute(i)
xw.WriteAttributeString(r.Name, r.Value)
Next
r.MoveToElement()
End If
If r.IsEmptyElement Then
xw.WriteEndElement()
End If
Exit Select
Case XmlNodeType.EndElement
xw.WriteEndElement()
Exit Select
Case XmlNodeType.Text
xw.WriteString(r.Value)
Exit Select
Case Else
Throw New Exception("Unrecognized node type: " + r.NodeType)
End Select
End While
End Sub
Как насчет:
string xml = ExternalMethod();
var xd = XDocument.Parse(xml);
xd.WriteTo(xw);