0

xslt-1.0 を使用して、入力 xml を csv 出力に変換しようとしています。以下は私の入力xml形式です。

     <input>
     <add add-value="First Name">
        <value type="string">New</value>
      </add>
       <add add-value="Surname">
        <value  type="string">user1</value>
      </add>
      <add add-value="Title">
        <value type="string">engineer</value>
     </add>
     <add add-value="Description">
        <value type="string">New joinee.</value>
      </add>
<add .....
</add>
    </input>

出力csvは、xsltの変数を介して提供している固定数の列で構成されています。

以下は私のxsltです:

     <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="http://exslt.org/common" >   
        <xsl:variable name="delimiter" select="','"/>   
        <xsl:template match="input/add">
            <xsl:variable name="SplitWordsSet">
                <xsl:call-template name="split">
                    <xsl:with-param name="pText" select="'First name,Surname,Phone number,Description,Title'"/>
                </xsl:call-template>
            </xsl:variable>
            <xsl:variable name="vSplitWords" select="ext:node-set($SplitWordsSet)/*"/>

            <xsl:call-template name="counter">
                <xsl:with-param name="split-words" select="$vSplitWords"/>
                <xsl:with-param name="count"select="1"/>
            </xsl:call-template>
        </xsl:template> 
<!-- Below templtate splits the pText values -->
        <xsl:template name="split">
            <xsl:param name="pText"/>
            <xsl:param name="pElemName" select="'word'"/>
            <xsl:variable name="first" select="substring-before(concat($pText,','),',')"/>
            <xsl:variable name="remaining" select="substring-after($pText,',')"/>
            <xsl:element name="{$pElemName}">
                <xsl:value-of select="$first"/>
            </xsl:element>
            <xsl:choose>
                <xsl:when test="$remaining">
                    <xsl:call-template name="split">
                        <xsl:with-param name="pText" select="$remaining"/>
                        <xsl:with-param name="pElemName" select="$pElemName"/>
                    </xsl:call-template>
                </xsl:when>
            </xsl:choose>
        </xsl:template> 
<!-- below is recursive template to maintain count of columns values -->
        <xsl:template name="counter">
            <xsl:param name="count" select="1"/>
            <xsl:param name="split-words"/>
            <xsl:variable name="split-word" select="$split-words[$count]"/>
            <xsl:if test="$count &lt; 6">
                <xsl:call-template name="output-csv">
                    <xsl:with-param name="field-value" select="*[(@add-value = '$split-word')]/value"/>
                </xsl:call-template>
                <xsl:value-of select="$delimiter"/>
                <xsl:call-template name="counter">
                    <xsl:with-param name="count" select="$count + 1"/>
                </xsl:call-template>
            </xsl:if>
        </xsl:template>     
        <xsl:template name="output-csv">
            <xsl:param name="field-value"/>
        <xsl:value-of select="$field-value"/>
        </xsl:template>
    </xsl:stylesheet>

私が興味を持っている追加値属性は param として渡されpTextます。これらの値は、出力 csv の列です。

私の期待される出力:

First name,Surname,Phone number,Description,Title
New,User1,,New joinee,engineer

しかし、私は目的の出力を得ることができません,,,,,

4

1 に答える 1

1

XSLT にはいくつかの問題があります。まず、最初のテンプレートの一致では、追加要素で一致していますが、CSV ファイルの行を表す入力要素であるため、おそらくそれで一致したいと考えています。

<xsl:template match="input">

次に、 output-csvテンプレートを呼び出すときに、現在の単語の正しいadd-value属性を持つadd要素を探す必要があります。

<xsl:call-template name="output-csv">
   <xsl:with-param name="field-value" select="add[@add-value = $split-word]/value"/>
</xsl:call-template>

ただし、主な問題は、カウンターテンプレートを再帰的に呼び出す方法にあります。ここでは分割単語属性を再設定していないため、2 回目の呼び出しではパラメーターは空になります。

 <xsl:call-template name="counter">
    <xsl:with-param name="count" select="$count + 1"/>
 </xsl:call-template>

(XML では最初の属性が 'First Name' ですが、XSLT の列名のリストでは 'first name' であることに注意してください。XSLT での文字列比較では、大文字と小文字が区別されます。 )。

ここでパラメーターを設定することもできますが、分割単語のリストを入力要素ごとに分割するのではなく、グローバル変数にする方が良い (確かに効率的) 場合があります。

