XMLを使用して小さな連絡先リストを保存し、それをCSVファイルに変換するXSLテンプレートを作成しようとしています。私が抱えている問題は、出力の空白にあります。
出力:
Friend, John, Smith, Home,
123 test,
Sebastopol,
California,
12345,
Home 1-800-123-4567, Personal [email protected]
読みやすく開発しやすいように、ソースXMLファイルと関連するXSLテンプレートの両方をインデント/スペースしましたが、余分な空白はすべて出力に含まれています。 XML自体にはノード内に余分な空白はなく、フォーマットのためにノードのすぐ外側にあります。XSLTについても同じことが言えます。
CSVファイルを有効にするには、各エントリが分割されていない独自の行にある必要があります。 XMLおよびXSLTから余分な空白をすべて削除する(コードを1行だけにする)ほかに、出力の空白を削除する別の方法はありますか?
編集:小さなXMLサンプルを次に示します。
<PHONEBOOK>
<LISTING>
<FIRST>John</FIRST>
<LAST>Smith</LAST>
<ADDRESS TYPE="Home">
<STREET>123 test</STREET>
<CITY>Sebastopol</CITY>
<STATE>California</STATE>
<Zip>12345</Zip>
</ADDRESS>
<PHONE>1-800-123-4567</PHONE>
<EMAIL>[email protected]</EMAIL>
<RELATION>Friend</RELATION>
</LISTING>
</PHONEBOOK>
XSLTは次のとおりです。
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" />
<xsl:template match="/">
<xsl:for-each select="//LISTING">
<xsl:value-of select="RELATION" /><xsl:text>, </xsl:text>
<xsl:value-of select="FIRST" /><xsl:text>, </xsl:text>
<xsl:value-of select="LAST" /><xsl:text>, </xsl:text>
<xsl:if test="ADDRESS">
<xsl:for-each select="ADDRESS">
<xsl:choose>
<xsl:when test="@TYPE">
<xsl:value-of select="@TYPE" />,
</xsl:when>
<xsl:otherwise>
<xsl:text>Home </xsl:text>
</xsl:otherwise>
</xsl:choose>
<xsl:value-of select="STREET" />,
<xsl:value-of select="CITY" />,
<xsl:value-of select="STATE" />,
<xsl:value-of select="Zip" />,
</xsl:for-each>
</xsl:if>
<xsl:for-each select="PHONE">
<xsl:choose>
<xsl:when test="@TYPE">
<xsl:value-of select="@TYPE" />
</xsl:when>
<xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise>
</xsl:choose>
<xsl:value-of select="." /><xsl:text >, </xsl:text>
</xsl:for-each>
<xsl:if test="EMAIL">
<xsl:for-each select="EMAIL">
<xsl:choose>
<xsl:when test="@TYPE">
<xsl:value-of select="@TYPE" /><xsl:text > </xsl:text>
</xsl:when>
<xsl:otherwise><xsl:text >Personal </xsl:text></xsl:otherwise>
</xsl:choose>
<xsl:value-of select="." /><xsl:text >, </xsl:text>
</xsl:for-each>
</xsl:if>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
XSLTでは、空白は非常に適切なデータになる可能性があるため、デフォルトで空白が保持されます。
出力で不要な空白を防ぐ最良の方法は、最初に空白を作成しないことです。しないでください:
_<xsl:template match="foo">
foo
</xsl:template>
_
プロセッサの観点からは、それは_"\n··foo\n"
_であるためです。むしろする
_<xsl:template match="foo">
<xsl:text>foo</xsl:text>
</xsl:template>
_
スタイルシートの空白は、XML要素間でのみ発生する限り無視されます。簡単に言えば、XSLTコードのどこでも「裸の」テキストを使用せず、常に要素で囲みます。
また、不特定の使用:
_<xsl:apply-templates />
_
テキストノードのデフォルトのXSLTルールには「それらを出力にコピーする」と書かれているため、問題があります。これは、「空白のみ」のノードにも適用されます。例えば:
_<xml>
<data> value </data>
</xml>
_
3つのテキストノードが含まれます。
"\n··"
_(_<xml>
_の直後)"·value·"
_\n"
_(_</xml>
_の直前)#1と#3が出力にこっそり入らないようにするには(これが不要なスペースの最も一般的な理由です)、空のテンプレートを宣言してテキストノードのデフォルトルールをオーバーライドできます。
_<xsl:template match="text()" />
_
すべてのテキストノードがミュートされ、テキスト出力を明示的に作成する必要があります。
_<xsl:value-of select="data" />
_
値から空白を削除するには、normalize-space()
XSLT関数を使用できます。
_<xsl:value-of select="normalize-space(data)" />
_
ただし、この関数は文字列内の空白を正規化するため、注意が必要です。 _"·value··1·"
_は_"value·1"
_になります。
さらに、_<xsl:strip-space>
_および_<xsl:preserve-space>
_要素を使用できますが、通常これは必要ではありません(個人的には、上記のように明示的な空白処理を好みます)。
デフォルトでは、XSLTテンプレートには<xsl:preserve-space>
set。出力に空白を保持します。あなたは付け加えられます <xsl:strip-space elements="*">
空白を削除する場所を示します。
次のように、normalize-spaceディレクティブを含める必要がある場合もあります。
<xsl:template match="text()"><xsl:value-of select="normalize-space(.)"/></xsl:template>
タブを削除して別々の行を保持する限り、次のXSLT 1.0アプローチを試しましたが、かなりうまくいきます。バージョン1.0または2.0の使用は、使用しているプラットフォームに大きく依存します。 .NETテクノロジーはまだXSLT 1.0に依存しているように見えるため、非常に面倒なテンプレートに限定されます(以下を参照)。 Javaまたは他の何かを使用している場合は、一番下の方にリストされているよりクリーンなXSLT 2.0アプローチを参照してください。
これらの例は、特定のニーズに合わせて拡張することを目的としています。ここではタブを例として使用していますが、これは拡張可能な十分な汎用性が必要です。
XML:
<?xml version="1.0" encoding="UTF-8"?>
<text>
adslfjksdaf
dsalkfjdsaflkj
lkasdfjlsdkfaj
</text>
...およびXSLT 1.0テンプレート(.NETを使用する場合に必要):
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template name="search-and-replace">
<xsl:param name="input"/>
<xsl:param name="search-string"/>
<xsl:param name="replace-string"/>
<xsl:choose>
<xsl:when test="$search-string and
contains($input,$search-string)">
<xsl:value-of
select="substring-before($input,$search-string)"/>
<xsl:value-of select="$replace-string"/>
<xsl:call-template name="search-and-replace">
<xsl:with-param name="input"
select="substring-after($input,$search-string)"/>
<xsl:with-param name="search-string"
select="$search-string"/>
<xsl:with-param name="replace-string"
select="$replace-string"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$input"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="text">
<xsl:call-template name="search-and-replace">
<xsl:with-param name="input" select="text()" />
<xsl:with-param name="search-string" select="'	'" />
<xsl:with-param name="replace-string" select="''" />
</xsl:call-template>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0は、replace
関数を使用してこれを簡単にします。
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs"
version="2.0">
<xsl:template match="text">
<xsl:value-of select="replace(text(), '	', '')" />
</xsl:template>
</xsl:stylesheet>
他の人はすでに一般的な問題を指摘しています。あなたのスタイルシートに特有のものは、カンマの<xsl:text>
を忘れたことです:
<xsl:choose>
<xsl:when test="@TYPE">
<xsl:value-of select="@TYPE" />,
</xsl:when>
<xsl:otherwise>Home </xsl:otherwise>
</xsl:choose>
<xsl:value-of select="STREET" />,
<xsl:value-of select="CITY" />,
<xsl:value-of select="STATE" />,
<xsl:value-of select="Zip" />,
これにより、すべてのコンマに続く空白が有意になり、出力になります。各コンマを<xsl:text>
で囲むと、問題はなくなります。
また、そのdisable-output-escaping
を取り除きます。 XMLを出力していないため、ここでは何もしません。
私の以前の答えは間違っています、すべてのコンマはタグ「text」を介して出力する必要があります
<?xml version="1.0" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/PHONEBOOK">
<xsl:for-each select="LISTING">
<xsl:value-of select="RELATION" /><xsl:text>, </xsl:text>
<xsl:value-of select="FIRST" /><xsl:text>, </xsl:text>
<xsl:value-of select="LAST" /><xsl:text>, </xsl:text>
<xsl:for-each select="ADDRESS">
<xsl:choose>
<xsl:when test="@TYPE">
<xsl:value-of select="@TYPE" /><xsl:text>,</xsl:text>
</xsl:when>
<xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise>
</xsl:choose>
<xsl:value-of select="STREET/text()" /><xsl:text>,</xsl:text>
<xsl:value-of select="CITY/text()" /><xsl:text>,</xsl:text>
<xsl:value-of select="STATE/text()" /><xsl:text>,</xsl:text>
<xsl:value-of select="Zip/text()" /><xsl:text>,</xsl:text>
</xsl:for-each>
<xsl:for-each select="PHONE">
<xsl:choose>
<xsl:when test="@TYPE">
<xsl:value-of select="@TYPE" />
</xsl:when>
<xsl:otherwise><xsl:text>Home </xsl:text></xsl:otherwise>
</xsl:choose>
<xsl:value-of select="." /><xsl:text >, </xsl:text>
</xsl:for-each>
<xsl:if test="EMAIL">
<xsl:for-each select="EMAIL">
<xsl:choose>
<xsl:when test="@TYPE">
<xsl:value-of select="@TYPE" /><xsl:text > </xsl:text>
</xsl:when>
<xsl:otherwise><xsl:text >Personal </xsl:text></xsl:otherwise>
</xsl:choose>
<xsl:value-of select="." /><xsl:text >, </xsl:text>
</xsl:for-each>
</xsl:if>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()|@*">
<xsl:text>-</xsl:text>
</xsl:template>
</xsl:stylesheet>
1つのテンプレートをxsltに追加します
<xsl:template match="text()"/>
生のxmlファイルをフォーマットするために使用したコードを変更し、以下の行を削除して、エクスポートされたExcelに追加された余分な空白を削除します。
インデントされたプロパティシステムを使用した書式設定では、これらの余分な空白スペースが追加されます。
以下のようなXMLのフォーマットに関連する行をコメントして試してください。
xmlWriter.Formatting = System.Xml.Formatting.Indented;