Отступ XML при вставке строки XML в XmlWriter - PullRequest
18 голосов
/ 13 мая 2009

У меня есть 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 (очень очень ручной процесс).

В конце этого я предпочел бы простое решение, чем то, которое следует моим предпочтениям. (Естественно, лучшее решение было бы простым и соответствовало бы моим предпочтениям.)

Ответы [ 6 ]

30 голосов
/ 13 мая 2009

Как насчет использования XmlReader для чтения XML как узлов XML?

string xml = ExternalMethod();
XmlReader reader =  XmlReader.Create(new StringReader(xml));
xw.WriteNode(reader, true);
3 голосов
/ 13 мая 2009

Не следует использовать 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, а затем используете этот узел, чтобы записать ее в свой XmlWriter.

2 голосов
/ 10 августа 2011

Составляя ответы выше, я нашел это работает:

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();
}
2 голосов
/ 13 мая 2009

Это лучшее, что у меня есть. Очень ручной процесс, который поддерживает только то, что написано. Моя строка 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);
        }
    }
}
1 голос
/ 26 сентября 2012

Я искал ответ на этот вопрос, но в 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
0 голосов
/ 31 октября 2010

Как насчет:

string xml = ExternalMethod();
var xd = XDocument.Parse(xml);
xd.WriteTo(xw);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...