You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何调整XSLT 1.0以保留CSV空令牌并转换为指定XML?

调整XSLT 1.0代码处理含空令牌的CSV生成目标XML

问题背景

你手头有一份包含空令牌的CSV数据,现有的XSLT 1.0代码会跳过这些空值,而且原本是生成层级XML结构,但现在需要改成每个CSV行对应一个<data>节点的格式,每个列要对应表头指定的元素名称。

输入示例

<root>
GroupName,GroupValue,SubGroupName,SubGroupValue,ItemName,ItemValue
,A,1,C,1,G
1,,1,C,2,H
1,A,2,D,1,I
</root>

现有XSLT的核心问题

原代码的tokenize模板通过<xsl:if test="$token">判断跳过了空令牌,同时输出逻辑是按group层级聚合,完全不符合现在的目标输出结构。

修改后的XSLT代码

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
extension-element-prefixes="exsl">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="/">
    <!-- 拆分CSV为行 -->
    <xsl:variable name="rows">
        <xsl:call-template name="tokenize">
            <xsl:with-param name="text" select="root"/>
        </xsl:call-template>
    </xsl:variable>
    
    <!-- 提取表头并拆分 -->
    <xsl:variable name="header-row" select="exsl:node-set($rows)/row[1]"/>
    <xsl:variable name="headers">
        <xsl:call-template name="tokenize">
            <xsl:with-param name="text" select="$header-row"/>
            <xsl:with-param name="delimiter" select="','"/>
            <xsl:with-param name="name" select="'header'"/>
        </xsl:call-template>
    </xsl:variable>
    
    <!-- 处理数据行,拆分每个行为cell元素 -->
    <xsl:variable name="data-rows">
        <xsl:for-each select="exsl:node-set($rows)/row[position() > 1]">
            <row>
                <xsl:call-template name="tokenize">
                    <xsl:with-param name="text" select="."/>
                    <xsl:with-param name="delimiter" select="','"/>
                    <xsl:with-param name="name" select="'cell'"/>
                </xsl:call-template>
            </row>
        </xsl:for-each>
    </xsl:variable>
    
    <!-- 生成目标XML结构 -->
    <Document>
        <xsl:for-each select="exsl:node-set($data-rows)/row">
            <data>
                <xsl:for-each select="cell">
                    <xsl:variable name="pos" select="position()"/>
                    <!-- 用表头名称作为元素名,匹配对应位置的cell值 -->
                    <xsl:element name="{exsl:node-set($headers)/header[$pos]}">
                        <xsl:value-of select="."/>
                    </xsl:element>
                </xsl:for-each>
            </data>
        </xsl:for-each>
    </Document>
</xsl:template>

<xsl:template name="tokenize">
    <xsl:param name="text"/>
    <xsl:param name="delimiter" select="'&#10;'"/>
    <xsl:param name="name" select="'row'"/>
    <xsl:variable name="token" select="substring-before(concat($text, $delimiter), $delimiter)" />
    <!-- 移除空token判断,确保空值也生成对应元素 -->
    <xsl:element name="{$name}">
        <xsl:value-of select="$token"/>
    </xsl:element>
    <xsl:if test="contains($text, $delimiter)">
        <!-- 递归拆分剩余内容 -->
        <xsl:call-template name="tokenize">
            <xsl:with-param name="text" select="substring-after($text, $delimiter)"/>
            <xsl:with-param name="delimiter" select="$delimiter"/>
            <xsl:with-param name="name" select="$name"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

关键修改说明

  • 修复空令牌丢失:删掉了tokenize模板中判断$token是否为空的<xsl:if test="$token">,这样即使是空字符串也会生成对应的<cell>或<header>元素,完整保留所有空值。
  • 重构输出逻辑:放弃了原有的层级聚合逻辑,改成:
    1. 先提取CSV的表头行,拆分成<header>元素集合;
    2. 遍历每个数据行,将每个<cell>和对应位置的表头名称绑定,生成以表头命名的元素;
    3. 每个数据行对应一个<data>节点,最终统一包裹在<Document>根节点下。

生成的目标输出

<?xml version="1.0" encoding="utf-8"?>
<Document>
  <data>
    <GroupName></GroupName>
    <GroupValue>A</GroupValue>
    <SubGroupName>1</SubGroupName>
    <SubGroupValue>C</SubGroupValue>
    <ItemName>1</ItemName>
    <ItemValue>G</ItemValue>
  </data>
  <data>
    <GroupName>1</GroupName>
    <GroupValue></GroupValue>
    <SubGroupName>1</SubGroupName>
    <SubGroupValue>C</SubGroupValue>
    <ItemName>2</ItemName>
    <ItemValue>H</ItemValue>
  </data>
  <data>
    <GroupName>1</GroupName>
    <GroupValue>A</GroupValue>
    <SubGroupName>2</SubGroupName>
    <SubGroupValue>D</SubGroupValue>
    <ItemName>1</ItemName>
    <ItemValue>I</ItemValue>
  </data>
</Document>

内容的提问来源于stack exchange,提问作者E. Xue

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:27:01