2011-07-26 56 views
5

我遇到的問題的淡化版本是這樣的。對於這樣一個XML文件:如何根據節點屬性動態更改xslt頁面序列?

<?xml version="1.0" encoding="UTF-8"?> 
<items> 
    <item cols="1">Item 1</item> 
    <item cols="1">Item 2</item> 
    <item cols="1">Item 3</item> 
    <item cols="1">Item 4</item> 
    <item cols="1">Item 5</item> 
    <item cols="1">Item 6</item> 
    <item cols="1">Item 7</item> 
    <item cols="1">Item 8</item> 
    <item cols="1">Item 9</item> 
    <item cols="2">Item 10</item> 
    <item cols="1">Item 11</item> 
    <item cols="1">Item 12</item> 
    <item cols="1">Item 13</item> 
    <item cols="1">Item 14</item> 
    <item cols="1">Item 15</item> 
    <item cols="1">Item 16</item> 
    <item cols="1">Item 17</item> 
    <item cols="1">Item 18</item> 
</items> 

我需要能夠打印的「有項目的‘的cols = 1’在一列頁面佈局和」那個‘的cols = 2’在有項目的雙列頁面佈局。項目的排序必須保留。所有連續的'具有相同值的@cols項目都需要以連續流的形式出現。每當@cols值發生變化時,我都需要打開新頁面並根據需要更改佈局。

我在做這樣的事情:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format"> 

    <xsl:strip-space elements="*"/> 

    <xsl:template match="/"> 
     <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
      <fo:layout-master-set> 

       <fo:simple-page-master master-name="one-column-page-master"> 
        <fo:region-body margin-top="3cm" region-name="body" column-count="1"/> 
       </fo:simple-page-master> 

       <fo:simple-page-master master-name="two-column-page-master"> 
        <fo:region-body margin-top="3cm" region-name="body" column-count="2"/> 
        <fo:region-before region-name="header" extent="2cm"/> 
       </fo:simple-page-master> 

       <fo:page-sequence-master master-name="one-column-page"> 
        <fo:repeatable-page-master-reference master-reference="one-column-page-master"/> 
       </fo:page-sequence-master> 

       <fo:page-sequence-master master-name="two-column-page"> 
        <fo:repeatable-page-master-reference master-reference="two-column-page-master"/> 
       </fo:page-sequence-master> 

      </fo:layout-master-set> 

      <xsl:for-each select="//item"> 
       <xsl:choose> 
        <xsl:when test="@cols = preceding-sibling::item[1]/@cols"> 
         <!--cols value hasn't changed, don't create a new page-sequence--> 
         <!--But we cannot directly add fo:flow as the child of fo:root! --> 
         <xsl:call-template name="itemtemplate"/> 
        </xsl:when> 
        <xsl:otherwise> 
         <xsl:choose> 
          <xsl:when test="@cols = 1"> 
           <fo:page-sequence master-reference="one-column-page"> 
            <xsl:call-template name="itemtemplate"/> 
           </fo:page-sequence> 
          </xsl:when> 
          <xsl:otherwise> 
           <fo:page-sequence master-reference="two-column-page"> 
            <xsl:call-template name="itemtemplate"/> 
           </fo:page-sequence> 
          </xsl:otherwise> 
         </xsl:choose> 
        </xsl:otherwise> 
       </xsl:choose> 
      </xsl:for-each> 
     </fo:root> 

    </xsl:template> 

    <xsl:template name="itemtemplate"> 
      <fo:flow flow-name="body"> 
       <fo:block margin-bottom="5cm"> 
        <xsl:apply-templates/> 
       </fo:block> 
      </fo:flow> 

    </xsl:template> 

</xsl:stylesheet> 

但當然,問題是,我要麼必須包括< FO:在我的樣式表頁序... >,還是不行,我不能'動態'決定放入一個基於音符屬性。 (除非我有一個首先動態創建樣式表的元程序,但我希望只使用普通的靜態樣式表來完成此操作)。

+1

好問題。我想知道XSLT 2.0的分組功能是否能爲您解決這個問題。請爲您的示例輸入顯示所需的輸出XML(FO),以便我們可以更好地瞭解您要達到的目標。 – LarsH

回答

4

