我正在尝试转换与此类似的xml转储
<?xml version="1.0" encoding="UTF-8"?>
<report>
<report_header>
<c1>desc</c1>
<c2>prname</c2>
<c3>prnum</c3>
<c4>cdate</c4>
<c5>phase</c5>
<c6>stype</c6>
<c7>status</c7>
<c8>parent</c8>
<c9>location</c9>
</report_header>
<report_row>
<c1></c1>
<c2>IT Project Message Validation</c2>
<c3>IT-0000021</c3>
<c4>12/14/2010 09:56 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
<report_row>
<c1></c1>
<c2>David, Michael John Morning QA Test</c2>
<c3>IT-0000020</c3>
<c4>12/14/2010 08:12 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
</report>
下面的xslt,到csv。不幸的是,contains函数不起作用。
<?xml version="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:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="report">
<xsl:apply-templates select="report_header"/>
<xsl:apply-templates select="report_row"/>
</xsl:template>
<xsl:template match="report_header">
<xsl:for-each select="*">
<xsl:value-of select="."/>
<xsl:if test="position() != last()">
<xsl:value-of select="','"/>
</xsl:if>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:template>
<xsl:template match="report_row">
<xsl:param name="value" />
<xsl:for-each select="*">
<xsl:value-of select="$value" />
<xsl:if test="(contains($value,','))">
<xsl:text>"</xsl:text><xsl:value-of select="."/><xsl:text>"</xsl:text>
</xsl:if>
<xsl:if test="not(contains($value,','))">
<xsl:value-of select="."/>
</xsl:if>
<xsl:if test="position() != last()">
<xsl:value-of select="','"/>
</xsl:if>
</xsl:for-each>
<xsl:if test="position() != last()">
<xsl:text>
</xsl:text>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
我得到以下转储。我期望在第二行的prname列周围有限定符。
desc,prname,prnum,cdate,phase,stype,status,parent,location
,IT Project Message Validation,IT-0000021,12/14/2010 09:56 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
,David, Michael John Morning QA Test,IT-0000020,12/14/2010 08:12 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
我只使用了coldfusion xmltransform函数来测试它。
答案 0 :(得分:2)
提供的代码存在问题,其中一些代码在Mads Hansen的回答中报道。
主要问题是代码不必要复杂。
以下是一个简单的解决方案,可以产生看似想要的东西:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="report_header/*">
<xsl:value-of select="."/>
<xsl:call-template name="processEnd"/>
</xsl:template>
<xsl:template match="report_row/*[contains(., ',')]">
<xsl:text>"</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
<xsl:call-template name="processEnd"/>
</xsl:template>
<xsl:template match="report_row/*[not(contains(., ','))]">
<xsl:value-of select="."/>
<xsl:call-template name="processEnd"/>
</xsl:template>
<xsl:template name="processEnd">
<xsl:choose>
<xsl:when test="position() != last()">,</xsl:when>
<xsl:otherwise><xsl:text> </xsl:text></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
应用于提供的XML文档:
<report>
<report_header>
<c1>desc</c1>
<c2>prname</c2>
<c3>prnum</c3>
<c4>cdate</c4>
<c5>phase</c5>
<c6>stype</c6>
<c7>status</c7>
<c8>parent</c8>
<c9>location</c9>
</report_header>
<report_row>
<c1></c1>
<c2>IT Project Message Validation</c2>
<c3>IT-0000021</c3>
<c4>12/14/2010 09:56 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
<report_row>
<c1></c1>
<c2>David, Michael John Morning QA Test</c2>
<c3>IT-0000020</c3>
<c4>12/14/2010 08:12 AM</c4>
<c5>Preparation</c5>
<c6>IT Projects</c6>
<c7>Active</c7>
<c8>IT</c8>
<c9>/IT/BIOMED</c9>
</report_row>
</report>
产生了想要的正确结果:
desc,prname,prnum,cdate,phase,stype,status,parent,location ,IT Project Message Validation,IT-0000021,12/14/2010 09:56 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED ,"David, Michael John Morning QA Test",IT-0000020,12/14/2010 08:12 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
答案 1 :(得分:1)
我认为contains()
不是您的问题。
问题是, report_row 模板的<xsl:param name="value"/>
永远不会分配值。你有从这个参数驱动的逻辑,它永远不会激发。由于$value
为空,因此永远不会contain()
,
或任何其他字符。
您可以通过向select
添加xsl:param
属性来获得所需的行为:
<xsl:template match="report_row">
<xsl:param name="value" select="." />
您可以通过制作更多“推送”样式来简化样式表和逻辑,这种样式比尝试在XSLT中实现过程逻辑的“拉”式样式表更容易调试和维护。
以下样式表之类的内容实现了同样的目的:
<?xml version="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:template match="/">
<xsl:apply-templates select="*/report_header/*"/>
<xsl:apply-templates select="*/report_row/*"/>
</xsl:template>
<!-- For all but the last item, apply templates for the content, then add a comma -->
<xsl:template match="*[following-sibling::*]">
<xsl:apply-templates/>
<xsl:text>,</xsl:text>
</xsl:template>
<!-- If it's the last element in a group, add a newline char -->
<xsl:template match="*[not(following-sibling::*)]">
<xsl:apply-templates />
<!--Line break-->
<xsl:text> </xsl:text>
</xsl:template>
<!-- If any values contains a comma, wrap it in quotes -->
<xsl:template match="text()[contains(.,',')]">
<xsl:text>"</xsl:text>
<xsl:value-of select="."/>
<xsl:text>"</xsl:text>
</xsl:template>
</xsl:stylesheet>
生成以下输出:
desc,prname,prnum,cdate,phase,stype,status,parent,location
,IT Project Message Validation,IT-0000021,12/14/2010 09:56 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED
,"David, Michael John Morning QA Test",IT-0000020,12/14/2010 08:12 AM,Preparation,IT Projects,Active,IT,/IT/BIOMED