我正在尝试使用Java将xml转换为csv。我编写了一个使用xslt生成csv文件的程序,该程序可用于以下程序:
<xsl:text>PART_ID,TITLE,ITEM_NUMBER,SUBASSEMBLY_ITEM,QUANTITY</xsl:text>
<xsl:text>
</xsl:text>
<xsl:for-each select="//row">
<xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(PART_ID)"/></xsl:call-template>
<xsl:text>,</xsl:text>
<xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(TITLE)"/></xsl:call-template>
<xsl:text>,</xsl:text>
<xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(ITEM_NUMBER)"/></xsl:call-template>
<xsl:text>,</xsl:text>
<xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(SUBASSEMBLY_ITEM)"/></xsl:call-template>
<xsl:text>,</xsl:text>
<xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(QUANTITY)"/></xsl:call-template>
<xsl:text>
</xsl:text>
</xsl:for-each>
使用CsvEscape函数,生成的表格的格式正确,并且数据中的任何逗号在CSV文件中的格式正确。
现在我正在尝试使它动态化,因此它可以在不直接指定表头的情况下适用于任何XML。
<xsl:template match="/">
<xsl:for-each select="//row[1]">
<xsl:for-each select="*">
<xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(name(.))"/></xsl:call-template>
<xsl:text>, </xsl:text>
</xsl:for-each>
</xsl:for-each>
<xsl:text>
</xsl:text>
<xsl:for-each select="//row">
<xsl:for-each select="*">
<xsl:call-template name="CsvEscape"><xsl:with-param name="value" select="normalize-space(.)"/></xsl:call-template>
<xsl:text>, </xsl:text>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
我的XML:
<row>
<PART_ID>15-00002-01</PART_ID>
<TITLE>Shell Assembly</TITLE>
<ITEM_NUMBER>4</ITEM_NUMBER>
<SUBASSEMBLY_ITEM>18-00004-01 - Polyurethane, 4Ply, Hex Cut White Patches</SUBASSEMBLY_ITEM>
<QUANTITY>15.000000000000</QUANTITY>
</row>
注意:xml中的项目中也可以包含“,”,因此我需要通过CsvEscape运行它才能正确显示。
必需的输出是:
PART_ID,TITLE,ITEM_NUMBER,SUBASSEMBLY_ITEM,QUANTITY
15-20002-01,Shell Assembly,1,"18-20003-01 - Polyurethane, 4Ply, Hex Cut Black Patches",16.000000000000
这生成了带有动态生成标题的CSV文件。数据也正在被识别,但是没有通过CsvEscape函数传递,如果我的数据中有逗号,这会弄乱我的CSV文件。
我该如何解决?
答案 0 :(得分:1)
假设此输入XML
<?xml version="1.0" encoding="UTF-8"?>
<rows>
<row>
<cell>PART_ID</cell>
<cell>TITLE</cell>
<cell>ITEM_NUMBER</cell>
<cell>SUBASSEMBLY_ITEM</cell>
<cell>QUANTITY</cell>
</row>
<row>
<cell>id1</cell>
<cell> some title </cell>
<cell>1</cell>
<cell>y;x,z</cell>
<cell>20</cell>
</row>
<row>
<cell>id2</cell>
<cell> another title </cell>
<cell>2</cell>
<cell>q/r|s</cell>
<cell>10</cell>
</row>
</rows>
这是一种基于参数化的基于XPath的解决方案,用于一般生成CSV输出:
<?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="3.0">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:template match="/">
<xsl:sequence select="
let $escapeChar := '"',
$newLine := '
',
$separator := ','
return //row ! (string-join(* ! string-join($escapeChar||normalize-space(.)||$escapeChar),$separator),$newLine)
"/>
</xsl:template>
</xsl:stylesheet>
输出:
"PART_ID","TITLE","ITEM_NUMBER","SUBASSEMBLY_ITEM","QUANTITY"
"id1","some title","1","y;x,z","20"
"id2","another title","2","q/r|s","10"
如果您想要更多基于XSLT的解决方案,建议使用模板:
<xsl:variable name="escapeChar" select="'"'" as="xs:string"/>
<xsl:variable name="separator" select="','" as="xs:string"/>
<xsl:variable name="newLine" select="'
'" as="xs:string"/>
<!-- identity template or shallow-skip -->
<xsl:mode on-no-match="shallow-skip"/>
<xsl:template match="//row">
<xsl:apply-templates select="*"/>
<xsl:value-of select="$newLine"/>
</xsl:template>
<xsl:template match="*[parent::row]">
<xsl:value-of select="$escapeChar"/>
<xsl:value-of select="."/>
<xsl:value-of select="$escapeChar"/>
<xsl:if test="not(position()=last())">
<xsl:value-of select="$separator"/>
</xsl:if>
</xsl:template>