Есть ли таблица стилей или инструмент командной строки Windows для управляемого XML-форматирования, в частности, установка атрибутов по одной строке?
Я ищу инструмент XSLT или командной строки (или код С#, который можно сделать в инструменте командной строки и т.д.) для Windows, который будет делать XML-печать. В частности, я хочу, чтобы у меня была возможность поместить атрибуты в одну строку, например:
<Node>
<ChildNode
value1='5'
value2='6'
value3='happy' />
</Node>
Он не должен быть ТОЧНО подобным, но я хочу использовать его для XML файла, который имеет узлы с десятками атрибутов и распространяет их по нескольким строкам, что упрощает их чтение, редактирование и text-diff.
ПРИМЕЧАНИЕ. Я считаю, что моим предпочтительным решением является лист XSLT, который я могу пройти через метод С#, хотя инструмент командной строки Windows тоже хорош.
Ответы
Ответ 1
Здесь небольшая С# -камера, которая может использоваться непосредственно вашим кодом или встроена в exe и вызывается в comand-строке как "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>
Пример вывода (обратите внимание, что вы можете удалить <?xml ...
с помощью 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();
Ответ 2
Здесь PowerShell script, чтобы сделать это. Он принимает следующий ввод:
<?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))
Возьмите этот script, сохраните его как C:\formatxml.ps1. Затем из приглашения PowerShell введите следующее:
C:\formatxml.ps1 C:\Path\To\UglyFile.xml C:\Path\To\NeatAndTidyFile.xml
Этот script в основном использует платформу .NET, поэтому вы можете легко перенести это в приложение С#.
ПРИМЕЧАНИЕ. Если вы еще не запускали сценарии из PowerShell, вам нужно выполнить следующую команду в расширенной подсказке PowerShell, прежде чем вы сможете выполнить script:
Set-ExecutionPolicy RemoteSigned
Вам нужно сделать это только один раз.
Я надеюсь, что это вам полезно.
Ответ 3
Попробуйте 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
отступ-атрибуты
Тип верха: логическое значение
По умолчанию: нет Пример: y/n, да/нет, t/f, true/false, 1/0
Эта опция указывает, должен ли Tidy начинать каждый атрибут с новой строки.
Одно предостережение:
Ограниченная поддержка XML
Процессоры XML, совместимые с рекомендацией W3C XML 1.0, очень требовательны к тому, какие файлы они будут принимать. Tidy может помочь вам исправить ошибки, которые приводят к отклонению ваших файлов XML. Tidy еще не распознает все возможности XML, например, он не понимает разделы CDATA или подмножества DTD.
Но я подозреваю, что если ваш XML не является действительно продвинутым, инструмент должен работать нормально.
Ответ 4
Существует инструмент, который может разделять атрибуты по одному в строке: xmlpp. Это perl script, поэтому вам нужно будет установить perl. Использование:
perl xmlpp.pl -t input.xml
Вы также можете определить порядок атрибутов, создав файл с именем attributeOrdering.txt и вызывая perl xmlpp.pl -s -t input.xml
. Для получения дополнительных параметров используйте perl xmlpp.pl -h
Надеюсь, в нем не так много ошибок, но я работал до сих пор.
Ответ 5
XML Notepad 2007 может сделать это вручную... дайте мне посмотреть, можно ли его сценаризировать.
Нет... он может запускать его так:
XmlNotepad.exe a.xml
Остальное просто нажимает кнопку сохранения. Power Shell, другие инструменты могут автоматизировать это.
Ответ 6
Просто используйте этот 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 script: http://software.decisionsoft.com/index.html
Ответ 7
Вы можете реализовать простое приложение SAX, которое будет копировать все as is
и атрибуты отступа, как вам нравится.
UPD:
SAX означает Simple API for XML
. Это модель моделирования 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))