Ubah konten HTML ke format PDF

Membuat konten Web tersedia sebagai PDF adalah salah satu cara untuk memfasilitasi penyebaran konten. Di beberapa industri, menyediakan akses ke dokumen berformat cetak, seperti deskripsi tunjangan karyawan, adalah wajib. Undang-undang sebenarnya menentukan bahwa ringkasan rencana deskripsi (SPD) tersedia dalam format cetak meskipun isinya mungkin disediakan secara online. Mencetak Halaman Web saja tidak cukup karena format cetak harus menyertakan daftar isi dengan referensi nomor halaman.

Untuk menambahkan fungsionalitas tersebut ke Halaman Web, pengembang dapat mengonversi konten HTML ke format PDF; artikel ini menggambarkan caranya. Metode yang diilustrasikan di sini untuk melakukan konversi hanya menggunakan komponen open source. Produk komersial juga mendukung pembuatan dokumen dinamis. Adobe memiliki lini produk Server Dokumen, misalnya; Namun, biayanya cukup besar. Menggunakan solusi open source mengurangi faktor biaya sambil menambahkan transparansi kode sumber.

Konversi terdiri dari tiga langkah:

  1. Ubah HTML menjadi XHTML
  2. Ubah dokumen XHTML ke XSL-FO (Objek Pemformatan Bahasa Stylesheet yang Dapat Diperluas) menggunakan lembar gaya XSL dan transformator XSLT
  3. Teruskan dokumen XSL-FO ke pemformat untuk menghasilkan dokumen PDF target

Artikel ini menunjukkan cara melakukan terjemahan menggunakan antarmuka baris perintah yang disediakan oleh alat dan kemudian memperkenalkan program Java yang menggunakan antarmuka DOM (Model objek dokumen).

Versi komponen

Kode dalam artikel ini telah diuji dengan versi berikut:

Komponen Versi: kapan
JDK 1.5_06
JTidy r7-dev
Xalan-J 2.7
PESOLEK 0.20.5

Menggunakan antarmuka baris perintah

Masing-masing dari tiga langkah tersebut terdiri dari menghasilkan file keluaran dari file masukan. Input dan output dari langkah-langkah tersebut ditunjukkan pada gambar di bawah ini.

Menggunakan antarmuka baris perintah dari tiga alat memungkinkan cara mudah untuk memulai. Namun, pendekatan ini tidak cocok untuk sistem tingkat produksi karena file perantara sementara yang akan ditulis ke disk. I / O ekstra ini akan menghasilkan kinerja yang buruk. Kemudian di artikel ini, masalah file sementara menjadi diperdebatkan saat tiga alat dipanggil oleh program Java.

Langkah 1: HTML ke XHTML

Langkah pertama adalah menerjemahkan file HTML ke file XHTML baru. Tentunya jika titik awal untuk konversi sudah XHTML, maka langkah ini tidak berlaku.

Saya menggunakan JTidy untuk menerjemahkan. JTidy adalah port Java dari pengurai HTML Tidy. Dalam proses penerjemahan ke XHTML, JTidy juga menambahkan tag dekat yang hilang untuk membuat dokumen XML dengan format yang baik. Saya menggunakan versi terbaru yang terdaftar (r7-dev) di Situs Web SourceForge.

Untuk menjalankan JTidy, gunakan skrip tidy.sh berikut:

#/bin/sh

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

Skrip ini menetapkan CLASSPATHvariabel dan memanggil JTidy. Untuk menjalankan JTidy, file input dikirimkan sebagai argumen baris perintah. Secara default, XHTML yang dihasilkan diarahkan ke output standar. The -modifyswitch juga dapat digunakan untuk menimpa file masukan. The -asxmlberalih mengarahkan JTidy untuk output well-formed XML sebagai lawan HTML.

Skrip dipanggil sebagai:

 tidy.sh hello.html hello.xml

Dan file hello.html (input) dan hello.xml (output) ditampilkan di sini:

Hello World

Hello World!

Hello World

Hello World!

Perhatikan bahwa

tag memiliki penutup

tag dalam file XML yang ditambahkan oleh JTidy.

Langkah 2: XHTML ke XSL-FO

Selanjutnya, XHTML diubah menjadi XSL-FO, bahasa untuk menentukan format cetak dokumen XML. Untuk mencapai transformasi, saya menerapkan lembar gaya XSL yang diproses oleh transformator XSLT (Apache Xalan). Stylesheet yang saya gunakan sebagai titik awal adalah xhtml2fo.xsl, disediakan oleh Antenna House, perusahaan yang menjual formatter komersial untuk XSL-FO.

Stylesheet xhtml2fo.xsl menentukan bagaimana setiap tag HTML akan diterjemahkan ke urutan yang sesuai dari perintah pemformatan XSL-FO. Misalnya, dalam kasus H2tag HTML , terjemahannya didefinisikan sebagai:

Template XSLT di atas dipanggil setiap kali H2tag ditemukan dalam aliran input HTML. The html:awalan menunjukkan bahwa H2tag adalah di namespace HTML. Ruang nama stylesheet ditetapkan sebagai atribut ke xsl:stylesheetdirektif level teratas . Melihat di bagian atas file xhtml2fo.xsl, kita melihat tiga ruang nama ditentukan. Satu untuk setiap bahasa XSL, XSL-FO, dan HTML:

 ... 

Baris kedua dari template

menyebabkan fo:blocktag menjadi keluaran, dengan H2set atribut untuk menghasilkan atribut dan nilai untuk fo:blocktag. Blok XSL-FO adalah wilayah teks yang dirender berdasarkan nilai yang ditentukan untuk atribut blok.

Set atribut untuk H2didefinisikan dalam stylesheet sebagai:

  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: