von Patrick Gundlach |

Versionen 2.9.13 und 2.9.14

Heute habe ich nach etwas Ruhe zwei neue Versionen hochgeladen. Die Neuerungen kann ich für ein aktuelles Kundenprojekt gut gebrauchen.

In XML eingebettete Bilder

Die Daten in einem aktuellen Kundenprojekt werden aus einer SQL-Datenbank extrahiert und in XML gewandelt. Zu den Daten gehören auch Bilddaten, die als BLOB ebenfalls in der Datenbank liegen. Nun ist die Frage: wie kommen die Bilder in das PDF? Eine Möglichkeit ist, die Bilder im Dateisystem zu speichern und den Dateinamen in das XML zu speichern. Wir haben einen anderen Weg gewählt und so sind die Bilder Base64 kodiert in den Daten enthalten. Das hat den offensichtlichen Nachteil, dass die XML-Daten nun größer sind (deutlich größer). Der Vorteil ist nicht von der Hand zu weisen: es ist keine separate Datenhaltung der Bilder notwendig. Die XML-Datei ist also self-contained und kann leichter archiviert werden.

Doch nun stellt sich die Frage: wie bekommt man die Bilder aus der XML-Datei heraus in das PDF? Für den Publisher ist es notwendig, dass die Bilder als externe Datei vorliegen. Als großer Freund von XSLT und XPath schiele ich natürlich auf die expath-Erweiterung von Saxon (u.a.), doch der Auftraggeber wollte eine andere Lösung.

Daten extrahieren

Seit Version 2.9.13 gibt es im Publisher zwei neue Funktionen: sd:decode-base64() und sd:filecontents(). Erstere dekodiert einen Base64 String und liefert einen Binärstrom zurück, den ich mit der zweiten Funktion in eine temporäre Datei schreiben kann. Diese Funktion wiederum liefert den Pfad zur temporären Datei zurück. Somit ist es nun leicht, das Bild aus der XML-Datei einzubinden

Gegeben sei eine Datendatei in der folgenden Form (data.xml):

<data>/9j/4AAQSkZJRgABAQEBLAEsAAD/
  4QECRXhpZgAATU0AKgAAAAgABAEPAAIA
  AAAGAAAAPgEQAAIAAAAQAAAARIKaAAUA
  AAABAAAAVIdpAAQAAAABAAAAXAAAAABD
  ....
  U3KQ8AZQwJPHlkRnHyB5Ova9oP/Z
</data>

Dann kann man das Bild extrahieren und laden mit folgendem Code in der Layoutdatei (layout.xml):

<Layout
  xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

  <Record element="data">
    <PlaceObject>
      <Image file="{ sd:filecontents(sd:decode-base64(.)) }" width="4"/>
    </PlaceObject>
  </Record>
</Layout>

Die geschweiften Klammern sind notwendig, damit vorübergehend in den XPath-Modus gesprungen wird. Eine Besonderheit ist hier gegeben: die Bilddatei benötigt keine Dateiendung, der Publisher erkennt das Format am Inhalt.

Das Ergebnis ist wenig überraschend ein Bild:

Das Bild wird indirekt aus der XML-Datei gelesen

Umschalten der Schriftart in den Daten

Ein weiteres schickes Feature (Version 2.9.14) ist die Möglichkeit, in den Daten mit CSS auf andere Schriftarten umzuschalten (font-family). Hintergrund ist die Nutzung von der beliebten Icon-Schriftart FontAwesome. Die Zeichen in der Schriftart lassen sich über einen Code ansprechen, z.B. ist &#xf240; der Code für eine volle Batterie (siehe die Beschreibung auf der Webseite). Um das Zeichen auszugeben, muss man auf die entsprechende Schriftart umschalten. Im Layout würde man das wie folgt machen:

<Layout
  xmlns="urn:speedata.de:2009/publisher/en"
  xmlns:sd="urn:speedata:2009/publisher/functions/en">

  <LoadFontfile name="FontAwesome" filename="fontawesome-webfont.ttf" />
  <DefineFontfamily name="FA" fontsize="10" leading="12">
    <Regular fontface="FontAwesome"/>
  </DefineFontfamily>

  <Record element="data">
    <PlaceObject>
      <Textblock>
        <Paragraph>
          <Fontface fontfamily="FA"><Value>&#xf240;</Value></Fontface>
          <Value> Die Batterie ist voll geladen</Value>
        </Paragraph>
      </Textblock>
    </PlaceObject>
  </Record>
</Layout>

Wenn man diese Zeichen aber in die Daten einfügen möchte, und nicht in der Layoutdatei, muss der Publisher wissen, wann auf die FontAwesome-Schriftart umgeschaltet werden muss.

Ist die Datendatei z.B. wie folgt aufgebaut:

<data>
  <fa>&#xf240;</fa>  Die Batterie ist voll geladen
  <fa>&#xf243;</fa>  Da geht noch was
</data>

muss man den Publisher anweisen, bei dem (bisher unbekannten) Tag <fa> auf die entsprechende Fontfamilie umzuschalten:

<Stylesheet>
  fa {
     font-family: FA;
  }
</Stylesheet>

Fügt man nun die CSS-Anweisung in das Layout oben ein, wird bei dem <fa>-Tag auf die mit <DefineFontfamily> definierte Schriftart umgestellt.

Mischung von FontAwesome mit einer Textschrift.

Tipp: die OpenType Variante der Schriftart scheint sehr ungewöhnliche Zeichenbreiten zu haben. Die TrueType Variante ist hingegen brauchbar.

Tipp 2: für XSLT 2.0-Freunde habe ich hier ein Stylesheet hinterlegt, das aus <i class="fa fa-..."></i> einen entsprechenden Code erzeugt.