我正在寻找可以进行XML漂亮打印的Windows的XSLT或命令行工具(或可以制作成命令行工具的C#代码等)。具体来说,我想要一个能够将属性一对一地放置的东西,例如:
<Node>
<ChildNode
value1='5'
value2='6'
value3='happy' />
</Node>
它不一定非常像,但我想将它用于具有数十个属性的节点的XML文件,并将它们分布在多行中,使它们更易于阅读,编辑和文本差异。
注意:我认为我的首选解决方案是可以通过C#方法传递的XSLT表,尽管Windows命令行工具也很好。
答案 0 :(得分:11)
这是一个小的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>
示例输出(请注意,您可以使用<?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();
答案 1 :(得分:11)
这是一个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
你只需要这样做一次。
我希望这对你有用。
答案 2 :(得分:4)
在SourceForge上尝试Tidy。虽然它经常在[X] HTML上使用,但我之前在XML上成功使用过它 - 只需确保使用-xml
选项。
http://tidy.sourceforge.net/docs/tidy_man.html
Tidy读取HTML,XHTML和XML文件并写入清理过的标记。 ...对于通用XML文件,Tidy仅限于纠正基本的格式错误和漂亮的打印。
人们已移植到多个平台,它可用作可执行和可调用的库。
Tidy有很多选项,包括:
http://tidy.sourceforge.net/docs/quickref.html#indent-attributes
缩进的属性
顶部类型:布尔
默认值:no示例:y / n,是/否,t / f,真/假,1/0 此选项指定Tidy是否应在新行上开始每个属性。
一个警告:
对XML的有限支持
符合W3C XML 1.0建议的XML处理器非常挑剔他们会接受哪些文件。 Tidy可以帮助您修复导致XML文件被拒绝的错误。 Tidy尚未识别所有XML功能,例如它不了解CDATA部分或DTD子集。
但我怀疑,除非你的XML真的先进,否则该工具应该可以正常工作。
答案 3 :(得分:2)
有一个工具可以将属性拆分为每行一个:xmlpp。这是一个perl脚本,因此您必须安装perl。用法:
perl xmlpp.pl -t input.xml
您还可以通过创建名为attributeOrdering.txt的文件并调用perl xmlpp.pl -s -t input.xml
来确定属性的顺序。有关更多选项,请使用perl xmlpp.pl -h
我希望,它没有太多的错误,但到目前为止它对我有用。
答案 4 :(得分:0)
XML Notepad 2007可以手动执行此操作...让我看看它是否可以编写脚本。
没有......它可以像这样启动它:
XmlNotepad.exe a.xml
其余的只是点击保存按钮。 Power Shell,其他工具可以实现自动化。
答案 5 :(得分:0)
只需使用此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
答案 6 :(得分:0)
您可以实现一个简单的SAX应用程序,它将复制所有内容as is
并缩进属性。
<强> UPD 强>:
SAX代表Simple API for XML
。它是XML解析的推送模型(Builder设计模式的经典示例)。 API存在于大多数当前的开发平台中(尽管本机.Net类库缺少一个,具有XMLReader intead)
这是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))