我希望包含来自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="','"/>
答案 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>
</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>
</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 <= $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>
</xsl:text>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="//keywords"/>
</xsl:template>
生成以下输出(使用常量的分隔符(,):
one,two,three,four
one,two,three,four
one,two,,
,,,