このXSLTを試してください

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="urn:schemas-microsoft-com:xslt" >   
    <xsl:variable name="delimiter" select="','"/>
   <xsl:variable name="SplitWordsSet">
     <xsl:call-template name="split">
       <xsl:with-param name="pText" select="'First name,Surname,Phone number,Description,Title'"/>
     </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="vSplitWords" select="ext:node-set($SplitWordsSet)/*"/>

    <xsl:template match="input">
        <xsl:call-template name="counter">
            <xsl:with-param name="count" select="1"/>
        </xsl:call-template>
    </xsl:template> 

  <!-- Below templtate splits the pText values -->
    <xsl:template name="split">
        <xsl:param name="pText"/>
        <xsl:param name="pElemName" select="'word'"/>
        <xsl:variable name="first" select="substring-before(concat($pText,','),',')"/>
        <xsl:variable name="remaining" select="substring-after($pText,',')"/>
        <xsl:element name="{$pElemName}">
            <xsl:value-of select="$first"/>
        </xsl:element>
        <xsl:choose>
            <xsl:when test="$remaining">
                <xsl:call-template name="split">
                    <xsl:with-param name="pText" select="$remaining"/>
                    <xsl:with-param name="pElemName" select="$pElemName"/>
                </xsl:call-template>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

 <!-- below is recursive template to maintain count of columns values -->
    <xsl:template name="counter">
        <xsl:param name="count" select="1"/>
        <xsl:param name="split-words"/>

        <xsl:variable name="split-word" select="$vSplitWords[$count]"/>
        <xsl:call-template name="output-csv">
          <xsl:with-param name="field-value" select="add[@add-value = $split-word]/value"/>
        </xsl:call-template>
        <xsl:if test="$count &lt; 5">
            <xsl:value-of select="$delimiter"/>
            <xsl:call-template name="counter">
                <xsl:with-param name="count" select="$count + 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>     
    <xsl:template name="output-csv">
        <xsl:param name="field-value"/>
    <xsl:value-of select="$field-value"/>
    </xsl:template>
</xsl:stylesheet>

これにより、出力が得られるはずです

 New,user1,,New joinee.,engineer

ただし、再帰的なテンプレートを使用しない別の方法があります。分割単語要素に一致するテンプレートを用意し、現在の入力をパラメーターとして渡します

   <xsl:template match="word">
     <xsl:param name="input" />
     <xsl:if test="position() > 1">
       <xsl:value-of select="$delimiter"/>
     </xsl:if>
     <xsl:value-of select="$input/add[@add-value = current()]/value" />
   </xsl:template>

その後、各行は次のように出力できます

      <xsl:apply-templates select="$vSplitWords">
        <xsl:with-param name="input" select="." />
      </xsl:apply-templates>

このXSLTも試してみてください

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ext="urn:schemas-microsoft-com:xslt" >   
    <xsl:variable name="delimiter" select="','"/>

   <xsl:variable name="SplitWordsSet">
     <xsl:call-template name="split">
       <xsl:with-param name="pText" select="'First name,Surname,Phone number,Description,Title'"/>
     </xsl:call-template>
   </xsl:variable>
   <xsl:variable name="vSplitWords" select="ext:node-set($SplitWordsSet)/*"/>

    <xsl:template match="input">
      <xsl:apply-templates select="$vSplitWords">
        <xsl:with-param name="input" select="." />
      </xsl:apply-templates>
    </xsl:template> 

 <!-- Below templtate splits the pText values -->
    <xsl:template name="split">
        <xsl:param name="pText"/>
        <xsl:param name="pElemName" select="'word'"/>
        <xsl:variable name="first" select="substring-before(concat($pText,','),',')"/>
        <xsl:variable name="remaining" select="substring-after($pText,',')"/>
        <xsl:element name="{$pElemName}">
            <xsl:value-of select="$first"/>
        </xsl:element>
        <xsl:choose>
            <xsl:when test="$remaining">
                <xsl:call-template name="split">
                    <xsl:with-param name="pText" select="$remaining"/>
                    <xsl:with-param name="pElemName" select="$pElemName"/>
                </xsl:call-template>
            </xsl:when>
        </xsl:choose>
    </xsl:template>

   <xsl:template match="word">
     <xsl:param name="input" />
     <xsl:if test="position() > 1">
       <xsl:value-of select="$delimiter"/>
     </xsl:if>
     <xsl:value-of select="$input/add[@add-value = current()]/value" />
   </xsl:template>

</xsl:stylesheet>
于 2013-07-29T07:58:15.063 に答える