2011-03-18 32 views
1

前一段時間我問了一個非常類似的問題([1]:XSL to create nested list from flat tree problem「從平坦樹問題創建嵌套列表」),但是我的問題稍微擴大了。最初我沒有考慮嵌套在列表中的段落。所以,現在,隨着輸入:增強XSL從平坦樹問題創建嵌套列表

<root> 
    <h1>text</h1> 
    <list level="1">num1</list> 
    <list level="1">num2</list> 
    <para type="indent">indented para1</para> 
    <list level="2">sub-num1</list> 
    <para type="indent">sub-indented para1</para> 
    <para type="indent">sub-indented para2</para> 
    <list level="2">sub-num2</list> 
    <list level="3">sub-sub-num1</list> 
    <list level="1">num3</list> 
    <p>text</p> 
    <list>num1</list> 
    <list>num2</list> 
    <h2>text</h2> 
</root> 

我需要這樣的輸出:

<root> 
    <h1>text</h1> 
    <ol> 
     <li>num1</li> 
     <li>num2 
      <paragraph>indented para1</paragraph> 
      <ol> 
       <li>sub-num1 
        <paragraph>sub-indented para1</paragraph> 
        <paragraph>sub-indented para2</paragraph> 
       </li> 
       <li>sub-num2      
        <ol> 
         <li>sub-sub-num1</li> 
        </ol> 
       </li> 
      </ol> 
     </li> 
     <li>num3</li> 
    </ol> 
    <p>text</p> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
    </ol> 
    <h2>text</h2> 
</root> 

也可能有縮進的段落不在列表內的情況,但我想我能明白這一點一旦我把這隻猴子從我背上取下來。 我需要使用XSLT 1.0,並再次感謝任何幫助。

回答

3

沒有太多的修改我的previus answer,這個樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kListByParent" 
      match="list" 
      use="concat(generate-id(
          preceding-sibling::*[ 
           not(self::list|self::para) 
          ][1] 
         ), '+', 
         generate-id(
          preceding-sibling::list[ 
           current()/@level > @level 
          ][1] 
         ) 
       )"/> 
    <xsl:key name="kParaByList" match="para" 
      use="generate-id(preceding-sibling::list[1])"/> 
    <xsl:template match="node()|@*" name="identity"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="node()|@*" mode="copy"> 
     <xsl:call-template name="identity"/> 
    </xsl:template> 
    <xsl:template match="list[preceding-sibling::*[1][ 
           self::list|self::para 
           ] 
         ] | 
         para"/> 
    <xsl:template match="list"> 
     <xsl:variable name="vListMark" 
         select="generate-id(preceding-sibling::*[1])"/> 
     <ol> 
      <xsl:apply-templates select="key('kListByParent', 
              concat($vListMark,'+'))" 
           mode="makeLi"> 
       <xsl:with-param name="pListMark" select="$vListMark"/> 
      </xsl:apply-templates> 
     </ol> 
    </xsl:template> 
    <xsl:template match="list" mode="makeLi"> 
     <xsl:param name="pListMark"/> 
     <xsl:variable name="vSubList" 
         select="key('kListByParent', 
            concat($pListMark,'+',generate-id()))"/> 
     <li> 
      <xsl:apply-templates 
       select="node()|key('kParaByList',generate-id())" 
       mode="copy"/> 
      <xsl:if test="$vSubList"> 
       <ol> 
        <xsl:apply-templates select="$vSubList" mode="makeLi"> 
         <xsl:with-param name="pListMark" 
             select="$pListMark"/> 
        </xsl:apply-templates> 
       </ol> 
      </xsl:if> 
     </li> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<root> 
    <h1>text</h1> 
    <ol> 
     <li>num1</li> 
     <li>num2 
      <para type="indent">indented para1</para> 
      <ol> 
       <li>sub-num1 
        <para type="indent">sub-indented para1</para> 
        <para type="indent">sub-indented para2</para> 
       </li> 
       <li>sub-num2 
        <ol> 
         <li>sub-sub-num1</li> 
        </ol> 
       </li> 
      </ol> 
     </li> 
     <li>num3</li> 
    </ol> 
    <p>text</p> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
    </ol> 
    <h2>text</h2> 
</root> 

注意:從概念上講這應該遞歸分組開始list最小@level 。我會重構這個以使它在語義上更加準確。

編輯:語義更接近XSLT 2.0解決方案。

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="root"> 
     <xsl:copy> 
      <xsl:for-each-group select="node()" 
       group-adjacent="boolean(self::list|self::para)"> 
       <xsl:choose> 
        <xsl:when test="current-grouping-key()"> 
         <xsl:call-template name="makeList"> 
          <xsl:with-param name="pList" 
              select="current-group()"/> 
         </xsl:call-template> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:apply-templates select="current-group()"/> 
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:for-each-group> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template name="makeList"> 
     <xsl:param name="pList"/> 
     <xsl:variable name="vFirstList" select="($pList/self::list)[1]"/> 
     <xsl:apply-templates 
      select="$pList[not(. >> $vFirstList)] except $vFirstList"/> 
     <xsl:if test="$vFirstList"> 
      <ol> 
       <xsl:for-each-group select="$pList[not($vFirstList >> .)]" 
       group-starting-with="list[not($vFirstList/@level ne @level)]"> 
        <li> 
         <xsl:value-of select="current-group()[1]"/> 
         <xsl:if test="current-group()[2]"> 
          <xsl:call-template name="makeList"> 
           <xsl:with-param name="pList" 
           select="current-group()[position()!=1]"/> 
          </xsl:call-template> 
         </xsl:if> 
        </li> 
       </xsl:for-each-group> 
      </ol> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 
+0

+1。好,清楚。 – Flack 2011-03-18 20:24:59

+0

+1。完美的作品。非常感謝 – Jacqueline 2011-03-18 20:30:46

+0

@Jacqueline:不客氣。請注意,XSLT 1.0解決方案並不像XSLT 2.0解決方案那麼通用。我將再次訪問此主題。 – 2011-03-18 20:34:03