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



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

705   6  

6 ответов:

Как насчет использования 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.Создайте метод и Класс XmlWriterSettings. Это позволяет вы, чтобы в полной мере воспользоваться всеми преимуществами новые возможности, представленные в этом освобождать. Для получения дополнительной информации см. Создание XML-писателей.

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

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

Обновление

Я думаю, что вы можете просто использовать WriteNode. Вы берете свою xml-строку и загружаете ее в XDocument или XmlReader, а затем используете узел из этого, чтобы записать ее в свой 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 было несколько раздражающих атрибутов empty (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);

Comments

    Ничего не найдено.