Существует ли инструмент командной строки таблицы стилей или Windows для управляемого форматирования XML, конкретно помещая атрибуты one-per-line?

Я ищу XSLT или инструмент командной строки (или код C#, который может быть превращен в инструмент командной строки, и т.д.) для Windows, который сделает симпатичную печать XML. А именно, я хочу тот, который имеет способность поместить атрибуты one-to-a-line, что-то как:

<Node>
   <ChildNode 
      value1='5'
      value2='6'
      value3='happy' />
</Node>

Это не должно быть ТОЧНО похожим на это, но я хочу использовать его для XML-файла, который имеет узлы с десятками атрибутов, и распространение их через несколько строк делает их легче считать, отредактировать, и различный текстом

Примечание: Я думаю, что мое предпочтительное решение является листом XSLT, я могу пройти через метод C#, хотя инструмент командной строки Windows хорош также.

13
задан Scott Stafford 12 April 2010 в 21:35
поделиться

7 ответов

Вот небольшой пример на C#, который может быть использован непосредственно в вашем коде или встроен в exe и вызван из командной строки как "myexe from.xml to.xml":

    using System.Xml;

    static void Main(string[] args)
    {
        XmlWriterSettings settings = new XmlWriterSettings {
            NewLineHandling = NewLineHandling.Entitize,
            NewLineOnAttributes = true, Indent = true, IndentChars = "  ",
            NewLineChars = Environment.NewLine
        };

        using (XmlReader reader = XmlReader.Create(args[0]))
        using (XmlWriter writer = XmlWriter.Create(args[1], settings)) {
            writer.WriteNode(reader, false);
            writer.Close();
        }
    }

Пример ввода:

<Node><ChildNode value1='5' value2='6' value3='happy' /></Node>

Пример вывода (обратите внимание, что вы можете удалить с помощью settings.OmitXmlDeclaration):

<?xml version="1.0" encoding="utf-8"?>
<Node>
  <ChildNode
    value1="5"
    value2="6"
    value3="happy" />
</Node>

Обратите внимание, что если вам нужна строка, а не запись в файл, просто поменяйте местами с StringBuilder:

StringBuilder sb = new StringBuilder();
using (XmlReader reader = XmlReader.Create(new StringReader(oldXml)))
using (XmlWriter writer = XmlWriter.Create(sb, settings)) {
    writer.WriteNode(reader, false);
    writer.Close();
}
string newXml = sb.ToString();
11
ответ дан 1 December 2019 в 20:29
поделиться

XML Notepad 2007 может сделать это вручную ... позвольте мне посмотреть, можно ли это написать в сценарии.

Нет ... запустить его можно так:

XmlNotepad.exe a.xml

Остальное - просто нажать кнопку сохранения. Power Shell, другие инструменты могут это автоматизировать.

0
ответ дан 1 December 2019 в 20:29
поделиться

Просто используйте этот xslt:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" encoding="ISO-8859-1"/>
  <xsl:param name="indent-increment" select="'   '"/>

  <xsl:template name="newline">
    <xsl:text disable-output-escaping="yes">
</xsl:text>
  </xsl:template>

  <xsl:template match="comment() | processing-instruction()">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
    <xsl:copy />
  </xsl:template>

  <xsl:template match="text()">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
    <xsl:value-of select="normalize-space(.)"/>
  </xsl:template>

  <xsl:template match="text()[normalize-space(.)='']"/>

  <xsl:template match="*">
    <xsl:param name="indent" select="''"/>
    <xsl:call-template name="newline"/>    
    <xsl:value-of select="$indent"/>
      <xsl:choose>
       <xsl:when test="count(child::*) > 0">
        <xsl:copy>
         <xsl:copy-of select="@*"/>
         <xsl:apply-templates select="*|text()">
           <xsl:with-param name="indent" select="concat ($indent, $indent-increment)"/>
         </xsl:apply-templates>
         <xsl:call-template name="newline"/>
         <xsl:value-of select="$indent"/>
        </xsl:copy>
       </xsl:when>       
       <xsl:otherwise>
        <xsl:copy-of select="."/>
       </xsl:otherwise>
     </xsl:choose>
  </xsl:template>    
</xsl:stylesheet>

Или, как другой вариант, вот сценарий Perl: http://software.decisionsoft.com/index.html

0
ответ дан 1 December 2019 в 20:29
поделиться

Существует инструмент, который может разделять атрибуты по одному в строке: xmlpp . Это сценарий Perl, поэтому вам нужно установить perl . Использование:

perl xmlpp.pl -t input.xml

Вы также можете определить порядок атрибутов, создав файл с именем attributeOrdering.txt и вызвав perl xmlpp.pl -s -t input.xml . Для получения дополнительных опций используйте perl xmlpp.pl -h

. Надеюсь, в нем не так много ошибок, но до сих пор он работал у меня.

2
ответ дан 1 December 2019 в 20:29
поделиться

Вы можете реализовать простое приложение SAX, которое будет копировать все как есть с отступом атрибуты, как вам нравится.

UPD :

SAX означает Простой API для XML . Это модель push-анализа XML (классический пример шаблона проектирования Builder). API присутствует на большинстве текущих платформ разработки (хотя в собственной библиотеке классов .Net он отсутствует, имея интерфейс XMLReader)

Вот необработанная реализация на python, она довольно загадочная, но вы можете реализовать основную идею.

from sys import stdout
from xml.sax import parse
from xml.sax.handler import ContentHandler
from xml.sax.saxutils import escape

class MyHandler(ContentHandler):

    def __init__(self, file_, encoding):
        self.level = 0
        self.elem_indent = '    '

        # should the next block make a line break
        self._allow_N = False
        # whether the opening tag was closed with > (to allow />)
        self._tag_open = False

        self._file = file_
        self._encoding = encoding

    def _write(self, string_):
        self._file.write(string_.encode(self._encoding))

    def startElement(self, name, attrs):
        if self._tag_open:
            self._write('>')
            self._tag_open = False

        if self._allow_N:
            self._write('\n')
            indent = self.elem_indent * self.level
        else:
            indent = ''
        self._write('%s<%s' % (indent, name))

        # attr indent equals to the element indent plus '  '
        attr_indent = self.elem_indent * self.level + '  '
        for name in attrs.getNames():
            # write indented attribute one per line
            self._write('\n%s%s="%s"' % (attr_indent, name, escape(attrs.getValue(name))))

        self._tag_open = True

        self.level += 1
        self._allow_N = True

    def endElement(self, name):
        self.level -= 1
        if self._tag_open:
            self._write(' />')
            self._tag_open = False
            return

        if self._allow_N:
            self._write('\n')
            indent = self.elem_indent * self.level
        else:
            indent = ''
        self._write('%s</%s>' % (indent, name))
        self._allow_N = True

    def characters(self, content):
        if self._tag_open:
            self._write('>')
            self._tag_open = False

        if content.strip():
            self._allow_N = False
            self._write(escape(content))
        else:
            self._allow_N = True


if __name__ == '__main__':
    parser = parse('test.xsl', MyHandler(stdout, stdout.encoding))
0
ответ дан 1 December 2019 в 20:29
поделиться

Вот для этого сценарий PowerShell. Он принимает следующий ввод:

<?xml version="1.0" encoding="utf-8"?>
<Node>
    <ChildNode value1="5" value2="6" value3="happy" />
</Node>

... и производит это как вывод:

<?xml version="1.0" encoding="utf-8"?>
<Node>
  <ChildNode
    value1="5"
    value2="6"
    value3="happy" />
</Node>

Вот и все:

param(
    [string] $inputFile = $(throw "Please enter an input file name"),
    [string] $outputFile = $(throw "Please supply an output file name")
)

$data = [xml](Get-Content $inputFile)

$xws = new-object System.Xml.XmlWriterSettings
$xws.Indent = $true
$xws.IndentChars = "  "
$xws.NewLineOnAttributes = $true

$data.Save([Xml.XmlWriter]::Create($outputFile, $xws))

Возьмите этот сценарий и сохраните его как C: \ formatxml.ps1. Затем в командной строке PowerShell введите следующее:

C:\formatxml.ps1 C:\Path\To\UglyFile.xml C:\Path\To\NeatAndTidyFile.xml

Этот сценарий в основном просто использует платформу .NET, поэтому вы можете очень легко перенести его в приложение C #.

ПРИМЕЧАНИЕ. Если вы раньше не запускали сценарии из PowerShell, вам нужно будет выполнить следующую команду в командной строке PowerShell с повышенными привилегиями, прежде чем вы сможете выполнить сценарий:

 Set-ExecutionPolicy RemoteSigned 
 

Вам нужно сделать это только один раз.

Надеюсь, это полезно для вас.

12
ответ дан 1 December 2019 в 20:29
поделиться

Попробуйте Tidy на SourceForge. Хотя он часто используется в [X] HTML, я раньше успешно использовал его в XML - просто убедитесь, что вы используете параметр -xml .

http://tidy.sourceforge.net/#docs

Tidy читает файлы HTML, XHTML и XML и записывает очищенную разметку. ...Для общих файлов XML Tidy ограничивается исправлением основных ошибок правильного формата и красивой печатью .

Люди портировали его на несколько платформ, и он доступен в виде исполняемой и вызываемой библиотеки.

В Tidy есть куча параметров , включая:

http://api.html-tidy.org/tidy/quickref_5.0.0.html#indent

атрибуты отступа
Тип верхней части: Boolean
По умолчанию: no Пример: y / n, yes / no, t / f, true / false, 1/0
Этот параметр указывает, должен ли Tidy начинать каждый атрибут с новой строки.

Одно предостережение:

Ограниченная поддержка XML

XML-процессоры, совместимые с рекомендацией W3C XML 1.0, очень разборчивы в том, какие файлы они будут принимать. Tidy может помочь вам исправить ошибки, из-за которых ваши XML-файлы отклоняются. Однако Tidy еще не распознает все функции XML, например он не понимает разделы CDATA или подмножества DTD.

Но я подозреваю, что если ваш XML не является действительно продвинутым, инструмент должен работать нормально.

5
ответ дан 1 December 2019 в 20:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: