如何在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
相关产品推荐
相关产品推荐

