Feature der Woche: Seitentypen
Seitentypen (oder auch Masterseiten, Seitenvorlagen) dienen dazu, Ränder für Seiten zu definieren, Platzierungsrahmen zu erstellen und Aktionen auszuführen, wenn eine Seite erzeugt oder in die PDF Datei geschrieben wird. Klassischerweise gibt es eine Seitenvorlage für linke Seiten und für rechte Seiten. Im einfachsten Fall sieht eine Vorlage so aus:
<Pagetype name="page" test="...">
<Margin left="1cm" right="1cm" top="1cm" bottom="1cm"/>
</Pagetype>
Der angegebene Name ist erst einmal nur zur Information, kann aber für andere
Befehle interessant werden. Ein Rand muss angegeben werden. Die Bedingung im
Attribut test
kann beliebig komplex sein. Eine Seite wird ausgewählt, sobald
ein Test eines Seitentyps wahr ergibt. Beispiele:
true()
: Diese Seite wird immer ausgewählt, datrue()
immer wahr ergibt.sd:current-page() > 1
: Hier wird die Seitenvorlage für alle Seiten ausgewählt, die nach der ersten Seite folgen.sd:even(sd:current-page())
: Wenn die neue Seitenzahl gerade ist, kommt dieser Seitentyp zu tragen. Das ist in der Regel dann, wenn es sich um eine linke Seite handelt.- Es kann aber auch komplexer werden:
sd:even(sd:current-page()) and $abschnitt = 'innenteil'
. Solange die Bedingung zu wahr oder falsch ausgewertet werden kann, ist dies ein gültiger Ausdruck.
Was passiert aber, wenn es mehrere Bedingungen gibt, die sich widersprechen oder gleichzeitig wahr sind? Die Seitentypen werden von »unten nach oben« ausgewertet. Das heißt, dass spezielle Seitenvorlagen später definiert werden müssen als die allgemeinen. Die voreingestellte Vorlage hat als Bedingung true()
und wird nach der Logik zuletzt ausgewertet.
Textrahmen
In der Seitentyp-Definition können auch Textrahmen angelegt werden. Das sind
rechteckige Bereiche auf einer Seite, die über einen Namen angesprochen
werden. Beispiele dafür sind »Kopfbereich«, »Seitenleiste« oder »Fußzeile«.
Diese Bereiche lassen sich bei <PlaceObject>
ansteuern und wechseln
automatisch auf den nächsten freien Rahmen, wenn sie voll sind.
<Layout xmlns="urn:speedata.de:2009/publisher/en"
xmlns:sd="urn:speedata:2009/publisher/functions/en">
<Options show-grid="yes"/>
<Pageformat width="16cm" height="12cm"/>
<SetGrid width="1cm" height="12pt"/>
<Pagetype name="page" test="true()">
<Margin left="1cm" right="1cm" top="1cm" bottom="1cm"/>
<PositioningArea name="text">
<PositioningFrame width="4" height="18" row="2" column="1"/>
<PositioningFrame width="4" height="10" row="3" column="6"/>
<PositioningFrame width="4" height="24" row="1" column="11"/>
</PositioningArea>
</Pagetype>
<Record element="data">
<Output area="text">
<Text>
<Loop select="5">
<Paragraph>
<Value select="sd:dummytext()"/>
</Paragraph>
</Loop>
</Text>
</Output>
</Record>
</Layout>
Das laufen lassen mit sp --dummy
um folgende Ausgabe zu erhalten:
AtPageCreation, AtPageShipout
Die beiden Befehle <AtPageCreation>
und <AtPageShipout>
sind dafür zuständig, Code auszuführen, wenn eine Seite erzeugt wird (es wird zum ersten Mal etwas ausgegeben) und wenn eine Seite in die PDF Datei geschrieben wird. Diese können für vielfältige Zwecke benutzt werden. Üblich ist es, in <AtPageCreation>
den Seitenkopf zu erzeugen und in <AtPageShipout>
den Seitenfuß.
Es folgt ein etwas umfangreicheres Beispiel. Auch dies mit sp --dummy
übersetzen:
<Layout xmlns="urn:speedata.de:2009/publisher/en"
xmlns:sd="urn:speedata:2009/publisher/functions/en">
<DefineTextformat name="center" alignment="centered"/>
<Stylesheet>
td {
padding-top: 3pt;
}
</Stylesheet>
<Pagetype name="page" test="true()">
<Margin left="1cm" right="1cm" top="1cm" bottom="1cm"/>
<AtPageCreation>
<PlaceObject column="1" row="1">
<Textblock>
<Paragraph textformat="center">
<Value>Titel</Value>
</Paragraph>
</Textblock>
</PlaceObject>
</AtPageCreation>
<AtPageShipout>
<PlaceObject column="1" row="{sd:number-of-rows() - 1}">
<Table stretch="max">
<Tablerule/>
<Tr>
<Td align="left"><Paragraph><Value select="sd:current-page()"/></Paragraph></Td>
<Td align="right"><Paragraph><Value>Firmenname</Value></Paragraph></Td>
</Tr>
</Table>
</PlaceObject>
</AtPageShipout>
</Pagetype>
<Record element="data">
<PlaceObject>
<Textblock>
<Paragraph>
<Value>Inhalt</Value>
</Paragraph>
</Textblock>
</PlaceObject>
</Record>
</Layout>
NewPage
Oben habe ich erwähnt, dass der Name des Seitentyps keine Rolle spielt. Das ist nicht ganz richtig. Bei dem Befehl <NewPage>
kann angegeben werden, welcher Seitentyp ausgewählt werden soll. Man kann den Test beim Seitentyp auch auf false()
setzen, er wird dennoch ausgewählt, da er explizit angegeben wird.
Im folgenden Beispiel werden zwei Seitentypen definiert, eine »Standard«-Vorlage, die immer genommen wird und eine Vorlage »Spezial«, die explizit mit <NewPage>
ausgewählt wird. Das Beispiel kann wie immer mit sp --dummy
übersetzt werden, wenn die Datei als layout.xml
gespeichert wird.
<Layout xmlns="urn:speedata.de:2009/publisher/en"
xmlns:sd="urn:speedata:2009/publisher/functions/en">
<DefineTextformat name="center" alignment="centered"/>
<Pageformat width="210mm" height="50mm"/>
<Pagetype name="Spezial" test="false()">
<Margin left="1cm" right="1cm" top="1cm" bottom="1cm"/>
<AtPageCreation>
<PlaceObject column="1" row="1">
<Textblock>
<Paragraph textformat="center">
<Value>Das ist die Seitenvorlage »Spezial«</Value>
</Paragraph>
</Textblock>
</PlaceObject>
</AtPageCreation>
</Pagetype>
<Pagetype name="Standard" test="true()">
<Margin left="1cm" right="1cm" top="1cm" bottom="1cm"/>
<AtPageCreation>
<PlaceObject column="1" row="1">
<Textblock>
<Paragraph textformat="center">
<Value>Das ist die Seitenvorlage »Standard«</Value>
</Paragraph>
</Textblock>
</PlaceObject>
</AtPageCreation>
</Pagetype>
<Record element="data">
<PlaceObject>
<Textblock>
<Paragraph>
<Value>Seite </Value><Value select="sd:current-page()"/>
</Paragraph>
</Textblock>
</PlaceObject>
<NewPage pagetype="Spezial" openon="right" />
<PlaceObject>
<Textblock>
<Paragraph>
<Value>Seite </Value><Value select="sd:current-page()"/>
</Paragraph>
</Textblock>
</PlaceObject>
</Record>
</Layout>