Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
812 views
in Technique[技术] by (71.8m points)

xslt - XSL-FO Different header/footer depending on page-position

This might be a quite common problem with XSL-FO: I try to build a billing which has clear specifications:

  1. "Main Header": on every page (Text, Logo and Barcode)
  2. "Sub Header": (Customer Data)

    -> On the first page this block should be about 10% of the pages height

    -> On all the others page this block should be about the half smaller, so lets say 5%

  3. "Last-Page Footer": just on the last page of course (Total amount and signatures)

  4. "Every-page Footer": just for the printing date

  5. "Body": the content of the billing (every position) should flow in between of the all headers and footers automatically

So i know that some points can be realised by using the attribute page-position:

<fo:page-sequence-master master-name="masterSequenceName1">
<fo:repeatable-page-master-alternatives>
  <fo:conditional-page-master-reference master-reference="masterNamePageFirst1" page-position="first"></fo:conditional-page-master-reference>
  <fo:conditional-page-master-reference master-reference="masterNamePageLast1"  page-position="last"></fo:conditional-page-master-reference>
  <fo:conditional-page-master-reference master-reference="masterNamePageAny"    page-position="any"></fo:conditional-page-master-reference>
</fo:repeatable-page-master-alternatives>
</fo:page-sequence-master>

I can define the regions for each of this cases but having these issues:

  1. If the first page is the last ( only one page), the last page footer won't appear. Knowing that page-position can have the value "only", a possiblity would be to set a static-content for this, too. But still I would have two blocks of the same content and whenever I wanted to edit this part, I would have to change it twice.
  2. The main header normally can be set by a region-before with a reference to page-position="any" (which is the standard), but somehow this won't work for me. I'm just getting the header at pages which aren't first or last. Shouldn't this actually be the desired function of page-position="rest" ?
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

A note in the definition of the page-position property states that (emphasis added):

Several of these values can be true simultaneously; for example, 'any' is always true and 'only' is true when both 'first' and 'last' are true. For that reason, it is necessary to order the fo:conditional-page-master-references so that the least inclusive test is performed before the more inclusive test which are also true.

In other words, the conditional-page-master-reference that is elected to build a page is the first one whose conditions evaluate to true, and following references are not even taken into consideration.

Another important point to remember is that conditions (page-position, odd-or-even, blank-or-not-blank) select a page master, not a specific static content.

So, looking at your issues:

1. If the first page is the last ( only one page), the last page footer won't appear.

this happens because the first conditional-page-master-reference applicable to the first and only page is, in your example, the one pointing to "masterNamePageFirst1" which (I guess, as it is not in the question) has a region-after into which only the "every page footer" is mapped.

Knowing that page-position can have the value "only", a possiblity would be to set a static-content for this, too. But still I would have two blocks of the same content and whenever I wanted to edit this part, I would have to change it twice.

You don't have to repeat twice the same content: you can put it into a named template, and call that template from inside the two static contents.

2. The main header normally can be set by a region-before with a reference to page-position="any" (which is the standard), but somehow this won't work for me. I'm just getting the header at pages which aren't first or last. Shouldn't this actually be the desired function of page-position="rest"?

Static content is mapped to a region: check whether that region is actually present in the page masters for the first and for the last page.

EDIT: complete fo example

Here is an example that shows both different page geometry for only/first/rest/any page and different headers/footers according to the page position using fo:markers and fo:retrieve-markers.

I tested it with FOP 1.1, and the resulting pdf should conform to your specifications.

<?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="singlePage" margin="1cm">
            <fo:region-body margin-top="5cm" margin-bottom="4cm" background-color="#FFFFAA"/>
            <fo:region-before extent="4cm" background-color="#AAFFFF"/>
            <fo:region-after extent="3cm" background-color="#FFAAFF" display-align="after"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="firstPage" margin="1cm">
            <fo:region-body margin-top="5cm" margin-bottom="2cm" background-color="#FFFFAA"/>
            <fo:region-before extent="4cm" background-color="#AAFFFF"/>
            <fo:region-after extent="1cm" background-color="#FFAAFF" display-align="after"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="middlePage" margin="1cm">
            <fo:region-body margin-top="2cm" margin-bottom="2cm" background-color="#FFFFAA"/>
            <fo:region-before extent="1cm" background-color="#AAFFFF"/>
            <fo:region-after extent="1cm" background-color="#FFAAFF" display-align="after"/>
        </fo:simple-page-master>
        <fo:simple-page-master master-name="lastPage" margin="1cm">
            <fo:region-body margin-top="2cm" margin-bottom="4cm" background-color="#FFFFAA"/>
            <fo:region-before extent="1cm" background-color="#AAFFFF"/>
            <fo:region-after extent="3cm" background-color="#FFAAFF" display-align="after"/>
        </fo:simple-page-master>
        <fo:page-sequence-master master-name="allPages">
            <fo:repeatable-page-master-alternatives>
                <fo:conditional-page-master-reference page-position="only" master-reference="singlePage"/>
                <fo:conditional-page-master-reference page-position="first" master-reference="firstPage"/>
                <fo:conditional-page-master-reference page-position="rest" master-reference="middlePage"/>
                <fo:conditional-page-master-reference page-position="last" master-reference="lastPage"/>
            </fo:repeatable-page-master-alternatives>
        </fo:page-sequence-master>
    </fo:layout-master-set>
    <fo:page-sequence master-reference="allPages">
        <!--
            header
        -->
        <fo:static-content flow-name="xsl-region-before" font-size="90%">
            <!-- main header on every page -->
            <fo:block>Text, logo, barcode</fo:block>
            <!-- sub header -->
            <fo:retrieve-marker retrieve-class-name="subHeader" retrieve-position="first-starting-within-page"/>
        </fo:static-content>
        <!--
            footer
        -->
        <fo:static-content flow-name="xsl-region-after" font-size="90%">
            <!-- special footer -->
            <fo:retrieve-marker retrieve-class-name="footer" retrieve-position="first-starting-within-page"/>
            <!-- common footer on every page -->
            <fo:block>printing date dd/mm/yyyy</fo:block>
        </fo:static-content>
        <!--
            document body
        -->
        <fo:flow flow-name="xsl-region-body">
            <!-- empty blocks with markers for the header -->
            <fo:block>
                <!-- sub header for the first page -->
                <fo:marker marker-class-name="subHeader">
                    <fo:block>LARGE SUB HEADER</fo:block>
                </fo:marker>
            </fo:block>
            <fo:block>
                <!-- sub header for the not-first pages -->
                <fo:marker marker-class-name="subHeader">
                    <fo:block>small sub header</fo:block>
                </fo:marker>
            </fo:block>
            <!-- normal content -->
            <!-- 
                YOUR REAL CONTENT GOES HERE 
                (I just put some blocks with page breaks to produce a few pages)
            -->
            <fo:block break-after="page">Long sequence with many pages ...</fo:block>
            <fo:block break-after="page">... bla bla bla ...</fo:block>
            <fo:block>... the end</fo:block>
            <!-- empty block with marker for the footer -->
            <fo:block>
                <!-- footer for the last page -->
                <fo:marker marker-class-name="footer">
                    <fo:block>TOTAL AMOUNT $$$ AND SIGNATURES</fo:block>
                </fo:marker>
            </fo:block>
       </fo:flow>
    </fo:page-sequence>
</fo:root>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...