XSLT 3.0 XML转CSV:拆分属性多值为CSV单独行
XSLT 3.0 实现XML转CSV并拆分属性值为多行
这事儿用XSLT 3.0处理起来挺顺手的,核心就是用tokenize()函数把ana属性里的空格分隔值拆成序列,然后遍历这个序列生成单独的CSV行就行。给你写个完整的样式表示例,直接就能适配你的源XML:
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 设置输出为纯文本格式,适配CSV --> <xsl:output method="text" media-type="text/csv" encoding="UTF-8"/> <!-- 处理根节点,先输出CSV表头 --> <xsl:template match="/"> <xsl:text>deposition-number,seg-number,persName-name,ana-value </xsl:text> <xsl:apply-templates select="//persName"/> </xsl:template> <!-- 处理每个persName节点,拆分ana属性生成多行 --> <xsl:template match="persName"> <!-- 获取当前persName所属的上层节点属性值 --> <xsl:variable name="depositionNum" select="ancestor::deposition/deposition-number/@n"/> <xsl:variable name="segNum" select="ancestor::seg/@n"/> <xsl:variable name="persNameValue" select="@name"/> <!-- 拆分ana属性的空格分隔值,遍历每个值生成一行 --> <xsl:for-each select="tokenize(@ana, '\s+')"> <!-- 拼接CSV行,注意如果字段包含逗号/引号需要额外处理,这里先给基础版 --> <xsl:value-of select="$depositionNum, $segNum, $persNameValue, current()" separator=","/> <xsl:text> </xsl:text> </xsl:for-each> </xsl:template> </xsl:stylesheet>
代码说明:
tokenize(@ana, '\s+'):用正则表达式匹配一个或多个空格,把ana属性值拆分成字符串序列,完美处理多个连续空格的情况- 用
ancestor::轴获取当前persName所属的deposition和seg节点的属性值,确保每行都能关联到正确的上下文 - 输出时用
separator=","自动拼接字段, 是换行符,保证每行数据单独占一行
示例输出:
运行上面的样式表后,你的源XML会生成如下CSV内容:
deposition-number,seg-number,persName-name,ana-value dep1,seg1,personA,foo1 dep1,seg1,personA,foo2
进阶优化(处理特殊字符):
如果你的字段里可能包含逗号、双引号这类CSV特殊字符,可以加一个辅助函数来给字段套上双引号,并转义内部的双引号:
<xsl:function name="local:quote" as="xs:string"> <xsl:param name="value" as="xs:string"/> <xsl:choose> <!-- 如果字段包含逗号或双引号,就用双引号包裹并转义内部的双引号 --> <xsl:when test="contains($value, ',') or contains($value, '"')"> <xsl:text>"</xsl:text> <xsl:value-of select="replace($value, '"', '""')"/> <xsl:text>"</xsl:text> </xsl:when> <xsl:otherwise> <xsl:value-of select="$value"/> </xsl:otherwise> </xsl:choose> </xsl:function>
然后把生成行的代码改成:
<xsl:value-of select="local:quote($depositionNum), local:quote($segNum), local:quote($persNameValue), local:quote(current())" separator=","/>
这样就能保证CSV格式的严格正确性了。
内容的提问来源于stack exchange,提问作者jbrehr
相关产品推荐
相关产品推荐

