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:
- Ubah HTML menjadi XHTML
- Ubah dokumen XHTML ke XSL-FO (Objek Pemformatan Bahasa Stylesheet yang Dapat Diperluas) menggunakan lembar gaya XSL dan transformator XSLT
- 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 CLASSPATH
variabel dan memanggil JTidy. Untuk menjalankan JTidy, file input dikirimkan sebagai argumen baris perintah. Secara default, XHTML yang dihasilkan diarahkan ke output standar. The -modify
switch juga dapat digunakan untuk menimpa file masukan. The -asxml
beralih 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
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 H2
tag HTML , terjemahannya didefinisikan sebagai:
Template XSLT di atas dipanggil setiap kali H2
tag ditemukan dalam aliran input HTML. The html:
awalan menunjukkan bahwa H2
tag adalah di namespace HTML. Ruang nama stylesheet ditetapkan sebagai atribut ke xsl:stylesheet
direktif 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:block
tag menjadi keluaran, dengan H2
set atribut untuk menghasilkan atribut dan nilai untuk fo:block
tag. Blok XSL-FO adalah wilayah teks yang dirender berdasarkan nilai yang ditentukan untuk atribut blok.
Set atribut untuk H2
didefinisikan 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: