# XSL-FO PDF erstellen



## manni (29. Mai 2007)

Ich möchte mehrere Zahlen aus einer SQL Datenbank auf vorgefertigte Etiketten drucken. Ich denke mal dass FOP von Apache dazu eine richtige Lösung wäre. Also zuerst ein XML Dokument der Daten erzeugen und dann mittels eines XSL-FO Templates das PDF erstellen.
Dazu brauche ich absolute Positionierung im XSL-FO: etwa in der Art:


```
<fo:block-container top="65mm" left="34mm" position="fixed">
            <fo:block>
               Lable1
            </fo:block>
</fo:block-container>
<fo:block-container top="65mm" left="64mm" position="fixed">
            <fo:block>
               Lable2
            </fo:block>
</fo:block-container>
```

Aber wie mache ich das, um auf jedem Label (zB.: 4x5 Labels auf DINA4 Seite) einen Ausdruck eines Wertes zu erhalten?


----------



## SlaterB (29. Mai 2007)

mache dir außen eine Tabelle mit 4 oder 5 Spalten, je nachdem was du meinst,
für jede Zelle rufst du dann ein Template,
diese 20 einzeiligen Aufrufe kannst du gerne einzeln aufführen,
<xsl:call-template name="xy"/>
weiß grad nicht, ob es da feste Schleife gibt, sicherlich auch

oder 4x ein Template für eine Zeile aufrufen und darin 5 Aufrufe für die Spalten

-------

in dem Zellentemplate gestaltest du eine Zelle mit den Daten der Vorlage


----------



## SnooP (29. Mai 2007)

Wenn du mit dem XSLT nicht so ganz klar kommst... - so wie ich, weil keine Lust zu lernen *g* - dann kannst du stattdessen auch Velocity verwenden und damit transformieren... das läuft imperativer 

Aber richtiger Ansatz wäre schonmal das ganze in eine Tabelle zu gießen, weil man dann die Zellenhöhen verwenden kann und nix selber rechnen muss... ansonsten musst du natürlich schlicht in jedem Schleifendurchlauf neben dem zu druckenden Text entweder left oder top verändern oder auch beides.


----------



## manni (29. Mai 2007)

erstmal danke für die Tipps - aber ich habe schon mal Installationsprobleme, um ein einfaches Beispiel zum Laufen zu bringen.

Verwende Tomcat 5.x, und FOP 0.20.5. Dort programmiere ich an einer JSP Weblösung.
Ich verwende Eclipse.

Ich habe mal einfach das fop.jar in webapps\test\web-inf\lib\ kopiert. Dann eine XML und XSL in webapps\test\resources kopiert, und ein package pdf angelegt und dort ein Java Servlet mit folgendem Code:


```
package pdf;

import org.apache.fop.apps.Driver;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import javax.xml.transform.*;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import java.io.IOException;

public class DisplayServlet extends HttpServlet {
   protected void service(
      HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

      // FO-Treiber erzeugen
      Driver driver = new Driver();
      driver.setRenderer(Driver.RENDER_PDF);

      // Outputstream für die Speicherung des generierten
      // PDF-Dokuments festlegen
      driver.setOutputStream(response.getOutputStream());

      // ServletContext ermitteln
      ServletContext ctx = getServletContext();

      // XML- und XSLT-Dokument laden
      Source xml = new StreamSource(
         ctx.getResourceAsStream("/resources/data.xml"));
      Source xsl = new StreamSource(
         ctx.getResourceAsStream("/resources/style.xsl"));

      // Result-Instanz ist eine SAXResult-Instanz, die an
      // den PDF-Renderer gebunden ist
      Result res = new SAXResult(driver.getContentHandler());

      // Transformation beginnen
      TransformerFactory factory = TransformerFactory.newInstance();
      Templates templates = null;
      try {
         // Templates-Instanz erzeugen
         templates = factory.newTemplates(xsl);

         // Transformer-Instanz erzeugen
         Transformer transformer = templates.newTransformer();

         // Inhalt transformieren, dabei wird auch gleich das PDF
         // erzeugt
         transformer.transform(xml, res);

         // ContentType setzen, damit das Ergebnis korrekt
         // im Browser dargestellt werden kann
         response.setContentType("application/pdf");
         //response.setContentType("text/xml");
      }  catch (TransformerConfigurationException e) {
         e.printStackTrace();
      } catch (TransformerException e) {
         e.printStackTrace();
      }
   }
}
```

