XSLT 1.0将逗号分隔字符串拆分写入CSV每行的实现
XSLT 1.0 逗号分隔值匹配Person行输出CSV实现方案
核心约束适配
- 兼容XSLT 1.0语法,无需依赖
tokenize()等高版本函数 - 无需修改现有C# Person类结构、无需为Person节点附加额外属性
- 自动适配Person记录数与ItemValue条目数不一致场景,缺项对应位置自动留空
- 保留原有Id、Name、Address字段的正常读取逻辑
实现逻辑
通过递归命名模板实现逗号分隔字符串的按索引取值,遍历Person节点生成CSV行时,直接用当前节点的内置位置序号匹配对应位置的ItemValue条目,不需要改造原有数据结构。递归模板自动处理索引越界场景,找不到对应条目时直接返回空串,符合业务规则要求。
完整可运行XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 逗号分隔ItemValue数据源:如果是C#传参可直接修改select为对应参数名,XML存储则改对应XPath --> <xsl:param name="ItemValueStr" select="/Root/ItemValueStr"/> <xsl:variable name="separator" select="','"/> <!-- CSV字段转义模板:自动处理字段中包含逗号、双引号、换行的格式兼容问题 --> <xsl:template name="escapeCsvField"> <xsl:param name="fieldVal"/> <xsl:choose> <xsl:when test="contains($fieldVal, ',') or contains($fieldVal, '"') or contains($fieldVal, '
')"> <xsl:text>"</xsl:text> <xsl:value-of select="translate($fieldVal, '"', '""')"/> <xsl:text>"</xsl:text> </xsl:when> <xsl:otherwise> <xsl:value-of select="$fieldVal"/> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 递归拆分模板:按索引取分隔字符串对应位置值,索引从1开始,越界自动返回空串 --> <xsl:template name="getSplitItem"> <xsl:param name="sourceStr"/> <xsl:param name="delimiter"/> <xsl:param name="targetIndex"/> <xsl:param name="currentIndex" select="1"/> <xsl:choose> <xsl:when test="$targetIndex < 1"> <xsl:text></xsl:text> </xsl:when> <xsl:when test="$currentIndex = $targetIndex"> <xsl:choose> <xsl:when test="contains($sourceStr, $delimiter)"> <xsl:value-of select="substring-before($sourceStr, $delimiter)"/> </xsl:when> <xsl:otherwise> <xsl:value-of select="$sourceStr"/> </xsl:otherwise> </xsl:choose> </xsl:when> <xsl:when test="not(contains($sourceStr, $delimiter))"> <xsl:text></xsl:text> </xsl:when> <xsl:otherwise> <xsl:call-template name="getSplitItem"> <xsl:with-param name="sourceStr" select="substring-after($sourceStr, $delimiter)"/> <xsl:with-param name="delimiter" select="$delimiter"/> <xsl:with-param name="targetIndex" select="$targetIndex"/> <xsl:with-param name="currentIndex" select="$currentIndex + 1"/> </xsl:call-template> </xsl:otherwise> </xsl:choose> </xsl:template> <!-- 主输出模板 --> <xsl:template match="/"> <!-- 输出CSV表头,可根据实际列顺序调整 --> <xsl:text>Id,Name,Address,ItemValue
</xsl:text> <!-- 遍历所有Person节点,路径与实际XML结构不匹配时直接修改select取值即可 --> <xsl:for-each select="/Root/PersonList/Person"> <xsl:variable name="rowIndex" select="position()"/> <!-- 取当前行对应的ItemValue --> <xsl:variable name="currentItem"> <xsl:call-template name="getSplitItem"> <xsl:with-param name="sourceStr" select="$ItemValueStr"/> <xsl:with-param name="delimiter" select="$separator"/> <xsl:with-param name="targetIndex" select="$rowIndex"/> </xsl:call-template> </xsl:variable> <!-- 拼接CSV行字段 --> <xsl:call-template name="escapeCsvField"> <xsl:with-param name="fieldVal" select="Id"/> </xsl:call-template> <xsl:text>,</xsl:text> <xsl:call-template name="escapeCsvField"> <xsl:with-param name="fieldVal" select="Name"/> </xsl:call-template> <xsl:text>,</xsl:text> <xsl:call-template name="escapeCsvField"> <xsl:with-param name="fieldVal" select="Address"/> </xsl:call-template> <xsl:text>,</xsl:text> <xsl:call-template name="escapeCsvField"> <xsl:with-param name="fieldVal" select="$currentItem"/> </xsl:call-template> <xsl:text>
</xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
调整说明
- 若实际XML中Person节点的层级路径和示例不一致,直接修改
for-each标签的select匹配规则即可 - 千级以内数据量下递归拆分逻辑无性能问题,可覆盖绝大多数业务场景
- 若需要调整CSV列顺序,直接修改主模板中字段拼接的先后顺序即可
内容的提问来源于stack exchange,提问作者SZ_SZ
相关产品推荐
相关产品推荐

