Need to dynamically change the simple-page-master's master-name

主宰稳场 提交于 2020-01-05 07:05:34

问题


I have an xml document as shown below. Each repeating doc is a page in PDF file

<AFPXMLFile>
    <docs>
      <regList>
           <region>1</region>
           <secList>
               <col>1</col>
               <lines></lines>
          </secList>
     </regList>
     <regList>
         <region>2</region>
         <secList>
               <col>2</col>
               <lines>
                  <line>IBM BELGIUM xxx</line>
                  <line>xxxxxx</line>
                  <line>xxxx</line>
              </lines>
         </secList>
     </regList>
     <regList></regList>
     <regList></regList>
  </docs>
  <docs></docs>
 </AFPXMLFile>

My XSL is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.1" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
exclude-result-prefixes="fo">

<xsl:template match="AFPXMLFile">
<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:layout-master-set>
<fo:simple-page-master page-width="21cm" page-height="29.7cm"  margin-top="1.27cm" margin-bottom="1.27cm" margin-left="1.75cm" master-name="A4">
  <fo:region-body   margin-top="1mm" margin-bottom="1mm"/>
  <fo:region-before extent="0mm"/>
  <fo:region-after  extent="0mm"/>
  <fo:region-start  writing-mode="tb-rl" precedence="true" extent="10mm" />  
</fo:simple-page-master>
</fo:layout-master-set>
<fo:page-sequence master-reference="A4" font-family="sans-serif">
<xsl:for-each select="docs">
    <xsl:for-each select="./regList">
        <xsl:choose>
            <xsl:when test="region = 1">
               <fo:static-content flow-name="xsl-region-before">
                    <xsl:for-each select="./secList/lines">
                        <xsl:for-each select="node()">
                            <fo:block font-size="8pt" color="purple">
                                <xsl:value-of select="."/>
                           </fo:block>                                 
                        </xsl:for-each>
                     </xsl:for-each>
                </fo:static-content>
            </xsl:when>
            <xsl:when test="region = 2">
               <fo:static-content flow-name="xsl-region-start">
                    <xsl:for-each select="./secList/lines">
                        <xsl:for-each select="node()">
                                <fo:block font-size="4pt" padding-before="4pt" text-align="left" color="green">
                                    <xsl:value-of select="."/>
                                </fo:block> 
                        </xsl:for-each>
                     </xsl:for-each>
                 </fo:static-content>    
            </xsl:when>
            <xsl:when test="region = 3">
                <fo:static-content flow-name="xsl-region-body">
                    <xsl:for-each select="./secList/lines">
                        <xsl:for-each select="node()">
                            <fo:block font-size="8pt" color="blue">
                                <xsl:value-of select="."/>
                            </fo:block>
                         </xsl:for-each>
                    </xsl:for-each>
                </fo:static-content>
            </xsl:when>
            <xsl:when test="region = 4">
               <fo:flow flow-name="xsl-region-after">
                    <xsl:for-each select="./secList">
                        <xsl:for-each select="./lines">
                            <xsl:for-each select="node()">
                                <fo:block font-size="8pt" color="orange">
                                    <xsl:value-of select="."/>
                               </fo:block>
                            </xsl:for-each>
                        </xsl:for-each>
                     </xsl:for-each>
               </fo:flow>      
            </xsl:when>  
        </xsl:choose>                        
    </xsl:for-each>
</xsl:for-each>
</fo:page-sequence>
</fo:root>
</xsl:template>
</xsl:stylesheet>

When I run the transformation I get the following error:

org.apache.fop.fo.ValidationException: For "fo:page-sequence", "fo:static-content" must be declared before "fo:flow"! (No context info available)

This I suspect because it is repeating the static content region for each page. So I believe I need to change the simple-page-master:master-name for every page I need help with that.


回答1:


According to the XSL-FO recommendation, the contents of 'fo:page-sequence' is:

