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

如何用XSLT 2.0/3.0分组相邻XML元素并调整嵌套结构

修改XSLT实现相邻元素包裹需求

需要调整现有XSLT代码,将所有与name属性包含level_的<p>元素相邻的非层级元素(如<table>、<note>、<reference>、<example>、<image>等),作为子元素包裹到前一个会转换为<li>标签的<p>元素中。


源XML

<root>
    <header>Header text</header>
    <p name="paragraph">Normal Paragraph</p>
    <p name="level_1">Value 1</p>
    <p name="level_1">Value 2 table</p>
    <table frame="all" rowsep="1" colsep="1"   
    id="table_whs_jmk_hzb">
    <title>table1</title>
    <tgroup cols="2" align="center">
    <colspec colname="c1" colnum="1" colwidth="1*"/>
    <colspec colname="c2" colnum="2" colwidth="1*"/>
    <thead>
    <row>
    <entry>Header 1</entry>
    <entry>Header 2</entry>
    </row>
    </thead>
    <tbody>
    <row>
    <entry>Testing cell 1 text</entry>
    <entry>Testing cell 2</entry>
    </row>
    </tbody>
    </tgroup>
    </table>
    <p name="level_2">Value 3</p>
    <p name="level_2">Value 4</p>
    <p name="level_1">Value 5 note</p>
    <note>Another element</note>
    <p name="level_1">Another Value 1</p>
    <p name="level_2">Another Value 2</p>
    <p name="level_2">Another Value 3 reference</p>
    <reference>Some reference text</reference>
    <p name="level_3">Another Value 4</p>
    <p name="level_3">Another Value 5 example</p>
    <example>Example text goes here</example>
    <p name="level_4">Another Value 3 image</p>
    <image src="./output/media/img(1).jpg"/>
    <p name="level_4">Another Value 4</p>
    <p name="level_1">Another Value 5</p>
    <p name="level_1">Another Value 6</p>
</root>

期望输出

<root>
    <header>Header text</header>
    <p name="paragraph">Normal Paragraph</p>
    <ol outputclass="ol-level_1 ">
    <li outputclass="li-level_1 ">Value 1</li>
    <li outputclass="li-level_1 ">Value 2 table <table frame="all" 
    rowsep="1" colsep="1"
    id="table_whs_jmk_hzb">
    <title>table1</title>
    <tgroup cols="2" align="center">
    <colspec colname="c1" colnum="1" colwidth="1*"/>
    <colspec colname="c2" colnum="2" colwidth="1*"/>
    <thead>
    <row>
    <entry>Header 1</entry>
    <entry>Header 2</entry>
    </row>
    </thead>
    <tbody>
    <row>
    <entry>Testing cell 1 text</entry>
    <entry>Testing cell 2</entry>
    </row>
    </tbody>
    </tgroup>
    </table>
    <ol outputclass="ol-level-2 ">
    <li outputclass="li-level_2 ">Value 3</li>
    <li outputclass="li-level_2 ">Value 4</li>
    </ol>
    </li>
    <li outputclass="li-level_1 ">Value 5 note <note>Another   
    element</note>
    </li>
   <li outputclass="li-level_1 ">Another Value 1 
   <ol outputclass="ol-level-2 ">
   <li outputclass="li-level_2 ">Another Value 2</li>
   <li outputclass="li-level_2 ">Another Value 3 reference 
   <reference>Some reference text</reference>
   <ol outputclass="ol-level-3 ">
   <li outputclass="li-level_3 ">Another Value 4</li>
   <li outputclass="li-level_3 ">Another Value 5 example  
   <example>Example text goes here</example>
   <ol outputclass="ol-level-4 ">
   <li outputclass="li-level_4 ">Another Value 3 image 
   <image src="./output/media/img(1).jpg"/></li>
   <li outputclass="li-level_4 ">Another Value 4</li>
   </ol></li></ol></li></ol></li>
    <li outputclass="li-level_1 ">Another Value 5</li>
    <li outputclass="li-level_1 ">Another Value 6</li>
    </ol></root>

修改后的XSLT代码

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="#all" version="3.0">
    <xsl:output method="xml" indent="yes"/>

    <xsl:function name="mf:group" as="node()*">
        <xsl:param name="items" as="element()*"/>
        <xsl:param name="level" as="xs:integer"/>
        
        <xsl:for-each-group select="$items" group-starting-with="p[@name = 'level_' || $level]">
            <xsl:choose>
                <xsl:when test="self::p[@name = 'level_' || $level]">
                    <li outputclass="li-{@name}">
                        <!-- 输出当前<p>的文本内容 -->
                        <xsl:apply-templates/>
                        
                        <!-- 输出当前组内非层级元素(如table、note、reference等) -->
                        <xsl:apply-templates select="current-group()[not(self::p[@name matches 'level_\d+'])]"/>
                        
                        <!-- 递归处理下一层级的<p>元素 -->
                        <xsl:variable name="next-level" select="$level + 1"/>
                        <xsl:where-populated>
                            <ol outputclass="ol-level-{$next-level}">
                                <xsl:sequence select="mf:group(current-group()[self::p[@name = 'level_' || $next-level]], $next-level)"/>
                            </ol>
                        </xsl:where-populated>
                    </li>
                </xsl:when>
                <xsl:otherwise>
                    <!-- 处理不在任何层级<p>开头的元素(理论上不会出现,除非输入有异常) -->
                    <xsl:apply-templates select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:function>

    <xsl:template match="root">
        <root>
            <xsl:copy-of select="header"/>
            <xsl:copy-of select="p[@name = 'paragraph']"/>
            <ol outputclass="ol-level_1 ">
                <!-- 传入所有需要处理的元素:除header和普通段落外的所有元素 -->
                <xsl:sequence select="mf:group(* except (header, p[@name='paragraph']), 1)"/>
            </ol>
        </root>
    </xsl:template>

    <!-- 保留原有的元素复制模板,新增reference处理 -->
    <xsl:template match="note | example | table | image | reference">
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

关键修改说明

  1. Root模板范围扩展:
    原代码仅传入层级<p>元素,现在改为传入root下除<header>和普通段落外的所有元素,确保相邻非层级元素被纳入处理流程。

  2. 分组后元素处理逻辑:
    在mf:group函数中,生成<li>后,先输出当前<p>的内容,再直接将组内的非层级元素(如<table>、<note>)作为<li>的子元素输出,实现包裹需求。

  3. 层级递归优化:
    筛选当前组内的下一层级<p>元素,递归调用分组函数生成对应的<ol>列表,保持原有层级结构的正确性。

  4. 元素模板扩展:
    新增<reference>元素的复制模板,确保所有需要保留的元素都能正确输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 05:49:53