Ich bekomme aber in Eclipse schon bei import org.apache.fop.apps.Driver einen Fehler. Oder bin ich hier sowieso falsch am Weg?


----------



## SlaterB (29. Mai 2007)

also wenn du so fragst, dann scheinst du generell von Bibliotheks-Nutzung, Versionskontrolle und allem was dazugehört wenig Ahnung zu haben,
dann ist 'einfach mal machen' durchaus der falsche Weg,
aber das ist natürlich schwierig zu lernen..

hast du die Lib in Eclipse auch importiert?
(Project, Properties, Java  Build Path, Libraries)


----------



## manni (29. Mai 2007)

tja - ertappt - grad sattelfest bin ich da nicht...

aber jetzt klappts dank deinem Tipp. Nur bekomme ich jetzt obiges Servlet nicht zum Laufen (bzw. wird nicht gefunden). Da ich sonst nur JSP-Dateien, Java Klassen und Beans verwende, weiss ich jetzt nicht wo der Fehler liegt.

Ich habs mit Eclipse als Servlet erstellt - in einem Package pdf. Die Mapping URL lautet /servlet/DisplayPDFServlet - und Eclipse macht einen automat. Eintrag in der web.xml.
Trotzdem bekomme ich beim Aufruf von http://..../pdf/servlet/DisplayPDFServlet  einen 404 error??!


----------



## SlaterB (29. Mai 2007)

fange mit einem Hello World-Servlet an.. (Tutorials lesen, Beispielprogramme ausprobieren)),

und bei Fragen mache einen neuen Thread auf,
hier Richtung PDF wird kaum einer zu Servlets reinschauen


----------



## manni (29. Mai 2007)

so - jetzt habe ich endlich das obige Beispiel am Laufen.
Das funktioniert aber nur im Firefox 2 und nicht im Internet Explorer 7:

Da erhalte ich so etwas:

```
%PDF-1.3 %���� 4 0 obj << /Type /Info /Producer (null) >> endobj 5 0 obj << /Length 714 /Filter /FlateDecode >> stream x���K��@�����n�*���#
```


----------



## MasterEvil (29. Mai 2007)

Das liegt vermutlich daran das mit der Seite nicht der Content-Type übertragen wird. Der muss natürlich auf PDF-Datei im Header angepasst werden.


----------



## manni (29. Mai 2007)

MasterEvil hat gesagt.:
			
		

> Das liegt vermutlich daran das mit der Seite nicht der Content-Type übertragen wird. Der muss natürlich auf PDF-Datei im Header angepasst werden.



..stimmt das nicht ?


```
templates = factory.newTemplates(xsl);

         // Transformer-Instanz erzeugen
         Transformer transformer = templates.newTransformer();

         // Inhalt transformieren, dabei wird auch gleich das PDF
         // erzeugt
         transformer.transform(xml, res);

         // ContentType setzen, damit das Ergebnis korrekt
         // im Browser dargestellt werden kann
         response.setContentType("application/pdf");
```


----------



## SlaterB (29. Mai 2007)

du setzt hoffentlich den ContentType BEVOR du das PDF in die Response schreibst?


----------



## manni (29. Mai 2007)

SlaterB hat gesagt.:
			
		

> du setzt hoffentlich den ContentType BEVOR du das PDF in die Response schreibst?



danke, das war der Fehler....  der IE zickt halt wie immer...


----------



## SlaterB (29. Mai 2007)

da zickt jeder der dieses Feld beachtet, 
denn wie soll man die bereits empfangenen Daten richtig anzeigen, 
wenn die entscheidene Information erst 2 Sekunden später kommt?

von Syntax/ Protokollvereinbarungen ganz zu schweigen


----------



## manni (29. Mai 2007)

und wie so klappte es dann im Firefox??


----------



## SlaterB (29. Mai 2007)

ach ich dachte wir wären da auf dem Stand, dass der ContentType gar nicht gebraucht wird,
sondern das Format automatisch erkannt wird,

aber du hattest da ja auch den ContentType gesetzt, dann stimmt es vielleicht


----------



## SnooP (30. Mai 2007)

by the way würde ich nicht mehr fop 0.2x nehmen - sondern auf 0.9.3 umschwenken! ... dringendsd angeraten! - 0.9.3 wurde nahezu komplett neu geschrieben, nachdem man mit der alten Version nicht mehr zu Rande kam...


----------

