如何用XSL 1.0将逗号分隔行转换为XML(含带引号内容)
XSLT处理带引号的CSV文本转XML结构
需求场景
输入的XML包含一段CSV格式的文本,其中部分字段用双引号包裹(字段内包含逗号),需要将这段CSV文本拆分为<column>节点,保留原始字段内容并去掉包裹的双引号。
输入内容
<raw> Value1,Value2,Value3,Value4,Value5,"Paris,France" </raw>
期望输出
<raw> <column>Value1</column> <column>Value2</column> <column>Value3</column> <column>Value4</column> <column>Value5</column> <column>Paris,France</column> </raw>
现有代码问题分析
你当前的代码假设输入已经是结构化的<RawData>、<row>、<column>节点,但实际输入是<raw>节点内的纯CSV文本,完全不匹配输入结构;同时没有处理带引号的字段,无法识别字段内的逗号不是分隔符。
正确的XSLT 1.0实现方案
下面是适配需求的XSLT代码,通过递归模板处理CSV拆分,同时支持带引号的字段:
<?xml version="1.0" encoding="utf-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 匹配根节点,复制<raw>标签 --> <xsl:template match="raw"> <raw> <!-- 调用拆分模板,处理<raw>内的文本内容 --> <xsl:call-template name="split-csv"> <xsl:with-param name="text" select="normalize-space(.)"/> </xsl:call-template> </raw> </xsl:template> <!-- 递归拆分CSV的核心模板 --> <xsl:template name="split-csv"> <xsl:param name="text"/> <xsl:param name="delimiter" select="','"/> <xsl:choose> <!-- 情况1:文本以双引号开头,处理带引号的字段 --> <xsl:when test="starts-with($text, '"')"> <!-- 找到闭合的双引号位置 --> <xsl:variable name="quote-end" select="substring-after($text, '"')"/> <xsl:variable name="field" select="substring-before($quote-end, '"')"/> <!-- 输出字段,去掉引号 --> <column><xsl:value-of select="$field"/></column> <!-- 处理剩余文本:跳过闭合引号后的分隔符,继续递归 --> <xsl:variable name="remaining" select="substring-after($quote-end, concat('"', $delimiter))"/> <xsl:if test="$remaining != ''"> <xsl:call-template name="split-csv"> <xsl:with-param name="text" select="$remaining"/> </xsl:call-template> </xsl:if> </xsl:choose> <!-- 情况2:普通字段,按分隔符拆分 --> <xsl:when test="contains($text, $delimiter)"> <column><xsl:value-of select="substring-before($text, $delimiter)"/></column> <!-- 递归处理剩余文本 --> <xsl:call-template name="split-csv"> <xsl:with-param name="text" select="substring-after($text, $delimiter)"/> </xsl:call-template> </xsl:when> <!-- 情况3:最后一个字段,直接输出 --> <xsl:otherwise> <xsl:if test="$text != ''"> <column><xsl:value-of select="$text"/></column> </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 匹配文本节点,避免默认输出 --> <xsl:template match="text()"/> </xsl:stylesheet>
关键逻辑说明
- 匹配
<raw>节点:保留外层<raw>标签,调用拆分模板处理内部文本,用normalize-space()去除首尾空白(包括换行)。 - 递归拆分模板:
- 优先处理以双引号开头的字段:先找到闭合的双引号,提取中间内容作为字段值,然后跳过引号后的分隔符,继续处理剩余文本。
- 处理普通字段:按逗号分隔符拆分,提取第一个字段后递归处理剩余内容。
- 处理最后一个字段:直接输出剩余的非空文本。
- 抑制默认文本输出:最后一个模板匹配所有文本节点,避免原始CSV文本直接输出到结果中。
内容的提问来源于stack exchange,提问作者Ram Rao
相关产品推荐
相关产品推荐

