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

如何在XSLT转换中复用父节点值?实现嵌套XML转扁平CSV

深度嵌套XML转扁平CSV的XSLT正确实现

嘿,我看你已经摸到门路了,但在循环逻辑和父节点值的复用绑定上还有点小问题,咱们一步步来解决这个需求:

你的核心需求是:遍历到最底层的<stock>节点(属于<availability>),同时把上层<category>、<element>的字段值复制到每一行CSV里,每个<stock>对应一行,对吧?

推荐的XSLT实现(XSLT 3.0)

这里给你两种可行的写法,都是围绕“让每个<stock>生成一行,同时带上所有父节点数据”这个核心逻辑:

方案一:从最内层节点向上回溯(更简洁)

这种写法直接从最底层的<stock>入手,通过轴向上查找父节点的值,逻辑清晰且代码简洁:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
    
    <!-- 每个<stock>生成一行CSV -->
    <xsl:template match="stock">
        <!-- 获取顶层category的type值 -->
        <xsl:value-of select="ancestor::market/category/type"/>
        <xsl:text>,</xsl:text>
        <!-- 获取当前stock所属element的字段 -->
        <xsl:value-of select="ancestor::element/(name, type, color)" separator=","/>
        <xsl:text>,</xsl:text>
        <!-- 获取当前stock的属性 -->
        <xsl:value-of select="@cat, @in" separator=","/>
        <xsl:text>&#10;</xsl:text> <!-- 换行符 -->
    </xsl:template>
    
    <!-- 忽略XML中的空白文本,避免输出冗余内容 -->
    <xsl:template match="text()"/>
</xsl:stylesheet>

方案二:嵌套循环(和你的思路更贴近)

如果你更习惯从外层节点开始遍历,也可以用嵌套循环的方式,先遍历<element>,再遍历每个<element>下的<stock>,同时把父节点的值存到变量里复用:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
    
    <xsl:template match="market">
        <!-- 先存好顶层category的type值,后续复用 -->
        <xsl:variable name="category-type" select="category/type"/>
        
        <!-- 遍历每个element -->
        <xsl:for-each select="items/element">
            <!-- 存当前element的所有字段,和category值拼在一起 -->
            <xsl:variable name="element-data" select="$category-type, name, type, color" separator=","/>
            
            <!-- 遍历当前element下的每个stock,生成一行 -->
            <xsl:for-each select="availability/stock">
                <xsl:value-of select="$element-data, @cat, @in" separator=","/>
                <xsl:text>&#10;</xsl:text>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

为什么你的初始代码没生效?

咱们来分析下你最初的代码问题:

  • 你用了三个独立的for-each,分别遍历category、element、stock,这会导致所有category值先一次性输出,然后是所有element值,最后是所有stock值,完全没有把父节点和子节点的数据对应起来,自然得不到每行关联的结果。

而你提到的第二段代码其实方向是对的,但有几个小瑕疵:

  • $ctype的路径写错了:market/category/type应该改成category/type(因为当前模板匹配的是market,直接访问子节点即可)
  • 用copy-of(.)!(.//name, .//type, .//color)有点冗余,直接用name, type, color就可以
  • 开头多了个;,会导致每行第一个字段前有多余的分隔符

测试结果

用你提供的示例XML测试,两种方案都会输出符合预期的CSV:

kids,police car,toy,blue,A,5
kids,police car,toy,blue,B,2

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:06:26