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

基于Saxon 11HE的多扁平XML转树形XML的XSLT实现问题

基于Saxon 11HE的扁平XML转树形结构优化方案

针对你提到的三个核心问题,结合Saxon 11HE对XSLT 3.0的支持,以下是高效且简洁的解决方案:


核心优化思路

先通过索引预构建减少重复查询,再通过变量与key机制切换上下文,最后嵌入排序逻辑完成层级转换。

预定义索引(解决重复查询问题)

在XSLT顶层定义两个索引,利用Saxon的预构建索引特性实现O(1)级查询效率:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 按OBJECTID索引1.xml中的地址对象 -->
    <xsl:key name="object-by-id" match="OBJECT" use="@OBJECTID"/>
    <!-- 按PARENTOBJID索引2.xml中的层级关联 -->
    <xsl:key name="child-items" match="ITEM" use="@PARENTOBJID"/>

    <!-- 预加载两个输入文档到变量,避免重复调用document() -->
    <xsl:variable name="address-data" select="document('1.xml')"/>
    <xsl:variable name="hierarchy-data" select="document('2.xml')"/>

问题1:在xsl:for-each中切换回1.xml的上下文

有两种直接可行的方式:

  1. 通过key指定上下文:不需要切换整个for-each的上下文,直接在查询时指定1.xml作为key的作用域:
    <!-- 示例:在遍历2.xml的ITEM时,获取对应1.xml的OBJECT节点 -->
    <xsl:variable name="current-object" select="key('object-by-id', @OBJECTID, $address-data)"/>
    
  2. 直接遍历变量中的1.xml节点:如果需要在for-each中直接操作1.xml的节点,将select指向预加载的变量即可:
    <xsl:for-each select="$address-data//OBJECT[@LEVEL='REGION']">
        <!-- 此处上下文即为1.xml中的OBJECT节点 -->
    </xsl:for-each>
    

问题2:高效匹配对象属性,避免重复查询

核心就是利用前面定义的两个索引:

  • 查询某个OBJECTID对应的地址对象:key('object-by-id', $target-id, $address-data)
  • 查询某个父节点下的所有子关联:key('child-items', $parent-id, $hierarchy-data)

Saxon会在文档加载时一次性构建索引,后续查询无需重复遍历整个文档,大数据量场景下性能提升明显。


问题3:按OBJECT的@NAME属性排序

在遍历节点的<xsl:for-each>中嵌入<xsl:sort>元素,直接关联对应OBJECT的NAME属性即可。如果是中文排序,可添加lang="zh"确保排序规则符合语言习惯:

<xsl:for-each select="key('child-items', $parent-id, $hierarchy-data)">
    <xsl:variable name="child-object" select="key('object-by-id', @OBJECTID, $address-data)"/>
    <!-- 按NAME排序,支持多语言规则 -->
    <xsl:sort select="$child-object/@NAME" lang="zh"/>
    
    <!-- 生成对应层级的元素 -->
    <xsl:element name="{translate($child-object/@LEVEL, ' ', '_')}">
        <xsl:copy-of select="$child-object/@*"/>
        <!-- 递归处理子节点 -->
        <xsl:call-template name="process-children">
            <xsl:with-param name="parent-id" select="@OBJECTID"/>
        </xsl:call-template>
    </xsl:element>
</xsl:for-each>

完整递归转换模板

<xsl:template match="/">
    <ROOT>
        <!-- 处理顶级节点(PARENTOBJID为空的层级) -->
        <xsl:for-each select="$hierarchy-data//ITEM[not(@PARENTOBJID) or @PARENTOBJID='']">
            <xsl:variable name="top-object" select="key('object-by-id', @OBJECTID, $address-data)"/>
            <xsl:element name="{translate($top-object/@LEVEL, ' ', '_')}">
                <xsl:copy-of select="$top-object/@*"/>
                <xsl:call-template name="process-children">
                    <xsl:with-param name="parent-id" select="@OBJECTID"/>
                </xsl:call-template>
            </xsl:element>
        </xsl:for-each>
    </ROOT>
</xsl:template>

<xsl:template name="process-children">
    <xsl:param name="parent-id"/>
    <!-- 遍历当前父节点的所有子关联并排序 -->
    <xsl:for-each select="key('child-items', $parent-id, $hierarchy-data)">
        <xsl:variable name="child-object" select="key('object-by-id', @OBJECTID, $address-data)"/>
        <xsl:sort select="$child-object/@NAME"/>
        
        <xsl:element name="{translate($child-object/@LEVEL, ' ', '_')}">
            <xsl:copy-of select="$child-object/@*"/>
            <!-- 递归处理下一级子节点 -->
            <xsl:call-template name="process-children">
                <xsl:with-param name="parent-id" select="@OBJECTID"/>
            </xsl:call-template>
        </xsl:element>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 04:36:17