web-dev-qa-db-ja.com

XSLT-テンプレートから空白を削除します

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>&#10;&#13;</xsl:text>
   </xsl:for-each>
 </xsl:template>

</xsl:stylesheet>
44
Robert DeBoer

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つのテキストノードが含まれます。

  1. _"\n··"_(_<xml>_の直後)
  2. _"·value·"_
  3. "_\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>_要素を使用できますが、通常これは必要ではありません(個人的には、上記のように明示的な空白処理を好みます)。

90
Tomalak

デフォルトでは、XSLTテンプレートには<xsl:preserve-space> set。出力に空白を保持します。あなたは付け加えられます <xsl:strip-space elements="*">空白を削除する場所を示します。

次のように、normalize-spaceディレクティブを含める必要がある場合もあります。

<xsl:template match="text()"><xsl:value-of select="normalize-space(.)"/></xsl:template> 

W3 Schoolsからのスペースの保存/削除の例 です。

8
Noah Heldman

タブを削除して別々の行を保持する限り、次の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="'&#x9;'" />
     <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(), '&#x9;', '')" />
 </xsl:template>
</xsl:stylesheet>
2
David Andres

他の人はすでに一般的な問題を指摘しています。あなたのスタイルシートに特有のものは、カンマの<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を出力していないため、ここでは何もしません。

1
Pavel Minaev

私の以前の答えは間違っています、すべてのコンマはタグ「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>&#10;&#13;</xsl:text>
        </xsl:for-each>
    </xsl:template>
    <xsl:template match="text()|@*">
        <xsl:text>-</xsl:text>
    </xsl:template>

</xsl:stylesheet>
1
Nick Groznykh

1つのテンプレートをxsltに追加します

<xsl:template match="text()"/>
1
Nick Groznykh

生のxmlファイルをフォーマットするために使用したコードを変更し、以下の行を削除して、エクスポートされたExcelに追加された余分な空白を削除します。

インデントされたプロパティシステムを使用した書式設定では、これらの余分な空白スペースが追加されます。

以下のようなXMLのフォーマットに関連する行をコメントして試してください。

xmlWriter.Formatting = System.Xml.Formatting.Indented;
0
Tejas Sawant