XSLT转换QuickBooks XML为CSV时如何移除字段内多余的单双引号
解决方案
核心思路
CSV规范要求字段内部出现的双引号需要转义为两个连续双引号,避免打断字段包裹结构。由于你使用的是XSLT 1.0版本,没有内置replace函数,我们可以通过新增递归命名模板实现双引号转义,再将所有字段输出逻辑替换为调用转义模板即可。
完整修改后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output method="text" encoding="iso-8859-1"/> <xsl:strip-space elements="*" /> <xsl:variable name="delimiter" select="','"/> <xsl:variable name="Quotes" select="'"'"/> <!-- 新增双引号转义模板:将输入字符串中的"替换为"" --> <xsl:template name="escape-quotes"> <xsl:param name="input-str"/> <xsl:choose> <xsl:when test="contains($input-str, '"')"> <xsl:value-of select="substring-before($input-str, '"')"/> <xsl:text>""</xsl:text> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="substring-after($input-str, '"')"/> </xsl:call-template> </xsl:when> <xsl:otherwise> <xsl:value-of select="$input-str"/> </xsl:otherwise> </xsl:choose> </xsl:template> <xsl:template match="/"> <xsl:for-each select="QBXML/QBXMLMsgsRs/GeneralDetailReportQueryRs/ReportRet/ReportData/DataRow"> <xsl:value-of select="$Quotes"/> <!-- 所有取value的位置都调用转义模板 --> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./RowData/@value[../@rowType]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=2]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=3]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=4]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=5]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=6]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=7]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=8]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=9]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=10]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=11]"/> </xsl:call-template> <xsl:value-of select="concat($Quotes,$delimiter,$Quotes)"/> <xsl:call-template name="escape-quotes"> <xsl:with-param name="input-str" select="./ColData/@value[../@colID=12]"/> </xsl:call-template> <xsl:value-of select="$Quotes"/> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
修改说明
- 新增的
escape-quotes模板会递归扫描输入字符串,把所有单双引号替换为两个连续双引号,符合RFC 4180 CSV格式规范 - 所有字段取值位置都替换为调用转义模板,无论字段是否包含双引号都可以正常处理,不会影响无特殊字符的字段输出
- 你给出的问题示例中
Triaxle Stone 2A Modified 3/4"会被转义为Triaxle Stone 2A Modified 3/4"",包裹在双引号中不会导致字段提前闭合错位
内容的提问来源于stack exchange,提问作者moore1emu
相关产品推荐
相关产品推荐

