是否有用于可控 XML 格式设置的样式表或 Windows 命令行工具,特别是每行一个属性?

发布于 2024-08-27 16:58:02 字数 366 浏览 16 评论 0原文

我正在寻找适用于 Windows 的 XSLT 或命令行工具(或可以制作成命令行工具的 C# 代码等),以执行 XML 漂亮打印。具体来说,我想要一个能够将属性一对一放置的能力,例如:

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

它不必完全像那样,但我想将它用于具有数十个节点的 XML 文件。属性并将它们分布在多行中使它们更易于阅读、编辑和文本比较。

注意:我认为我的首选解决方案是可以通过 C# 方法传递的 XSLT 表,尽管 Windows 命令行工具也很好。

I am searching for an XSLT or command-line tool (or C# code that can be made into a command-line tool, etc) for Windows that will do XML pretty-printing. Specifically, I want one that has the ability to put attributes one-to-a-line, something like:

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

It doesn't have to be EXACTLY like that, but I want to use it for an XML file that has nodes with dozens of attributes and spreading them across multiple lines makes them easier to read, edit, and text-diff.

NOTE: I think my preferred solution is an XSLT sheet I can pass through a C# method, though a Windows command-line tool is good too.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

━╋う一瞬間旳綻放 2024-09-03 16:58:02

这是一个用于执行此操作的 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

不过,您只需执行一次。

我希望这对你有用。

Here's a PowerShell script to do it. It takes the following input:

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

...and produces this as output:

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

Here you go:

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))

Take that script, save it as C:\formatxml.ps1. Then, from a PowerShell prompt type the following:

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

This script is basically just using the .NET framework so you could very easily migrate this into a C# application.

NOTE: If you have not run scripts from PowerShell before, you will have to execute the following command at an elevated PowerShell prompt before you will be able to execute the script:

Set-ExecutionPolicy RemoteSigned

You only have to do this one time though.

I hope that's useful to you.

怕倦 2024-09-03 16:58:02

下面是一个小型 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();

Here's a small C# sample, which can be used directly by your code, or built into an exe and called at the comand-line as "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();
        }
    }

Sample input:

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

Sample output (note you can remove the <?xml ... with settings.OmitXmlDeclaration):

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

Note that if you want a string rather than write to a file, just swap with 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();
牛↙奶布丁 2024-09-03 16:58:02

在 SourceForge 上尝试 Tidy。虽然它经常在 [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、真/假、1/0
此选项指定 Tidy 是否应在新行中开始每个属性。

一个警告:

对 XML 的支持有限

符合 W3C XML 1.0 建议的 XML 处理器对于接受哪些文件非常挑剔。 Tidy 可以帮助您修复导致 XML 文件被拒绝的错误。不过,Tidy 还不能识别所有 XML 功能,例如,它不能理解 CDATA 部分或 DTD 子集。

但我怀疑除非您的 XML 非常先进,否则该工具应该可以正常工作。

Try Tidy over on SourceForge. Although its often used on [X]HTML, I've used it successfully on XML before - just make sure you use the -xml option.

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

Tidy reads HTML, XHTML and XML files and writes cleaned up markup. ... For generic XML files, Tidy is limited to correcting basic well-formedness errors and pretty printing.

People have ported to several platforms and it available as an executable and callable library.

Tidy has a heap of options including:

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

indent-attributes
Top Type: Boolean
Default: no Example: y/n, yes/no, t/f, true/false, 1/0
This option specifies if Tidy should begin each attribute on a new line.

One caveat:

Limited support for XML

XML processors compliant with W3C's XML 1.0 recommendation are very picky about which files they will accept. Tidy can help you to fix errors that cause your XML files to be rejected. Tidy doesn't yet recognize all XML features though, e.g. it doesn't understand CDATA sections or DTD subsets.

But I suspect unless your XML is really advanced, the tool should work fine.

微暖i 2024-09-03 16:58:02

有一个工具可以将属性拆分为每行一个:xmlpp。它是一个 Perl 脚本,因此您必须安装 perl。用法:

perl xmlpp.pl -t input.xml

您还可以通过创建名为 attributeOrdering.txt 的文件并调用 perl xmlpp.pl -s -t input.xml 来确定属性的顺序。要获得更多选项,请使用 perl xmlpp.pl -h

我希望它没有太多错误,但到目前为止它对我有用。

There is a tool, that can split attributes to one per line: xmlpp. It's a perl script, so you'll have to install perl. Usage:

perl xmlpp.pl -t input.xml

You can also determine the ordering of attributes by creating a file called attributeOrdering.txt, and calling perl xmlpp.pl -s -t input.xml . For more options, use perl xmlpp.pl -h

I hope, it doesn't have too many bugs, but it has worked for me so far.

永言不败 2024-09-03 16:58:02

XML Notepad 2007 可以手动执行此操作...让我看看是否可以编写脚本。

不……它可以像这样启动它:

XmlNotepad.exe a.xml

剩下的只需单击“保存”按钮即可。 Power Shell,其他工具可以自动执行此操作。

XML Notepad 2007 can do so manually ... let me see if it can be scripted.

Nope ... it can launch it like so:

XmlNotepad.exe a.xml

The rest is just clicking the save button. Power Shell, other tools can automate that.

━╋う一瞬間旳綻放 2024-09-03 16:58:02

只需使用此 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

Just use this 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>

Or, as another option, here is a perl script: http://software.decisionsoft.com/index.html

2024-09-03 16:58:02

您可以实现一个简单的 SAX 应用程序,它将按您喜欢的方式复制所有内容并缩进属性。

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))

You can implement a simple SAX application that will copy everything as is and indent attributes how you like.

UPD:

SAX stands for Simple API for XML. It is a push model of XML parsing (a classical example of Builder design pattern). The API is present in most of the current development platforms (though native .Net class library lacks one, having XMLReader intead)

Here is a raw implementation in python, it is rather cryptic but you can realize the main idea.

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))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文