这种转变:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common" exclude-result-prefixes="ext">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kChildren" match="TodoList" use="ParentId"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:variable name="vrtfPass1">
<xsl:copy>
<xsl:apply-templates select="key('kChildren', '')"/>
</xsl:copy>
</xsl:variable>
<xsl:variable name="vPass1" select="ext:node-set($vrtfPass1)"/>
<xsl:apply-templates select="$vPass1/*" mode="pass2"/>
</xsl:template>
<xsl:template match="TodoList">
<xsl:copy>
<xsl:apply-templates />
<xsl:apply-templates select="key('kChildren', Id)"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node()|@*" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="node()|@*" mode="pass2"/>
</xsl:copy>
</xsl:template>
<xsl:template match="TodoList" mode="pass2">
<xsl:copy>
<xsl:apply-templates select="*[not(self::TodoList)]" mode="pass2"/>
</xsl:copy>
<xsl:apply-templates select="TodoList" mode="pass2"/>
</xsl:template>
<xsl:template match="Count" mode="pass2">
<Count>
<xsl:value-of select="sum(..//Count)"/>
</Count>
</xsl:template>
</xsl:stylesheet>
当应用于以下 XML 文档时(基于提供的,但具有更深层次的层次结构):
<TodoListCollection>
<TodoList>
<Id>1</Id>
<ParentId></ParentId>
<Count>3</Count>
<TodoItemCollection>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>2</Id>
<ParentId>1</ParentId>
<Count>7</Count>
<TodoItemCollection>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>3</Id>
<ParentId>2</ParentId>
<Count>5</Count>
<TodoItemCollection>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>4</Id>
<ParentId>3</ParentId>
<Count>3</Count>
<TodoItemCollection>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>5</Id>
<ParentId>2</ParentId>
<Count>1</Count>
<TodoItemCollection>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
</TodoItemCollection>
</TodoList>
</TodoListCollection>
产生想要的正确结果:
<TodoListCollection>
<TodoList>
<Id>1</Id>
<ParentId/>
<Count>19</Count>
<TodoItemCollection>
<TodoItem/>
<TodoItem/>
<TodoItem/>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>2</Id>
<ParentId>1</ParentId>
<Count>16</Count>
<TodoItemCollection>
<TodoItem/>
<TodoItem/>
<TodoItem/>
<TodoItem/>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>3</Id>
<ParentId>2</ParentId>
<Count>8</Count>
<TodoItemCollection>
<TodoItem/>
<TodoItem/>
<TodoItem/>
<TodoItem/>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>4</Id>
<ParentId>3</ParentId>
<Count>3</Count>
<TodoItemCollection>
<TodoItem/>
<TodoItem/>
<TodoItem/>
<TodoItem/>
</TodoItemCollection>
</TodoList>
<TodoList>
<Id>5</Id>
<ParentId>2</ParentId>
<Count>1</Count>
<TodoItemCollection>
<TodoItem/>
<TodoItem/>
<TodoItem/>
<TodoItem/>
</TodoItemCollection>
</TodoList>
</TodoListCollection>
说明:
这是一个两遍转换:
在第一遍中,文档根据父 --> id 关系从平面转换为层次结构。
在第二遍中,pass1 的结果被转换回平面文档。Count
元素被调整为包含Count
它们最里面的子树中所有元素的总和。
TodoList
如果我们希望最终结果包含按其排序的元素,则可能需要第三遍Id
。