使用XSLT基于属性值的Flat to Nested结构

Cyl*_*ian 5 xslt-2.0

我有一个扁平的结构化XML文件,如下所示:

<rs>
    <r id="r1" lev="0"/>
    <r id="r2" lev="1"/>
    <r id="r3" lev="0"/>
    <r id="r4" lev="1"/>
    <r id="r5" lev="2"/>
    <r id="r6" lev="3"/>
    <r id="r7" lev="0"/>
    <r id="r8" lev="1"/>
    <r id="r9" lev="2"/>
</rs>
Run Code Online (Sandbox Code Playgroud)

我需要转换为嵌套的.规则是一种东西,都r[number(@lev) gt 0]应该嵌套在其中r[number(@lev) eq 0].输出将是这样的:

<rs>
    <r id="r1">
        <r id="r2"/>
    </r>
    <r id="r3">
        <r id="r4">
            <r id="r5">
                <r id="r6"/>
            </r>
        </r>
    </r>
    <r id="r7">
        <r id="r8">
            <r id="r9"/>
        </r>
    </r>
</rs>
Run Code Online (Sandbox Code Playgroud)

我试过的是以下转变:

<?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 indent="yes"/>

    <xsl:template match="/">
        <rs>
            <xsl:apply-templates select="node()|@*"/>
        </rs>
    </xsl:template>

    <xsl:template match="r">
        <xsl:variable name="lev" select="number(@lev)" as="xs:double"/>
        <r>
            <xsl:copy-of select="@id"/>
            <xsl:apply-templates select="following-sibling::r[not(number(@lev) eq $lev)
                                         and 
                                         count(preceding-sibling::r[number(@lev) eq $lev]) eq 1]"/>
        </r>
    </xsl:template>

</xsl:stylesheet>
Run Code Online (Sandbox Code Playgroud)

但是,这并没有给我预期的结果.指出我的编码错误或任何其他方法来完成工作,非常感谢.

Mic*_*Kay 2

除非另有要求,否则 Dimitre 倾向于使用 XSLT 1.0 来回答问题。这可能是一个正确的猜测,但我认为值得指出的是,XSLT 2.0 现在已经相当广泛地可用和使用,并且 XSLT 2.0 中用于分组问题的代码要简单得多(它可能并不总是短得多,但它是更具可读性)。与 Dimitre 不同,我没有时间也没有意愿为每个问题提供漂亮的完整且经过测试的解决方案,但如果您想查看此问题的 XSLT 2.0 解决方案,我几年前在这里写的一篇论文中有一个解决方案:

http://www.saxonica.com/papers/ideadb-1.1/mhk-paper.xml

搜索递归模板名称=“进程级别”。