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

如何使用XSL生成类CSV格式?附相关XSL代码片段

嘿,我来帮你搞定用XSL生成标准CSV格式的事儿!看你贴的代码片段,应该是在处理CD目录数据,但目前的逻辑有点小问题——比如重复判断最后一个cd元素,而且没处理字段分隔、换行,更重要的是没考虑CSV里的特殊字符(这可是踩坑重灾区)。

先给你一个完整的、健壮的实现,然后拆解关键部分:

完整XSL代码示例

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 匹配根目录节点,开始生成CSV -->
    <xsl:template match="/catalog">
        <!-- 先输出CSV表头,和你的CD字段对应,可按需修改 -->
        <xsl:text>Artist,Title,Year,Price&#xD;&#xA;</xsl:text>
        
        <!-- 遍历每一张CD -->
        <xsl:for-each select="cd">
            <!-- 依次输出每个字段,用逗号分隔 -->
            <xsl:apply-templates select="artist"/>
            <xsl:text>,</xsl:text>
            <xsl:apply-templates select="title"/>
            <xsl:text>,</xsl:text>
            <xsl:apply-templates select="year"/>
            <xsl:text>,</xsl:text>
            <xsl:apply-templates select="price"/>
            
            <!-- 除了最后一行,每行末尾加换行符 -->
            <xsl:if test="position() != last()">
                <xsl:text>&#xD;&#xA;</xsl:text>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>

    <!-- 核心:处理CSV特殊字符,避免解析错误 -->
    <xsl:template match="text()">
        <xsl:choose>
            <!-- 如果字段包含逗号或双引号,用双引号包裹,内部双引号转成两个(CSV标准要求) -->
            <xsl:when test="contains(., ',') or contains(., '&quot;')">
                <xsl:text>"</xsl:text>
                <xsl:value-of select="translate(., '&quot;', '&quot;&quot;')"/>
                <xsl:text>"</xsl:text>
            </xsl:when>
            <!-- 普通内容直接输出 -->
            <xsl:otherwise>
                <xsl:value-of select="."/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

关键细节说明

  1. 表头与换行:
    先定义好CSV的列名,和你的XML字段一一对应。用&#xD;&#xA;表示Windows风格的换行(如果是Unix/Linux环境,只用&#xA;就行),确保生成的CSV能被表格软件正确识别。

  2. 字段分隔与行处理:
    每个cd元素对应CSV的一行,字段之间用逗号分隔。最后一行不输出多余的换行,避免生成空行。

  3. 特殊字符处理:
    这是最容易忽略的点!如果你的CD字段里有逗号(比如艺术家名字是"Doe, John")或者双引号,直接输出会导致CSV解析错乱。上面的代码会自动把这类字段用双引号包裹,并且把字段内部的双引号转成两个(比如"He said ""Hello"""),完全符合CSV标准。

如果你需要动态适配字段

如果你的XML中cd的子元素不是固定的(比如可能新增字段),可以改成动态遍历的方式,不用硬编码字段名:

<!-- 动态生成表头 -->
<xsl:for-each select="cd[1]/*">
    <xsl:value-of select="name()"/>
    <xsl:if test="position() != last()">
        <xsl:text>,</xsl:text>
    </xsl:if>
</xsl:for-each>
<xsl:text>&#xD;&#xA;</xsl:text>

<!-- 动态遍历每个CD的子元素 -->
<xsl:for-each select="cd">
    <xsl:for-each select="*">
        <xsl:apply-templates/>
        <xsl:if test="position() != last()">
            <xsl:text>,</xsl:text>
        </xsl:if>
    </xsl:for-each>
    <xsl:if test="position() != last()">
        <xsl:text>&#xD;&#xA;</xsl:text>
    </xsl:if>
</xsl:for-each>

你的原有代码问题分析

你原来的代码里,重复判断了position() = last(),而且直接取./child::*会把所有子元素的内容连在一起,没有分隔,这样生成的内容根本不是标准的CSV格式。另外缺少特殊字符处理,很容易出问题。

内容的提问来源于stack exchange,提问作者Hat hout

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 07:49:14