我们的一项服务提供了一个xml文档,列出了待办事项的集合。待办事项的结构是可嵌套在待办事项列表下。每个todo item
都将有父todo list
。我需要使用 XSL 显示当前父todo-list
的待办事项数。请在下面找到 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>4</Count>
<TodoItemCollection>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
<TodoItem></TodoItem>
</TodoItemCollection>
</TodoList>
</TodoListCollection>
在 TodoList ID = 1
的第一次迭代中,我应该能够总共算作 3 + 4 = 7
。因为第一个待办事项集合中有 3 个,然后子待办事项集合中有 4 个 (ParentId = 1
)。这里的嵌套只是一个级别,但我们将其设计为N级。
注意:您可以在此处在线尝试查询 http://chris.photobooks.com/xml/default.htm
此转换:
<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
元素的总和。如果我们希望最终结果包含按
Id
排序的TodoList
元素,则可能需要第三次传递。