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

如何在XSLT 1.0中选取兄弟节点范围以拆分XML列表?

问题描述

给定如下XML输入:

<?xml version="1.0" encoding="utf8"?>
<test>
  <list>
    <li>a</li>
    <li>a</li>
    <li begin="true">b</li>  <!-- begin of the "b" list -->
    <li>b</li>
    <li>b</li>
    <li end="true">b</li>  <!-- end of the "b" list -->
    <li>c</li>
    <li>c</li>
  </list>
</test>

需要使用XSLT 1.0基于begin和end属性将列表拆分为三个独立的<list>,预期输出如下:

<list>
    <li>a</li>
    <li>a</li>
  </list>

  <list>
    <li>b</li>
    <li>b</li>
    <li>b</li>
    <li>b</li>
  </list>

  <list>
    <li>c</li>
    <li>c</li>
  </list>

目前已成功匹配第一个和第三个列表,但无法正确选取中间列表的节点范围,现有代码如下:

<xsl:template match="list">
  <list>
    <xsl:apply-templates select="li[@begin = 'true']/preceding-sibling::li" />
  </list>
  <list>
    <xsl:apply-templates select="li[...]" />  <!-- Hmm 🤔 -->
  </list>
  <list>
    <xsl:apply-templates select="li[@end = 'true']/following-sibling::li" />
  </list>
</xsl:template>

补充说明:begin和end属性是唯一的,原始列表中仅有一组带这两个属性的节点。

解决方案

要选取中间列表的节点,可利用XPath的节点范围选择逻辑,直接匹配begin节点、end节点,以及两者之间的所有<li>。对应的XPath表达式可以写为:

li[@begin='true'] | li[@begin='true']/following-sibling::li[preceding-sibling::li[@end='true']]

完整的可运行XSLT代码如下:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes" encoding="utf-8"/>

  <xsl:template match="list">
    <!-- 第一个列表:begin节点之前的所有li -->
    <list>
      <xsl:apply-templates select="li[@begin='true']/preceding-sibling::li" />
    </list>

    <!-- 中间列表:begin到end之间的所有li(含首尾节点) -->
    <list>
      <xsl:apply-templates select="li[@begin='true'] | li[@begin='true']/following-sibling::li[preceding-sibling::li[@end='true']]" />
    </list>

    <!-- 第三个列表:end节点之后的所有li -->
    <list>
      <xsl:apply-templates select="li[@end='true']/following-sibling::li" />
    </list>
  </xsl:template>

  <!-- 直接复制li节点,保留原内容 -->
  <xsl:template match="li">
    <xsl:copy-of select="." />
  </xsl:template>
</xsl:stylesheet>

逻辑说明

  • 中间列表的选择器中,li[@begin='true']选中标记起始的节点;li[@begin='true']/following-sibling::li[preceding-sibling::li[@end='true']]选中起始节点之后、且在结束节点之前的所有<li>,两者结合就覆盖了整个中间组的所有节点。
  • 由于begin和end属性唯一,无需担心匹配到其他无关节点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 09:48:08