Подтвердить что ты не робот

Отступ XML при вводе XML-строки в XmlWriter

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

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

4b9b3361

Ответ 1

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

string xml = ExternalMethod();
XmlReader reader =  XmlReader.Create(new StringReader(xml));
xw.WriteNode(reader, true);

Ответ 2

Нельзя использовать XmlTextWriter, как указано в MSDN, где указано:

В .NET Framework версии 2.0 релиз, рекомендуемая практика для создания экземпляров XmlWriter с использованием метод XmlWriter.Create и Класс XmlWriterSettings. Это позволяет вы должны в полной мере воспользоваться всеми новые функции, представленные в этом выпуск. Для получения дополнительной информации см. Создание XML-писателей.

Вместо этого вы должны использовать XmlWriter.Create, чтобы получить своего автора. Затем вы можете использовать класс XmlWriterSettings, чтобы указать такие вещи, как отступ.

XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";

Update

Я думаю, вы можете просто использовать WriteNode. Вы берете строку xml и загружаете ее в XDocument или XmlReader, а затем используйте node, чтобы записать ее в свой XmlWriter.

Ответ 3

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

Ответ 4

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

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

Ответ 5

Я искал ответ на этот вопрос, но на 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

Ответ 6

Как насчет:

string xml = ExternalMethod();
var xd = XDocument.Parse(xml);
xd.WriteTo(xw);