von Patrick Gundlach |

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, da true() 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:

Automatischer Textüberlauf im Textrahmen

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>

Seitenkopf und -fuß

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>

Verschiedene Seitentypen

In der Serie »Feature der Woche« beschreibe ich jeden Montag mehr oder weniger nützliche Eigenschaften des Publishers. Kommentare gerne an mich per E-Mail oder einfach im Kommentarfeld.