(title?,folio-prefix?,folio-suffix?,static-content*,flow+)

which means that all the fo:static-content elements must be before the fo:flow elements.

Your stylesheet dynamically creates either fo:static-content (if region is 1, 2 or 3) or fo:flow (if region is 4). From the reduced input file in your question it is not possible to see whether the regList elements are alway correctly sorted, so that they produce a valid output when sequentially processed.

Moreover, as each docs element represents a different document with different headers/footers, you have to create distinct fo:page-sequences instead of a single one (otherwise you get too many static contents and flows for a single page sequence):

<xsl:for-each select="docs">
    <fo:page-sequence master-reference="A4" font-family="sans-serif">
        <xsl:for-each select="./regList">
            ....
        </xsl:for-each>
    </fo:page-sequence>
</xsl:for-each>

Moreover, there is a strange thing in the stylesheet: you map an fo:static-content to the xsl-region-body region, and the fo:flow to the xsl-region-after region, which is quite unusual. If the "real" content for the body region is the one with region = 3, you must process region 1, 2 and 4 first, and then region 3:

<xsl:for-each select="docs">
    <fo:page-sequence master-reference="A4" font-family="sans-serif">
        <!-- create static contents -->
        <xsl:apply-templates select="./regList[region != '3']"/>
        <!-- create flow -->
        <xsl:apply-templates select="./regList[region = '3']"/>
    </fo:page-sequence>
</xsl:for-each>

with an additional template to match reglist:

<xsl:template match="regList">
    <xsl:choose>
        <xsl:when test="region = '1'">
           <fo:static-content flow-name="xsl-region-before">
                <xsl:for-each select="./secList/lines">
                    <xsl:for-each select="node()">
                        <fo:block font-size="8pt" color="purple">
                            <xsl:value-of select="."/>
                       </fo:block>                                 
                    </xsl:for-each>
                 </xsl:for-each>
            </fo:static-content>
        </xsl:when>
        <xsl:when test="region = '2'">
           <fo:static-content flow-name="xsl-region-start">
                <xsl:for-each select="./secList/lines">
                    <xsl:for-each select="node()">
                            <fo:block font-size="4pt" padding-before="4pt" text-align="left" color="green">
                                <xsl:value-of select="."/>
                            </fo:block> 
                    </xsl:for-each>
                 </xsl:for-each>
             </fo:static-content>    
        </xsl:when>
        <xsl:when test="region = '3'">
            <fo:flow flow-name="xsl-region-body">
                <xsl:for-each select="./secList/lines">
                    <xsl:for-each select="node()">
                        <fo:block font-size="8pt" color="blue">
                            <xsl:value-of select="."/>
                        </fo:block>
                     </xsl:for-each>
                </xsl:for-each>
            </fo:flow>
        </xsl:when>
        <xsl:when test="region = '4'">
           <fo:static-content flow-name="xsl-region-after">
                <xsl:for-each select="./secList">
                    <xsl:for-each select="./lines">
                        <xsl:for-each select="node()">
                            <fo:block font-size="8pt" color="orange">
                                <xsl:value-of select="."/>
                           </fo:block>
                        </xsl:for-each>
                    </xsl:for-each>
                 </xsl:for-each>
           </fo:static-content>      
        </xsl:when>
    </xsl:choose>
</xsl:template>

or several, smaller templates:

<xsl:template match="reglist[region = '1']">
   <fo:static-content flow-name="xsl-region-before">
        <xsl:for-each select="./secList/lines">
            <xsl:for-each select="node()">
                <fo:block font-size="8pt" color="purple">
                    <xsl:value-of select="."/>
                </fo:block>                                 
            </xsl:for-each>
        </xsl:for-each>
    </fo:static-content>
</xsl:template>

<xsl:template match="reglist[region = '2']">
    ...
</xsl:template>

...


来源:https://stackoverflow.com/questions/45641048/need-to-dynamically-change-the-simple-page-masters-master-name

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!