15

XMLプリティプリントを行うWindows用のXSLTまたはコマンドラインツール(またはコマンドラインツールにできるC#コードなど)を探しています。具体的には、次のような属性を 1 行に 1 つずつ配置できる機能が必要です。

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

必ずしもそのようである必要はありませんが、数十の属性を持つノードを持つ XML ファイルに使用し、それらを複数行に分散させることで、読みやすく、編集しやすく、テキストの差分を取りやすくしたいと考えています。

注: Windows コマンド ライン ツールも優れていますが、C# メソッドを介して渡すことができる XSLT シートを使用することをお勧めします。

4

7 に答える 7

14

これを行うための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

このスクリプトは基本的に.NETFrameworkを使用しているため、これをC#アプリケーションに非常に簡単に移行できます。

注:以前にPowerShellからスクリプトを実行したことがない場合は、スクリプトを実行する前に、昇格したPowerShellプロンプトで次のコマンドを実行する必要があります。

Set-ExecutionPolicy RemoteSigned

ただし、これを行う必要があるのは1回だけです。

お役に立てば幸いです。

于 2010-04-18T15:34:30.173 に答える
11

コードで直接使用するか、exe に組み込み、コマンドラインで " myexe from.xml to.xml" として呼び出すことができる小さな C# サンプルを次に示します。

    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();
于 2010-04-18T09:46:12.197 に答える
6

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

indent-attributes
トップタイプ:ブール
デフォルト:no例:y / n、yes / no、t / f、true / false、1/0
このオプションは、Tidyが各属性を新しい行で開始するかどうかを指定します。

1つの警告:

XMLの限定的なサポート

W3CのXML1.0勧告に準拠するXMLプロセッサは、どのファイルを受け入れるかについて非常に慎重です。Tidyは、XMLファイルが拒否される原因となるエラーを修正するのに役立ちます。ただし、TidyはまだすべてのXML機能を認識していません。たとえば、CDATAセクションまたはDTDサブセットを理解していません。

しかし、XMLが本当に高度でない限り、ツールは正常に機能するはずです。

于 2010-04-17T16:43:29.157 に答える
2

属性を 1 行に 1 つに分割できるツールがあります: xmlpp。これは perl スクリプトなので、 perl をインストールする必要があります。使用法:

perl xmlpp.pl -t input.xml

また、attributeOrdering.txt というファイルを作成し、 を呼び出すことによって、属性の順序を決定することもできますperl xmlpp.pl -s -t input.xml。その他のオプションについては、perl xmlpp.pl -h

バグが多すぎないことを願っていますが、これまでのところうまくいきました。

于 2010-04-12T18:00:29.987 に答える
0

XMLNotepad2007は手動でこれを行うことができます...スクリプト化できるかどうかを確認させてください。

いいえ...次のように起動できます:

XmlNotepad.exe a.xml

残りは保存ボタンをクリックするだけです。Power Shell、他のツールで自動化できます。

于 2010-04-02T18:15:25.610 に答える
0

as isすべてをコピーし、好きなように属性をインデントする単純な SAX アプリケーションを実装できます。

更新日:

SAXは の略ですSimple API for XML。これは、XML 構文解析のプッシュ モデルです (Builder デザイン パターンの古典的な例)。この API は、現在の開発プラットフォームのほとんどに存在します (ただし、ネイティブの .Net クラス ライブラリには API がなく、代わりに 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))
于 2010-04-12T19:57:28.210 に答える
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

于 2010-04-02T18:18:10.047 に答える