可能有一种简单的方法可以使用XSLT2.0完成,但我在这里假设使用XSLT1.0。
需要注意的一点是,您的XML不严格有效,因为缺少根元素。为了回答问题,我假设根元素称为 elements
要实现这一点,我认为您需要一个函数来确定元素的“级别”。这可以通过计算@lp属性中句点的数量来完成。在XSLT1.0中,我通过从文本中删除所有句点,并将结果字符串长度与原始字符串长度进行比较来实现此目的。
<xsl:variable name="level" select="string-length(@lp) - string-length(translate(@lp, '.', ''))" />
因此,要匹配顶级元素,您需要执行以下操作...
<xsl:apply-templates
select="element[string-length(@lp) - string-length(translate(@lp, '.', '')) = 0]"/>
这将匹配以下元素。
<element lp="1."/>
<element lp="2."/>
<element lp="3."/>
接下来,对于每个匹配的元素,需要匹配后续元素,其中:
- @lp属性以当前@lp属性开头
- 级别比当前级别高1
可以使用以下选择器完成此操作:
<xsl:apply-templates
select="following-sibling::element[substring(@lp, 1, $len) = $lp][string-length(@lp) - string-length(translate(@lp, '.', '')) = $level + 1]"/>
(注意$len和$level是包含当前@lp属性长度和当前级别的变量)
将所有内容综合起来,得到以下XSLT...
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/elements">
<elements>
<xsl:apply-templates select="element[string-length(@lp) - string-length(translate(@lp, '.', '')) = 0]"/>
</elements>
</xsl:template>
<xsl:template match="element">
<xsl:variable name="lp" select="@lp"/>
<xsl:variable name="len" select="string-length(@lp)"/>
<xsl:variable name="level" select="$len - string-length(translate(@lp, '.', ''))" />
<xsl:copy>
<xsl:copy-of select="@lp"/>
<xsl:apply-templates select="following-sibling::element[substring(@lp, 1, $len) = $lp][string-length(@lp) - string-length(translate(@lp, '.', '')) = $level + 1]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
当应用于以下XML时:
<elements>
<element lp="1"/>
<element lp="1.1"/>
<element lp="2"/>
<element lp="3"/>
<element lp="3.1"/>
<element lp="3.2"/>
<element lp="3.2.1"/>
</elements>
生成以下输出。
<elements>
<element lp="1">
<element lp="1.1"/>
</element>
<element lp="2"/>
<element lp="3">
<element lp="3.1"/>
<element lp="3.2">
<element lp="3.2.1"/>
</element>
</element>
</elements>