我有这个xslt将csv转换为xml,工作正常,但所有列的标签都相同。 我需要它像这样增加
<row>
<column1></column1>
<column2></column2>
<column3></column3>
</row>
当我使用position()时,它将所有列重命名为column1
<xsl:element name="{concat('column', position())}">
这是xslt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:variable name="LF" select="'
'"/>
<!-- template that matches the root node-->
<xsl:template match="/">
<root>
<xsl:call-template name="texttorows">
<xsl:with-param name="StringToTransform" select="/root"/>
</xsl:call-template>
</root>
</xsl:template>
<!-- template that actually does the conversion-->
<xsl:template name="texttorows">
<!-- import $StringToTransform-->
<xsl:param name="StringToTransform" select="''"/>
<xsl:choose>
<!-- string contains linefeed-->
<xsl:when test="contains($StringToTransform,$LF)">
<!-- Get everything up to the first carriage return-->
<row>
<xsl:call-template name="csvtoxml">
<xsl:with-param name="StringToTransform" select="substring-before($StringToTransform,$LF)"/>
</xsl:call-template>
</row>
<!-- repeat for the remainder of the original string-->
<xsl:call-template name="texttorows">
<xsl:with-param name="StringToTransform">
<xsl:value-of select="substring-after($StringToTransform,$LF)"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<!-- string does not contain newline, so just output it-->
<xsl:otherwise>
<row>
<xsl:call-template name="csvtoxml">
<xsl:with-param name="StringToTransform" select="$StringToTransform"/>
</xsl:call-template>
</row>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="csvtoxml">
<!-- import $StringToTransform-->
<xsl:param name="StringToTransform" select="''"/>
<xsl:choose>
<!-- string contains linefeed-->
<xsl:when test="contains($StringToTransform,',')">
<!-- Get everything up to the first carriage return-->
<xsl:element name="{concat('column', position())}">
<xsl:value-of select="substring-before($StringToTransform,',')"/>
</xsl:element>
<!-- repeat for the remainder of the original string-->
<xsl:call-template name="csvtoxml">
<xsl:with-param name="StringToTransform">
<xsl:value-of select="substring-after($StringToTransform,',')"/>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
<!-- string does not contain newline, so just output it-->
<xsl:otherwise>
<column>
<xsl:value-of select="$StringToTransform"/>
</column>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
以下是csv示例:
<root>
3779490,916705,CS,60,34.89,Sauce/Cholula
5918104,918958,CS,6,20.63,Pasta/Fresh/Cavatelli/6#/Frozen
5064774,920723,CS,10,45.5,Cheese/Oaxaca
3422752,925230,EA,8,69.6,Chipotle/Powder/Ground
5955640,BB171,CS,30,50.7,Butter/Unsalted
5295326,BC110005,CS,6000,54.95,Oil/Olive/Finishing
</root>
答案 0 :(得分:2)
虽然XSLT能够处理非XML内容,但它似乎并不是一个通用的文本转换工具。因此,您可以使用的大多数工具都是关于操纵XML信息集结构(如元素和属性)。对文本字符串有一点支持,但不多。所以position()
是根据输入节点定义的。
http://www.w3.org/TR/xpath/#section-Node-Set-Functions:
position函数返回一个等于表达式求值上下文中上下文位置的数字。
http://www.w3.org/TR/xslt#section-Expressions:
上下文位置来自当前节点列表中当前节点的位置;第一个位置是1
由于您的输入只是一个文本字符串,因此您始终处于位置1.我只能想到使用XSLT执行此操作的一种方法。变换两次。第一个转换为您提供了具有未编号列元素的基本结构。第二个转换对列元素进行编号。因为您是第二次从XML文档中选择节点,position()
应该具有您想要的值。
答案 1 :(得分:2)
看起来csvtoxml
被一个大字符串调用,它以递归的方式通过该字符串。 position()
在这种情况下不起作用,因为您没有使用一组节点。
相反,你可以用计数参数来实现你所追求的目标:
<xsl:template name="csvtoxml">
<!-- import $StringToTransform-->
<xsl:param name="StringToTransform" select="''"/>
<xsl:param name="ColumnNum" select="1"/>
<xsl:choose>
<!-- string contains linefeed-->
<xsl:when test="contains($StringToTransform,',')">
<!-- Get everything up to the first carriage return-->
<xsl:element name="{concat('column', $ColumnNum)}">
<xsl:value-of select="substring-before($StringToTransform,',')"/>
</xsl:element>
<!-- repeat for the remainder of the original string-->
<xsl:call-template name="csvtoxml">
<xsl:with-param name="StringToTransform" select="substring-after($StringToTransform,',')" />
<xsl:with-param name="ColumnNum" select="$ColumnNum + 1" />
</xsl:call-template>
</xsl:when>
<!-- string does not contain newline, so just output it-->
<xsl:otherwise>
<xsl:element name="{concat('column', $ColumnNum)}">
<xsl:value-of select="$StringToTransform" />
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
答案 2 :(得分:2)
虽然OP可能正在寻找XSLT 1.0解决方案,但感兴趣的是XSLT 2.0解决方案。此解决方案要求您下载我的csv-to-xml library style-sheet from here,this blog entry中讨论了这一点。
将此作为输入文档,在样式表中使用uri'gangt.csv'引用(使用参数或根据需要调整)...
3779490,916705,CS,60,34.89,Sauce/Cholula
5918104,918958,CS,6,20.63,Pasta/Fresh/Cavatelli/6#/Frozen
5064774,920723,CS,10,45.5,Cheese/Oaxaca
3422752,925230,EA,8,69.6,Chipotle/Powder/Ground
5955640,BB171,CS,30,50.7,Butter/Unsalted
5295326,BC110005,CS,6000,54.95,Oil/Olive/Finishing
...这个XSLT 2.0样式表...
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:clib="http://www.seanbdurkin.id.au/xslt/csv-to-xml.xslt"
xmlns:xcsv="http://www.seanbdurkin.id.au/xslt/xcsv.xsd"
exclude-result-prefixes="xsl clib xcsv">
<xsl:import href="csv-to-xml.xslt" />
<xsl:output indent="yes" omit-xml-declaration="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="/" >
<data-set>
<xsl:apply-templates select="clib:csv-to-xml('gangt.csv')/xcsv:row" />
</data-set>
</xsl:template>
<xsl:template match="xcsv:row">
<row>
<xsl:apply-templates select="xcsv:value" />
</row>
</xsl:template>
<xsl:template match="xcsv:value">
<xsl:element name="column{position()}">
<xsl:value-of select="." />
</xsl:element>
</xsl:template>
</xsl:stylesheet>
...生成此输出文档......
<data-set>
<row>
<column1>3779490</column1>
<column2>916705</column2>
<column3>CS</column3>
<column4>60</column4>
<column5>34.89</column5>
<column6>Sauce/Cholula</column6>
</row>
<row>
<column1>5918104</column1>
<column2>918958</column2>
<column3>CS</column3>
<column4>6</column4>
<column5>20.63</column5>
<column6>Pasta/Fresh/Cavatelli/6#/Frozen</column6>
</row>
<row>
<column1>5064774</column1>
<column2>920723</column2>
<column3>CS</column3>
<column4>10</column4>
<column5>45.5</column5>
<column6>Cheese/Oaxaca</column6>
</row>
<row>
<column1>3422752</column1>
<column2>925230</column2>
<column3>EA</column3>
<column4>8</column4>
<column5>69.6</column5>
<column6>Chipotle/Powder/Ground</column6>
</row>
<row>
<column1>5955640</column1>
<column2>BB171</column2>
<column3>CS</column3>
<column4>30</column4>
<column5>50.7</column5>
<column6>Butter/Unsalted</column6>
</row>
<row>
<column1>5295326</column1>
<column2>BC110005</column2>
<column3>CS</column3>
<column4>6000</column4>
<column5>54.95</column5>
<column6>Oil/Olive/Finishing</column6>
</row>
</data-set>
答案 3 :(得分:1)
我不确定你为什么在这种情况下选择XSLT。它不是像这样的字符串处理操作的首选,特别是因为你的源数据不是XML,你只是将它包装在一个节点中以使其成为XML。更明显的方法是通过PHP等方式处理CSV。
在任何情况下,要回答这个问题,如果您有权访问EXSLT(这通常适用于XSLT处理器,例如PHP):
Runnable demo here(请参阅输出来源)。
<!-- break into rows -->
<xsl:variable name='rows' select='str:split(root, "
")' />
<!-- root - kick things off -->
<xsl:template match='/'>
<root>
<xsl:apply-templates select='$rows' mode='row' />
</root>
</xsl:template>
<!-- rows -->
<xsl:template match='token' mode='row'>
<xsl:variable name='cols' select='str:split(., ",")' />
<row>
<xsl:apply-templates select='$cols' mode='col' />
</row>
</xsl:template>
<!-- columns -->
<xsl:template match='token' mode='col'>
<xsl:element name='col{position()}'>
<xsl:value-of select='.' />
</xsl:element>
</xsl:template>