Konvertieren Sie HTML-Inhalte in das PDF-Format

Die Bereitstellung von Webinhalten als PDF ist eine Möglichkeit, die Verbreitung von Inhalten zu erleichtern. In einigen Branchen ist der Zugriff auf druckformatierte Dokumente, z. B. Beschreibungen der Leistungen an Arbeitnehmer, obligatorisch. Das Gesetz schreibt tatsächlich vor, dass zusammenfassende Planbeschreibungen (SPDs) in gedruckter Form zur Verfügung gestellt werden, obwohl der Inhalt online bereitgestellt werden kann. Das Drucken der Webseite reicht nicht aus, da das Druckformat ein Inhaltsverzeichnis mit Seitenzahlreferenzen enthalten muss.

Um einer Webseite solche Funktionen hinzuzufügen, können Entwickler den HTML-Inhalt in das PDF-Format konvertieren. Dieser Artikel zeigt, wie. Die hier dargestellte Methode zur Durchführung der Konvertierung verwendet nur Open-Source-Komponenten. Kommerzielle Produkte unterstützen auch die dynamische Dokumentenerstellung. Adobe verfügt beispielsweise über die Document Server-Produktlinie. Die Kosten sind jedoch erheblich. Durch die Verwendung einer Open Source-Lösung wird der Kostenfaktor verringert und gleichzeitig die Transparenz des Quellcodes erhöht.

Die Konvertierung besteht aus drei Schritten:

  1. Konvertieren Sie den HTML-Code in XHTML
  2. Konvertieren Sie das XHTML-Dokument mithilfe eines XSL-Stylesheets und eines XSLT-Transformators in XSL-FO (Extensible Stylesheet Language Formatating Objects)
  3. Übergeben Sie das XSL-FO-Dokument an einen Formatierer, um das Ziel-PDF-Dokument zu generieren

Dieser Artikel beschreibt, wie die Übersetzungen mithilfe der von den Tools bereitgestellten Befehlszeilenschnittstellen ausgeführt werden, und stellt anschließend ein Java-Programm vor, das die DOM-Schnittstellen (Document Object Model) verwendet.

Komponentenversionen

Der Code in diesem Artikel wurde mit den folgenden Versionen getestet:

Komponente Ausführung
JDK 1.5_06
JTidy r7-dev
Xalan-J 2.7
GECK 0,20,5

Verwenden der Befehlszeilenschnittstellen

Jeder der drei Schritte besteht darin, eine Ausgabedatei aus einer Eingabedatei zu generieren. Die Ein- und Ausgänge der Schritte sind in der folgenden Abbildung dargestellt.

Die Verwendung der Befehlszeilenschnittstellen der drei Tools ermöglicht einen einfachen Einstieg. Dieser Ansatz ist jedoch aufgrund der temporären Zwischendateien, die auf die Festplatte geschrieben werden, nicht für ein System auf Produktionsebene geeignet. Diese zusätzliche E / A würde zu einer schlechten Leistung führen. Später in diesem Artikel wird das Problem der temporären Dateien behoben, wenn die drei Tools von einem Java-Programm aufgerufen werden.

Schritt 1: HTML zu XHTML

Der erste Schritt besteht darin, die HTML-Datei in eine neue XHTML-Datei zu übersetzen. Wenn der Startpunkt für die Konvertierung bereits XHTML ist, gilt dieser Schritt natürlich nicht.

Ich habe JTidy verwendet, um die Übersetzung durchzuführen. JTidy ist ein Java-Port des Tidy HTML-Parsers. Bei der Übersetzung in XHTML fügt JTidy auch fehlende Close-Tags hinzu, um ein wohlgeformtes XML-Dokument zu erstellen. Ich habe die neueste Version verwendet (r7-dev), die auf der SourceForge-Website aufgeführt ist.

Verwenden Sie zum Ausführen von JTidy das folgende Skript tidy.sh:

#/bin/sh

java -classpath lib/Tidy.jar org.w3c.tidy.Tidy -asxml >

Dieses Skript legt die CLASSPATHVariable fest und ruft JTidy auf. Um JTidy auszuführen, wird die Eingabedatei als Befehlszeilenargument übergeben. Standardmäßig wird das generierte XHTML auf die Standardausgabe gerichtet. Der -modifySchalter kann auch zum Überschreiben der Eingabedatei verwendet werden. Der -asxmlSchalter weist JTidy an, wohlgeformtes XML im Gegensatz zu HTML auszugeben.

Das Skript wird wie folgt aufgerufen:

 tidy.sh hello.html hello.xml

Die Dateien hello.html (Eingabe) und hello.xml (Ausgabe) werden hier angezeigt:

Hello World

Hello World!

Hello World

Hello World!

Notiere dass der

Tag hat einen Abschluss

Tag in der von JTidy hinzugefügten XML-Datei.

Schritt 2: XHTML zu XSL-FO

Als nächstes wird das XHTML in XSL-FO umgewandelt, eine Sprache zum Festlegen des Druckformats von XML-Dokumenten. Um die Transformation zu erreichen, wende ich ein XSL-Stylesheet an, das von einem XSLT-Transformator (Apache Xalan) verarbeitet wird. Das Stylesheet, das ich als Ausgangspunkt verwendet habe, ist xhtml2fo.xsl, bereitgestellt von Antenna House, einem Unternehmen, das einen kommerziellen Formatierer für XSL-FO verkauft.

