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

如何将指定XML节点包装到单个<p>元素中?XSLT实现问题

XSLT节点合并解决方案

需要实现以下节点合并逻辑:

  • 将<p class="p1">节点、<div class="disp-quote-p">节点,以及紧跟在<div class="disp-quote-p">之后的第一个<p class="p1">节点,全部包装到一个新的<p>元素中
  • 同时将<div class="disp-quote-p">转换为<disp-quote>

输入XML

<root>
    <p class="p">aa</p>
    <p class="p1">Although:</p>
    <div class="disp-quote-p">
        <p class="p">We had seen.</p>
    </div>
    <p class="p1">This dot.</p>
    <img src="a.png"/>
    <box>box</box>
    <p class="p">bb</p>
</root>

当前错误的XSLT代码

<xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    
    <xsl:template match="root">
        <xsl:copy>
            <xsl:for-each-group select="*" group-starting-with="p[@class='p1']">
                <xsl:for-each-group select="current-group()" group-adjacent="self::p[@class='p1'] or self::div[@class='disp-quote-p']">
                    <xsl:choose>
                        <xsl:when test="self::p[@class='p1']">
                            <p><xsl:apply-templates select="node(), current-group() except ."/></p>
                        </xsl:when>
                        <xsl:otherwise>
                            <xsl:copy-of select="current-group()"/>
                        </xsl:otherwise>
                    </xsl:choose>
                </xsl:for-each-group>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

预期输出

<root>
    <p class="p">aa</p>
    <p>Although:<disp-quote><p class="p">We had seen.</p></disp-quote>This dot.</p>
    <img src="a.png"/>
    <box>box</box>
    <p class="p">bb</p>
</root>

正确的XSLT实现

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <!-- 身份模板,默认复制所有节点 -->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <!-- 匹配root节点,处理分组逻辑 -->
    <xsl:template match="root">
        <xsl:copy>
            <xsl:for-each-group select="*" group-starting-with="p[@class='p1']">
                <xsl:choose>
                    <!-- 匹配p1 -> div.disp-quote-p -> p1的连续节点序列 -->
                    <xsl:when test="current-group() = (p[@class='p1'], div[@class='disp-quote-p'], p[@class='p1'])">
                        <p>
                            <!-- 输出第一个p1的内容 -->
                            <xsl:apply-templates select="current-group()[1]/node()"/>
                            <!-- 将div转换为disp-quote并输出内部内容 -->
                            <disp-quote>
                                <xsl:apply-templates select="current-group()[2]/node()"/>
                            </disp-quote>
                            <!-- 输出第三个p1的内容 -->
                            <xsl:apply-templates select="current-group()[3]/node()"/>
                        </p>
                    </xsl:when>
                    <!-- 其他节点序列按默认规则处理 -->
                    <xsl:otherwise>
                        <xsl:apply-templates select="current-group()"/>
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>

    <!-- 空模板匹配目标div,避免被身份模板重复复制 -->
    <xsl:template match="div[@class='disp-quote-p']"/>
</xsl:stylesheet>

实现思路

  1. 以<p class="p1">为分组起始点,将root的子节点分组,精准捕获目标节点序列
  2. 判断分组是否符合p1 -> div.disp-quote-p -> p1的结构,若符合则合并到新<p>元素中,并完成div到disp-quote的转换
  3. 用空模板屏蔽目标div的默认复制逻辑,避免节点重复输出
  4. 非目标节点保持原有结构输出

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:05:56