下面是一個使用xsl:for-each-groupgroup-adjacent的XSLT 2.0溶液:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
       xmlns:fo="http://www.w3.org/1999/XSL/Format"> 

    <xsl:strip-space elements="*"/> 
    <xsl:output indent="yes"/> 

    <xsl:template match="/"> 
     <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
     <fo:layout-master-set> 

      <fo:simple-page-master master-name="one-column-page-master"> 
      <fo:region-body margin-top="3cm" region-name="body" 
          column-count="1"/> 
      </fo:simple-page-master> 

      <fo:simple-page-master master-name="two-column-page-master"> 
      <fo:region-body margin-top="3cm" region-name="body" 
          column-count="2"/> 
      <fo:region-before region-name="header" extent="2cm"/> 
      </fo:simple-page-master> 

      <fo:page-sequence-master master-name="one-column-page"> 
      <fo:repeatable-page-master-reference 
       master-reference="one-column-page-master"/> 
      </fo:page-sequence-master> 

      <fo:page-sequence-master master-name="two-column-page"> 
      <fo:repeatable-page-master-reference 
       master-reference="two-column-page-master"/> 
      </fo:page-sequence-master> 

     </fo:layout-master-set> 
     <xsl:apply-templates/> 
     </fo:root> 
    </xsl:template> 

    <xsl:template match="items"> 
     <xsl:for-each-group select="item" 
          group-adjacent="@cols"> 

     <xsl:choose> 
      <xsl:when test="@cols = 1"> 
      <fo:page-sequence master-reference="one-column-page"> 
       <fo:flow flow-name="body"> 
       <xsl:for-each select="current-group()"> 
        <xsl:apply-templates select="."/> 
       </xsl:for-each> 
       </fo:flow> 
      </fo:page-sequence> 
      </xsl:when> 

      <xsl:otherwise> 
      <fo:page-sequence master-reference="two-column-page"> 
       <fo:flow flow-name="body"> 
       <xsl:for-each select="current-group()"> 
        <xsl:apply-templates select="."/> 
       </xsl:for-each> 
       </fo:flow> 
      </fo:page-sequence> 
      </xsl:otherwise> 

     </xsl:choose> 
     </xsl:for-each-group> 
    </xsl:template> 

    <xsl:template match="item"> 
     <fo:block margin-bottom="5cm"> 
     <xsl:apply-templates/> 
     </fo:block> 
    </xsl:template> 

</xsl:stylesheet> 

輸出:

<?xml version="1.0" encoding="UTF-8"?> 
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
    <fo:layout-master-set> 
     <fo:simple-page-master master-name="one-column-page-master"> 
     <fo:region-body margin-top="3cm" region-name="body" column-count="1"/> 
     </fo:simple-page-master> 
     <fo:simple-page-master master-name="two-column-page-master"> 
     <fo:region-body margin-top="3cm" region-name="body" column-count="2"/> 
     <fo:region-before region-name="header" extent="2cm"/> 
     </fo:simple-page-master> 
     <fo:page-sequence-master master-name="one-column-page"> 
     <fo:repeatable-page-master-reference master-reference="one-column-page-master"/> 
     </fo:page-sequence-master> 
     <fo:page-sequence-master master-name="two-column-page"> 
     <fo:repeatable-page-master-reference master-reference="two-column-page-master"/> 
     </fo:page-sequence-master> 
    </fo:layout-master-set> 
    <fo:page-sequence master-reference="one-column-page"> 
     <fo:flow flow-name="body"> 
     <fo:block margin-bottom="5cm">Item 1</fo:block> 
     <fo:block margin-bottom="5cm">Item 2</fo:block> 
     <fo:block margin-bottom="5cm">Item 3</fo:block> 
     <fo:block margin-bottom="5cm">Item 4</fo:block> 
     <fo:block margin-bottom="5cm">Item 5</fo:block> 
     <fo:block margin-bottom="5cm">Item 6</fo:block> 
     <fo:block margin-bottom="5cm">Item 7</fo:block> 
     <fo:block margin-bottom="5cm">Item 8</fo:block> 
     <fo:block margin-bottom="5cm">Item 9</fo:block> 
     </fo:flow> 
    </fo:page-sequence> 
    <fo:page-sequence master-reference="two-column-page"> 
     <fo:flow flow-name="body"> 
     <fo:block margin-bottom="5cm">Item 10</fo:block> 
     </fo:flow> 
    </fo:page-sequence> 
    <fo:page-sequence master-reference="one-column-page"> 
     <fo:flow flow-name="body"> 
     <fo:block margin-bottom="5cm">Item 11</fo:block> 
     <fo:block margin-bottom="5cm">Item 12</fo:block> 
     <fo:block margin-bottom="5cm">Item 13</fo:block> 
     <fo:block margin-bottom="5cm">Item 14</fo:block> 
     <fo:block margin-bottom="5cm">Item 15</fo:block> 
     <fo:block margin-bottom="5cm">Item 16</fo:block> 
     <fo:block margin-bottom="5cm">Item 17</fo:block> 
     <fo:block margin-bottom="5cm">Item 18</fo:block> 
     </fo:flow> 
    </fo:page-sequence> 
</fo:root> 
1

我需要能夠打印「項目的有‘的cols = 1’在一列頁面佈局,以及」具有在雙塔頁面佈局‘的cols = 2’項目的。項目的排序必須保留。

您希望根據的@cols在適當的FO頁面序列中的值最後組相鄰item元件。

XSLT 1.0指令(如xsl:choosexsl:for-each)不適合執行此任務。我認爲你必須改變主意。這裏是一個如何實現遞歸結果分組的例子。

