在XSLT中拆分以逗号分隔的字段,然后选择或限制字段数

时间:2013-05-15 01:08:30

标签: xml xslt xpath

我希望包含来自CSV格式的XML元素的数据。

具有讽刺意味的是,输出是一个CSV文件。

真正的问题是CSV格式允许4个关键字。

,,,,,,one,two,three,four,,,,,,     OK
,,,,,,one,two,three,four,five,,,,, WRONG
,,,,,,one,two,,,,,,,,              OK
,,,,,,,,,,,,,,,                    OK

因此,通常的嫌疑人<value-of select="keywords"/>不会工作,因为元素中的值的数量是可变的,大多数情况下通常为3到5个条目。

<keywords>one,two,three,four</keywords>
<keywords>one,two,three,four,five</keywords>
<keywords>one,two</keywords>
<keywords></keywords>

是否有任何方法可以使用XSLT将此CSV数组转换为XML元素,然后将每个数组作为目标。空值非常好。

<xsl:value-of select="fubar1"/><xsl:value-of select="','"/>
<xsl:value-of select="keyword[1]"/><xsl:value-of select="','"/>
<xsl:value-of select="keyword[2]"/><xsl:value-of select="','"/>
<xsl:value-of select="keyword[3]"/><xsl:value-of select="','"/>
<xsl:value-of select="keyword[4]"/><xsl:value-of select="','"/>
<xsl:value-of select="fubar3"/><xsl:value-of select="','"/>

2 个答案:

答案 0 :(得分:1)

<强>予。这是一个简单的XSLT 2.0解决方案:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:template match="text()">
   <xsl:value-of select=
    "tokenize(., ',')[.][not(position() gt 4)]" separator=","/>
    <xsl:text>&#xA;</xsl:text>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档(提供的片段包装到单个顶部元素中):

<t>
    <keywords>one,two,three,four</keywords>
    <keywords>one,two,three,four,five</keywords>
    <keywords>one,two</keywords>
    <keywords></keywords>
</t>

产生了想要的正确结果:

one,two,three,four
one,two,three,four
one,two

<强> II。非递归XSLT 1.0解决方案

此XSLT 1.0转换

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>
 <xsl:strip-space elements="*"/>

 <xsl:variable name="vDoc" select="document('')"/>

 <xsl:variable name="vNodes"
   select="$vDoc//node() | $vDoc//@* | $vDoc//namespace::*"/>

 <xsl:template match="text()">
    <xsl:variable name="vNorm" select="normalize-space(translate(.,',',' '))"/>
    <xsl:variable name="vCount" select=
    "string-length($vNorm) -string-length(translate($vNorm, ' ', ''))+1"/>

    <xsl:variable name="vTextToPrint">
        <xsl:choose>
          <xsl:when test="not($vCount >4)"><xsl:value-of select="$vNorm"/></xsl:when>
          <xsl:otherwise>
            <xsl:for-each select="$vNodes[not(position() > string-length($vNorm))]">
              <xsl:variable name="vPos" select="position()"/>
              <xsl:variable name="vheadSubstr" select="substring($vNorm,1,$vPos)"/>
              <xsl:if test=
              "substring($vNorm, $vPos, 1) = ' '
              and
                string-length($vheadSubstr)
               -
                string-length(translate($vheadSubstr, ' ',''))

                = 4">
                <xsl:value-of select="substring($vNorm,1,$vPos -1)"/>
              </xsl:if>
            </xsl:for-each>
          </xsl:otherwise>
        </xsl:choose>
    </xsl:variable>

    <xsl:value-of select="translate($vTextToPrint, ' ', ',')"/>
    <xsl:text>&#xA;</xsl:text>
 </xsl:template>
</xsl:stylesheet>

应用于同一XML文档(上图)时,会生成所需的正确结果

one,two,three,four
one,two,three,four
one,two

答案 1 :(得分:1)

这是一个简单的递归版本:

         

<xsl:template name="cvsmaxkey">
    <xsl:param name="keys" />
    <xsl:param name="nrofkeys" /> 
    <xsl:param name="pos" />
    <xsl:if test="$pos &lt;= $nrofkeys">
        <xsl:if test="$pos > 1 and $keys">
            <xsl:value-of select="','" />
        </xsl:if>
        <xsl:choose>
            <xsl:when test="contains($keys, ',')">
                <xsl:value-of select="substring-before($keys,',')" />
                <xsl:call-template name="cvsmaxkey">
                    <xsl:with-param name="keys" select="substring-after($keys,',')" />
                    <xsl:with-param name="nrofkeys" select="$nrofkeys" />
                    <xsl:with-param name="pos" select="$pos +1" />
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="$keys">
                <xsl:value-of select="$keys" />
                <xsl:value-of select="substring(',,,,,,,,,,,', 1,$nrofkeys - $pos)"/>
            </xsl:when>
            <xsl:otherwise>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:if>
</xsl:template>

<xsl:template match="keywords">
    <xsl:call-template name="cvsmaxkey">
        <xsl:with-param name="keys" select="." />
        <xsl:with-param name="nrofkeys" select="4" />
        <xsl:with-param name="pos" select="1" />
    </xsl:call-template>
    <xsl:text>&#xA;</xsl:text>
</xsl:template>
<xsl:template match="/">
    <xsl:apply-templates select="//keywords"/>
</xsl:template>

生成以下输出(使用常量的分隔符(,):

one,two,three,four
one,two,three,four
one,two,,
,,,