2011-07-26 4 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の『colsの= 2』を持っている= 1』一列のページレイアウトで、と」項目のダブルカラムページレイアウト。アイテムの順序を保持する必要があります。 @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つを入れることを「動的に」決めることはできません。 (私が最初にスタイルシートを動的に作成するメタプログラムを持っていない限り、私は単純な静的スタイルシートを使ってこれを達成することを望んでいました)。

+1

XSLT 2.0のグループ化機能がこの問題を解決するかどうかは不思議です。サンプル入力に必要な出力XML(FO)を表示して、目的のターゲットをよりよく理解できるようにしてください。 – LarsH

答えて

4

group-adjacentxsl:for-each-groupを使用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』を持つことを印刷できるようにする必要があります。アイテムの順序を保持する必要があります。

あなたは適切なfoのページ順序で@colsの値に従って、最終的グループ隣接item要素が欲しいです。

xsl:choosexsl:for-eachのようなXSLT 1.0命令は、このタスクに実際には適していません。私はあなたの心を少し変えなければならないと思います。ここでは、再帰によって結果のグループ化を行う方法の例を示します。

各フロー要素の中にどのような要素を含めるべきかはっきりしないので、要素をグループ化する方法を説明することにしました。次に、コードを要件に適合させることができます。


[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:Excellent!ですから、基本的なアプローチは、メインループ内の重要なアイテム(@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

ご意見ありがとうございます。では、なぜあなたは他の答えを受け入れたのですか? –

関連する問題