2012-04-13 63 views
1

我們的服務之一提供了一個列出待辦事項收集的XML文檔。 Todo的結構可以在todolist下嵌套。每一個todo item將有父母todo list。我需要使用XSL來顯示當前父母的待辦事項數量todo-list。請查找XML的下方如何遞歸計算XSLT 1.0中的待辦事項數量

<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。由於在第一個todo項目集合中,然後在子項目集合項目集合(ParentId = 1)中。嵌套在這裏只是一個級別,但我們已將其設計爲N級。

注: 您可以在線嘗試在這裏http://chris.photobooks.com/xml/default.htm

回答

2

這種轉變您的疑問:如果在下面的XML文檔應用(基於提供

<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> 

,但與更深層次):

<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> 

說明

這是一個兩通轉化:

  1. 在第一傳遞文檔被轉換從平面到基於parent - > id關係的分層結構。

  2. 在第二遍中,pass1的結果被轉換回平面文檔。 Count元素被調整爲包含其最內層包含子樹中所有Count元素的總和。

  3. 如果我們希望最終結果包含排序爲IdTodoList元素,則可能需要第三遍。

+0

+1精彩的回答。 – 2012-04-13 16:21:35

+0

@NickRyan:不客氣。 – 2012-04-13 16:55:53

+0

+1不管它說什麼,但遞歸在XSLT中可能更友好。語法和想法是太棒了 – Deeptechtons 2012-04-14 05:59:06