【问题标题】:How do i recursively count the number of todos in XSLT 1.0我如何递归计算 XSLT 1.0 中的待办事项数量
【发布时间】:2012-04-13 11:43:01
【问题描述】:

我们的一项服务提供了一个列出待办事项集合的 xml 文档。 Todo 的结构可以嵌套在 todolist 下。每个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

【问题讨论】:

    标签: xml xslt recursion aggregate xslt-1.0


    【解决方案1】:

    这种转变

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

    说明

    这是一个两遍转换:

    1. 在第一遍中,文档根据父级 --> id 关系从平面转换为层次结构。

    2. 在第二遍中,将 pass1 的结果转换回平面文档。 Count 元素被调整为包含所有 Count 元素的总和在其最里面的包含子树中。

    3. 如果我们希望最终结果包含按Id 排序的TodoList 元素,则可能需要第三遍。

    【讨论】:

    • +1 照它说的做,但递归在 XSLT 中可能更友好。语法和想法很棒
    猜你喜欢
    • 1970-01-01
    • 2018-12-07
    • 1970-01-01
    • 2019-03-30
    • 1970-01-01
    • 1970-01-01
    • 2012-12-01
    • 2022-12-03
    • 1970-01-01
    相关资源
    最近更新 更多