Принуждение MSXML для форматирования вывода XML с отступами и переводами строки - PullRequest
4 голосов
/ 20 июня 2011

Я использую MSXML 3.0 с Visual Basic 6 для хранения и получения конфигурации моего приложения. При сохранении результирующего DOMDocument в файл XML корневой объект отображается в виде одной очень длинной строки текста:

<?xml version="1.0"?>
<!--WORKAPP 2011 Configuration file-->
<profile version="1.0"><frmPlan><left>300</left><top>300</top><width>24600</width><height>13575</height></frmPlan><preferences><text1/><text2/><text3/><background_color/><grid-major-step-x>50</grid-major-step-x><grid-major-step-y>50</grid-major-step-y></preferences></profile>

Можно ли заставить MSXML форматировать полученный XML-файл с отступами и переводами строки?

Ответы [ 4 ]

8 голосов
/ 20 июня 2011

Для таких крошечных файлов, как конфигурация, накладные расходы на использование XSL, вероятно, в любом случае незначительны. Сила SAX более важна, когда вы имеете дело с большими файлами или тоннами небольших, таких как серверная часть веб-службы, - и там вам, вероятно, не стоит использовать тяжеловесный DOM.

Private Sub FormatDocToFile(ByVal Doc As MSXML2.DOMDocument, _
                            ByVal FileName As String)
    'Reformats the DOMDocument "Doc" into an ADODB.Stream
    'and writes it to the specified file.
    '
    'Note the UTF-8 output never gets a BOM.  If we want one we
    'have to write it here explicitly after opening the Stream.
    Dim rdrDom As MSXML2.SAXXMLReader
    Dim stmFormatted As ADODB.Stream
    Dim wtrFormatted As MSXML2.MXXMLWriter

    Set stmFormatted = New ADODB.Stream
    With stmFormatted
        .Open
        .Type = adTypeBinary
        Set wtrFormatted = New MSXML2.MXXMLWriter
        With wtrFormatted
            .omitXMLDeclaration = False
            .standalone = True
            .byteOrderMark = False 'If not set (even to False) then
                                   '.encoding is ignored.
            .encoding = "utf-8"    'Even if .byteOrderMark = True
                                   'UTF-8 never gets a BOM.
            .indent = True
            .output = stmFormatted
            Set rdrDom = New MSXML2.SAXXMLReader
            With rdrDom
                Set .contentHandler = wtrFormatted
                Set .dtdHandler = wtrFormatted
                Set .errorHandler = wtrFormatted
                .putProperty "http://xml.org/sax/properties/lexical-handler", _
                             wtrFormatted
                .putProperty "http://xml.org/sax/properties/declaration-handler", _
                             wtrFormatted
                .parse Doc
            End With
        End With
        .SaveToFile FileName
        .Close
    End With
End Sub
3 голосов
/ 11 октября 2012

Возможно, этот ответ не поможет в вашем конкретном случае, но в целом он может быть полезен.Это касается случаев, когда документ загружается и сохраняется без особых изменений.DomDocument имеет свойство preserveWhitespace, которое изначально установлено на False.Если вы установите значение True до load, то оно будет сохранено с использованием того же отступа, что и исходный файл.

Чтобы добавить отступ вручную, можно создать текстовые узлы и вставить их для создания новых строк.и пробелы между элементами, как это:

Set txt = doc.createTextNode(vbCrLf & "  ")
Call node.parentNode.insertBefore(txt, node)
2 голосов
/ 20 июня 2011

Вы можете взглянуть на этот другой вопрос по SO и код ответов C ++.Но это слишком много работы.Вы говорите, что просто храните файл конфигурации.Поэтому используйте преобразование XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:strip-space elements="*"/>
  <xsl:output indent="yes"/>
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

Не забудьте вывести в ADODB.Stream , а не в DOM.Если вы выводите на DOM, сериализатор XSLT будет игнорироваться.

1 голос
/ 23 ноября 2013

Вот более короткая служебная функция отступа, которая работает с объектами и строками DOM в качестве входных данных и выводит отформатированную строку. Обработка файлов (utf-8) оставлена ​​вне его области. Не использует потоки ADODB и не нуждается в MSXML в ссылках на проект.

Public Function FormatXmlIndent(vDomOrString As Variant, sResult As String) As Boolean
    Dim oWriter         As Object ' MSXML2.MXXMLWriter

    On Error GoTo QH
    Set oWriter = CreateObject("MSXML2.MXXMLWriter")
    oWriter.omitXMLDeclaration = True
    oWriter.indent = True
    With CreateObject("MSXML2.SAXXMLReader")
        Set .contentHandler = oWriter
        '--- keep CDATA elements
        .putProperty "http://xml.org/sax/properties/lexical-handler", oWriter 
        .parse vDomOrString
    End With
    sResult = oWriter.output
    '--- success
    FormatXmlIndent = True
    Exit Function
QH:
End Function

Можно использовать вот так

    sXml = ReadTextFile("doc.xml")
    FormatXmlIndent sXml, sXml

... поэтому, если что-то не получается (недопустимый XML и т. Д.) sXml по-прежнему содержит исходный неотформатированный ввод.

...