你不是很清楚你想在每個流程元素中包含什麼,然後我決定告訴你如何分組元素;那麼,您可以根據您的要求調整代碼。


[XSLT 1.0]

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="text()"/> 

    <xsl:template match="/*"> 
     <fo:root> 
      <!-- layout master stuff --> 
      <xsl:apply-templates select="item"/> 
     </fo:root> 
    </xsl:template> 

    <!-- match @cols 1, first group occurrences --> 
    <xsl:template match="/*/item[@cols=1] 
    [not(preceding-sibling::item[1][@cols=1])]"> 
     <fo:page-sequence master-reference="one-column-page"> 
      <xsl:copy-of select="."/> 
      <xsl:apply-templates select=" 
       following-sibling::*[1][self::item[@cols=1]]" mode="flow"> 
       <xsl:with-param name="cols" select="1"/> 
      </xsl:apply-templates> 
     </fo:page-sequence> 
    </xsl:template> 

    <!-- match @cols 2, first group occurrences --> 
    <xsl:template match="/*/item[@cols=2] 
    [not(preceding-sibling::item[1][@cols=2])]"> 
     <fo:page-sequence master-reference="two-column-page"> 
      <xsl:copy-of select="."/> 
      <xsl:apply-templates select=" 
       following-sibling::*[1][self::item[@cols=2]]" mode="flow"> 
       <xsl:with-param name="cols" select="2"/> 
      </xsl:apply-templates> 
     </fo:page-sequence> 
    </xsl:template> 

    <!-- recursive match adjacent @cols --> 
    <xsl:template match="item" mode="flow"> 
     <xsl:param name="cols"/> 
     <xsl:copy-of select="."/> 
     <xsl:apply-templates select=" 
      following-sibling::*[1][self::item[@cols=$cols]]" mode="flow"> 
      <xsl:with-param name="cols" select="$cols"/> 
     </xsl:apply-templates> 
    </xsl:template> 

</xsl:stylesheet> 

當施加到在問題中提供的樣品輸入生產:

<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
    <fo:page-sequence master-reference="one-column-page"> 
     <item cols="1">Item 1</item> 
     <item cols="1">Item 2</item> 
     <item cols="1">Item 3</item> 
     <item cols="1">Item 4</item> 
     <item cols="1">Item 5</item> 
     <item cols="1">Item 6</item> 
     <item cols="1">Item 7</item> 
     <item cols="1">Item 8</item> 
     <item cols="1">Item 9</item> 
    </fo:page-sequence> 
    <fo:page-sequence master-reference="two-column-page"> 
     <item cols="2">Item 10</item> 
    </fo:page-sequence> 
    <fo:page-sequence master-reference="one-column-page"> 
     <item cols="1">Item 11</item> 
     <item cols="1">Item 12</item> 
     <item cols="1">Item 13</item> 
     <item cols="1">Item 14</item> 
     <item cols="1">Item 15</item> 
     <item cols="1">Item 16</item> 
     <item cols="1">Item 17</item> 
     <item cols="1">Item 18</item> 
    </fo:page-sequence> 
</fo:root> 
1

@empo:太棒了!所以基本的方法是在主循環中處理關鍵的項目(其中@cols更改),並在遞歸模板調用中處理相鄰節點。我已經使用了你的方法並做了一些改變,以使代碼更簡單,但是這很好!

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="text()"/> 

    <xsl:template match="/*"> 
     <fo:root> 

      <xsl:for-each select="item"> 
       <xsl:choose> 
        <xsl:when test="preceding-sibling::item[1]/@cols != @cols or position()=1"> 
         <xsl:choose> 
          <xsl:when test="@cols = 1"> 
           <fo:page-sequence master-reference="one-column-page"> 
            <xsl:apply-templates select="." mode="recurse"> 
             <xsl:with-param name="cols" select="@cols"/> 
            </xsl:apply-templates> 
           </fo:page-sequence> 

          </xsl:when> 
          <xsl:when test="@cols = 2"> 
           <fo:page-sequence master-reference="two-column-page"> 
            <xsl:apply-templates select="." mode="recurse"> 
             <xsl:with-param name="cols" select="@cols"/> 
            </xsl:apply-templates> 
           </fo:page-sequence> 
          </xsl:when> 
         </xsl:choose> 
        </xsl:when> 
       </xsl:choose> 
      </xsl:for-each> 
     </fo:root> 
    </xsl:template> 


    <!-- recursive match adjacent @cols --> 
    <xsl:template match="item" mode="recurse"> 
     <xsl:param name="cols"/> 
     <xsl:copy-of select="."/> 
     <xsl:apply-templates select=" 
      following-sibling::*[1][self::item[@cols=$cols]]" 
      mode="recurse"> 
      <xsl:with-param name="cols" select="$cols"/> 
     </xsl:apply-templates> 
    </xsl:template> 

</xsl:stylesheet> 
+0

感謝您的反饋。那麼爲什麼你接受了另一個答案? –

相關問題