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

基于Xpath //book/part/chapter/sect拆分XML的XSLT实现求助

基于XPath拆分XML的XSLT解决方案

需求背景

需要将XML文件按//book/part/chapter/sect节点拆分,每个输出文件保留完整的<book>层级结构,仅包含单个<sect>节点;同时要求第一个输出文件保留<prelims>节点,其余输出文件移除该节点。

原始XML代码

<book>
<prelims>This is prelims</prelims>
<part>This is part
<chapter>This is Chapter
<level><sect>This is sect1</sect></level>
<level><sect>This is sect2</sect></level>
<level><sect>This is sect3</sect></level>
<level><sect>This is sect4</sect></level>
</chapter>
</part>
</book>

期望拆分输出

  • 输出1(含prelims):
<book>
<prelims>This is prelims</prelims>
<part>This is part
<chapter>This is Chapter
<level><sect>This is sect1</sect></level>
</chapter>
</part>
</book>
  • 输出2:
<book>
<part>This is part
<chapter>This is Chapter
<level><sect>This is sect2</sect></level>
</chapter>
</part>
</book>
  • 输出3:
<book>
<part>This is part
<chapter>This is Chapter
<level><sect>This is sect3</sect></level>
</chapter>
</part>
</book>
  • 输出4:
<book>
<part>This is part
<chapter>This is Chapter
<level><sect>This is sect4</sect></level>
</chapter>
</part>
</book>

现有XSLT代码问题

当前代码仅复制了sect节点本身,未保留完整的<book>层级结构,也未处理<prelims>的显示逻辑,且xsl:for-each select="."属于冗余操作,无法实现预期效果:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="no" exclude-result-prefixes="#all"/>
    <xsl:template match="@*|node()">
    <xsl:copy><xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
    </xsl:template>
    
    <xsl:template match="//sect">        
        <xsl:for-each select=".">
            <xsl:variable name="increment" select="position()"/>
     <xsl:result-document href="try{$increment}.xml">         
         <xsl:copy><xsl:apply-templates/></xsl:copy>
     </xsl:result-document>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

正确XSLT实现

以下是符合需求的XSLT 2.0代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    version="2.0"
    exclude-result-prefixes="#all">
    
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <!-- 全局变量:获取所有目标sect节点 -->
    <xsl:variable name="all-sects" select="//book/part/chapter/level/sect"/>
    
    <!-- 从根节点book开始处理,遍历每个sect生成输出文件 -->
    <xsl:template match="/book">
        <xsl:for-each select="$all-sects">
            <xsl:variable name="current-sect" select="."/>
            <xsl:variable name="file-index" select="position()"/>
            
            <xsl:result-document href="try{$file-index}.xml">
                <book>
                    <!-- 仅第一个输出文件保留prelims -->
                    <xsl:if test="$file-index = 1">
                        <xsl:copy-of select="../prelims"/>
                    </xsl:if>
                    
                    <!-- 复制part节点,并传递目标sect参数 -->
                    <xsl:apply-templates select="part">
                        <xsl:with-param name="target-sect" select="$current-sect" tunnel="yes"/>
                    </xsl:apply-templates>
                </book>
            </xsl:result-document>
        </xsl:for-each>
    </xsl:template>
    
    <!-- 复制part节点,传递目标sect参数 -->
    <xsl:template match="part">
        <xsl:param name="target-sect" tunnel="yes"/>
        <xsl:copy>
            <xsl:copy-of select="text()"/>
            <xsl:apply-templates select="chapter">
                <xsl:with-param name="target-sect" select="$target-sect" tunnel="yes"/>
            </xsl:apply-templates>
        </xsl:copy>
    </xsl:template>
    
    <!-- 复制chapter节点,传递目标sect参数 -->
    <xsl:template match="chapter">
        <xsl:param name="target-sect" tunnel="yes"/>
        <xsl:copy>
            <xsl:copy-of select="text()"/>
            <!-- 仅保留包含目标sect的level节点 -->
            <xsl:apply-templates select="level[sect is $target-sect]"/>
        </xsl:copy>
    </xsl:template>
    
    <!-- 复制level和sect节点 -->
    <xsl:template match="level|sect">
        <xsl:copy>
            <xsl:copy-of select="@*|text()"/>
            <xsl:apply-templates/>
        </xsl:copy>
    </xsl:template>
    
    <!-- 忽略其他节点的默认复制(避免多余内容) -->
    <xsl:template match="text()" priority="-1"/>
</xsl:stylesheet>

代码核心逻辑说明

  1. 全局变量定位:all-sects变量获取所有需要拆分的sect节点,作为遍历生成文件的基础。
  2. 多文件生成:通过xsl:result-document为每个sect生成独立XML文件,文件名按索引编号。
  3. prelims控制:仅第一个输出文件复制prelims节点,其余文件自动忽略。
  4. 层级过滤:在chapter节点处理时,仅保留包含当前目标sect的level节点,确保每个输出文件只有一个sect。
  5. 结构保留:通过模板匹配复制part、chapter等上层节点及文本内容,完整保留原始XML的层级结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 00:45:56