Das Stylesheet xhtml2fo.xsl gibt an, wie jedes der HTML-Tags in die entsprechende Folge von XSL-FO-Formatierungsbefehlen übersetzt werden soll. Im Fall eines HTML- H2Tags ist die Übersetzung beispielsweise wie folgt definiert:

Die obige XSLT-Vorlage wird jedes Mal aufgerufen, wenn ein H2Tag im HTML-Eingabestream auftritt. Das html:Präfix gibt an, dass sich das H2Tag im HTML-Namespace befindet. Die Namespaces des Stylesheets werden als Attribute für die xsl:stylesheetDirektive der obersten Ebene angegeben . Wenn wir uns den Anfang der Datei xhtml2fo.xsl ansehen, sehen wir drei angegebene Namespaces. Eine für jede der Sprachen XSL, XSL-FO und HTML:

 ... 

Die zweite Zeile der Vorlage

bewirkt, dass ein fo:blockTag ausgegeben wird, wobei das H2Attribut festgelegt wird, um die Attribute und Werte für das fo:blockTag zu generieren . Ein XSL-FO-Block ist ein Textbereich, der basierend auf den für die Blockattribute angegebenen Werten gerendert wird.

Der Attributsatz für H2ist im Stylesheet wie folgt definiert:

  10mm 10mm 1em 0.5em x-large bold black  

The start-indent and subsequent attributes above are used to specify the formatted appearance of an H2 block. Using an attribute set makes it easy to change the appearance of all blocks in the PDF document that correspond to the same HTML input tag. Simply change the settings in the attribute set; the output of all translations that use the attribute set will change too.

The next directive in the translation calls the template named "process-common-attributes-and-children":

This template is defined in the stylesheet. Its purpose is to check for some common HTML attributes (i.e., lang, id, align, valign, style) and then generate the corresponding XSL-FO directives. To trigger the translation of any tags nested within the top-level H2 tag, the process-common-attributes-and-children template then calls:

Hence, if the input is

Hello there

the inside the template for H2 would trigger the invocation of the template that translates the tag.

The output of translating an H2 tag is:


     

To apply the xhtml2f0.xsl, we invoke the Xalan transformer. The Unix script xalan.sh sets the CLASSPATH variable with the required jar files before calling Xalan:

#/bin/sh

export CLASSPATH=".;./lib/xalan.jar;./lib/xercesImpl.jar;./lib/xml-apis.jar;lib/serializer.jar"

java -classpath $CLASSPATH org.apache.xalan.xslt.Process -IN -XSL xhtml2fo.xsl -OUT -tt

Since Xalan requires an XML parser, the Apache Xerces parser and xml-api JARs are referenced in addition to xalan.jar. All of the jar files are bundled with the Xalan distribution.

To create an XSL-FO file by applying the stylesheet to the XHTML input, invoke the script:

 xalan.sh hello.xml hello.fo 

I like to use the trace option (-tt) with Xalan to display a trace of the templates that are applied. The file hello.fo is shown below:

Hello World Hello World

- -

Hello World!

Step 3: XSL-FO to PDF

The third and final step is to pass the XSL-FO document to a formatter that can generate PDF. I used Apache FOP (Formatting Objects Processor). FOP partially implements the XSL-FO standard and best supports the PDF output format. There is nascent support for Postscript, and support for Microsoft's RTF (rich text format) is planned. The FOP distribution contains the shell script fop.sh/fop.bat that takes an XSL-FO file as input and generates the specified PDF output file.

The Unix script can be run, for example, by:

 fop.sh hello.fo hello.pdf 

The only prerequisite is to set the environment variable used by the script for the FOP home directory's path.

The file hello.pdf contains the output from FOP and is included in this article's source code, which can be downloaded from Resources.

Since FOP doesn't currently fully implement the XSL-FO standard, there are some limitations. The subset of the standard that is supported is described in detail in the compliance section of the FOP Website.

Java program

Utilizing the DOM APIs of the three tools used in the steps above, I'll now present a Java program that requires two command line arguments (HTML input file and stylesheet) and creates a corresponding PDF. No temporary files are created.

First the program creates an InputStream for the HTML file. The InputStream object is then passed to JTidy.

JTidy has method parseDOM(), which is called to obtain the output XHTML content as a Document object:

public static void main(String[] args) {

// open file if (args.length != 2) { System.out.println("Usage: Html2Pdf htmlFile styleSheet"); System.exit(1); }

FileInputStream input = null; String htmlFileName = args[0]; try { input = new FileInputStream(htmlFileName); } catch (java.io.FileNotFoundException e) { System.out.println("File not found: " + htmlFileName); }

Tidy tidy = new Tidy(); Document xmlDoc = tidy.parseDOM(input, null);

XML namespaces are not supported in the JTidy's DOM implementation; hence, the rules in the Antenna House stylesheet must be modified to use the default namespace. For example, instead of

the rule is changed to

This change must be applied to all templates in xhtml2f0.xsl because the Document object created by JTidy has as the root tag, as opposed to:

The modified version of xhtml2fo.xsl is included in this article's source code.

Next, the method xml2FO() calls Xalan programmatically to apply the stylesheet to the DOM object created by JTidy:

 Document foDoc = xml2FO(xmlDoc, args[1]);

Method xml2FO() first calls getTransformer() to obtain a Transformer object for the specified stylesheet. The Document that represents the result of the transform is then returned: