XSLT berkembang dengan Java

Pernahkah Anda dibingungkan oleh masalah transformasi XML yang sulit yang tidak dapat Anda selesaikan dengan XSLT (Transformasi Bahasa Stylesheet yang Dapat Diperluas) saja? Ambil, misalnya, lembar gaya filter sederhana yang hanya memilih node yang tertanggal lebih awal dari lima hari yang lalu. Anda pernah mendengar bahwa XSLT dapat memfilter dokumen XML, jadi Anda yakin akan menyelesaikan masalah ini dalam waktu singkat. Tugas pertama adalah mendapatkan tanggal hari ini dari dalam stylesheet, asalkan informasi tersebut tidak disertakan dalam dokumen XML asli. Sayangnya, Anda tidak dapat menyelesaikan tugas ini hanya dengan XSLT. Dalam situasi seperti ini, Anda dapat menyederhanakan kode XSLT Anda dan menyelesaikan masalah lebih cepat dengan ekstensi Java.

Banyak prosesor XSLT memungkinkan beberapa jenis mekanisme ekstensi; spesifikasi mengharuskan mereka untuk melakukannya. Di dunia Java dan XML, prosesor XSLT yang paling banyak digunakan adalah prosesor Apache Xalan open source. Ditulis di Java, Xalan memungkinkan ekstensi di Java. Banyak pengembang menganggap ekstensibilitas Xalan sangat kuat karena memungkinkan mereka memanfaatkan keterampilan Java mereka dari dalam konteks lembar gaya. Pertimbangkan cara JSP (Halaman JavaServer), scriptlet, dan tag kustom menambahkan kekuatan ke HTML. Ekstensi Xalan menambahkan kekuatan ke stylesheet dengan cara yang hampir sama: dengan mengizinkan pengembang Java mengakses alat favorit mereka, Java.

Pada artikel ini, saya akan mendemonstrasikan bagaimana Anda dapat menggunakan Java dari dalam lembar gaya XSLT. Pertama, kita akan menggunakan ekstensibilitas Xalan untuk membuat instance dan menggunakan kelas yang ada di dalam JDK. Nanti, saya akan menunjukkan cara menulis fungsi ekstensi XSLT yang mengambil Stringargumen dan mengembalikan fragmen DOM (Model Objek Dokumen) ke prosesor stylesheet.

XSLT penting untuk pengembang J2EE (Java 2 Platform, Enterprise Edition) karena gaya dokumen XML telah menjadi operasi sisi server. Selain itu, JAXP (Java API for XML Processing), yang menyertakan dukungan untuk mesin XSLT, telah menjadi bagian dari spesifikasi J2EE (J2EE 2.6.11). Dalam masa pertumbuhan, XSLT dimaksudkan untuk mendesain XML pada klien; namun, sebagian besar aplikasi memberi gaya XML sebelum mengirimkannya ke klien. Untuk pengembang J2EE, ini berarti prosesor XSLT kemungkinan besar akan berjalan di dalam server aplikasi.

Sebelum Anda melanjutkan artikel ini, berhati-hatilah bahwa menggunakan ekstensi Java di lembar gaya XSLT Anda akan mengurangi portabilitasnya. Meskipun ekstensi adalah bagian dari spesifikasi XSLT, cara penerapannya tidak. Jika stylesheet Anda akan berjalan pada prosesor selain Xalan, seperti mesin stylesheet Internet Explorer, Anda harus menghindari penggunaan ekstensi dengan cara apa pun.

Kelemahan XSLT

Karena XSLT memiliki beberapa titik lemah, ekstensi XSLT terbukti cukup berguna. Saya tidak mengatakan bahwa XSLT buruk; Namun, itu tidak menawarkan alat terbaik untuk memproses segala sesuatu dalam dokumen XML. Pertimbangkan bagian XML ini:

 XSLT tidak mudah digunakan seperti yang beberapa orang inginkan ...   

Misalkan atasan Anda meminta Anda untuk memodifikasi stylesheet sehingga mengubah semua contoh "tidak" menjadi "bukan" dan melokalkan label umum. Tentu saja XSLT menyediakan mekanisme untuk melakukan sesuatu seperti ini, bukan? Salah. XSLT tidak menyediakan cara mudah untuk mengganti kemunculan kata atau pola di dalam string. Hal yang sama berlaku untuk pelokalan. Itu tidak berarti itu tidak dapat dilakukan dengan sintaks XSLT standar. Ada cara, tetapi tidak semudah yang kita inginkan. Jika Anda benar-benar ingin menulis fungsi manipulasi teks menggunakan templat rekursif, jadilah tamu saya.

Kelemahan utama XSLT adalah pemrosesan teks, yang tampaknya masuk akal karena tujuannya adalah untuk merender XML. Namun, karena konten XML seluruhnya adalah teks, XSLT membutuhkan penanganan teks yang lebih kuat. Tak perlu dikatakan, desainer stylesheet memerlukan beberapa ekstensibilitas dari waktu ke waktu. Dengan Xalan, Java menyediakan ekstensibilitas ini.

Gunakan kelas JDK dalam XSLT

Anda mungkin senang mengetahui bahwa Anda tidak perlu menulis kode Java apa pun untuk memanfaatkan ekstensibilitas Xalan. Saat Anda menggunakan Xalan, Anda bisa membuat dan memanggil metode di hampir semua objek Java. Sebelum menggunakan kelas Java, Anda harus memberikan namespace XSLT untuknya. Contoh ini mendeklarasikan "java"sebagai namespace untuk semua yang ada di dalam atau di bawah paket Java (yaitu, seluruh JDK):


  

Sekarang kita perlu melakukan sesuatu. Mari kita mulai dengan dokumen XML kecil:

 Java May Be a Fad J. Burke 30/11/97  

Anda telah diminta untuk mengatur gaya XML ini sehingga judul muncul dalam huruf besar. Pengembang yang baru mengenal XSLT hanya akan membuka referensi XSLT untuk mencari toUpper()fungsi; akan tetapi, dia akan kecewa karena referensi itu kurang. The translate()Metode adalah taruhan terbaik Anda, tapi saya memiliki metode yang lebih baik: java.lang.String.toUpperCase(). Untuk menggunakan metode ini, Anda perlu membuat instance Stringobjek dengan konten judul. Berikut adalah cara membuat Stringinstance baru dengan konten elemen judul:


  

The nameatribut menentukan pegangan untuk Anda yang baru Stringmisalnya. Anda memanggil konstruktor dengan terlebih dahulu menentukan namespace bersama dengan jalur yang tersisa ke Stringkelas. Seperti yang mungkin telah Anda perhatikan, Stringtidak memiliki new()metode. Anda gunakan new()untuk membuat objek Java di Xalan; itu sesuai dengan newkata kunci Java . Argumen yang diberikan untuk new()menentukan versi konstruktor yang akan dipanggil. Sekarang setelah Anda memiliki konten judul dalam Stringobjek Java , Anda dapat menggunakan toUpperCase()metode ini, seperti:


  

Ini mungkin terlihat aneh bagi Anda pada awalnya. Saat menggunakan metode Java pada contoh tertentu, argumen pertama adalah contoh tempat Anda ingin metode tersebut dipanggil. Jelas Xalan menggunakan introspeksi untuk menyediakan kemampuan ini.

Di bawah ini Anda akan menemukan trik lain. Inilah cara Anda memancarkan tanggal dan waktu di mana saja dalam stylesheet Anda menggunakan java.lang.Date:


  

Inilah sesuatu yang akan membuat hari siapa pun diminta untuk melokalkan stylesheet generik antara dua atau lebih bahasa. Anda dapat menggunakan java.util.ResourceBundleuntuk melokalkan teks literal dalam stylesheet. Karena XML Anda memiliki tag penulis, Anda mungkin ingin mencetak di "Author:"sebelah nama orang tersebut.

Salah satu opsinya adalah membuat stylesheet terpisah untuk setiap lokal, yaitu satu untuk bahasa Inggris, satu lagi untuk bahasa Cina, dan seterusnya. Masalah yang melekat dalam pendekatan ini harus terbukti. Menjaga konsistensi beberapa versi stylesheet memakan waktu. Anda juga perlu memodifikasi aplikasi Anda sehingga ia memilih stylesheet yang benar berdasarkan lokal pengguna.

Daripada menduplikasi lembar gaya untuk setiap bahasa, Anda dapat memanfaatkan fitur pelokalan Java. Melokalkan dengan bantuan ResourceBundlemembuktikan pendekatan yang lebih baik. Dalam XSLT, muat ResourceBundledi awal stylesheet Anda, seperti:


  

The ResourceBundlekelas mengharapkan untuk menemukan file bernama General.propertiesdalam Anda CLASSPATH. Setelah bundel dibuat, itu dapat digunakan kembali di seluruh stylesheet. Contoh ini mengambil authorsumber daya:


  

Perhatikan lagi tanda tangan metode aneh. Biasanya, ResourceBundle.getString()hanya membutuhkan satu argumen; namun, dalam XSLT Anda juga perlu menentukan objek yang ingin Anda gunakan untuk memanggil metode ini.

Tulis ekstensi Anda sendiri

Untuk beberapa situasi yang jarang terjadi, Anda mungkin perlu menulis ekstensi XSLT Anda sendiri, dalam bentuk fungsi ekstensi atau elemen ekstensi. Saya akan membahas membuat fungsi ekstensi, sebuah konsep yang cukup mudah dipahami. Semua fungsi ekstensi Xalan dapat mengambil string sebagai input dan mengembalikan string ke prosesor XSLT. Ekstensi Anda juga dapat menggunakan NodeLists atau Nodes sebagai argumen dan mengembalikan jenis ini ke prosesor XSLT. Menggunakan Nodes atau NodeLists berarti Anda dapat menambahkan ke dokumen XML asli dengan fungsi ekstensi, itulah yang akan kita lakukan.

Salah satu jenis item teks yang sering ditemukan adalah tanggal; ini memberikan peluang besar untuk ekstensi XSLT baru. Tugas kita adalah memberi style pada elemen artikel sehingga tanggal dicetak dalam format berikut:

Jumat, 30 November 200

Can standard XSLT complete the date above? XSLT can finish most of the task. Determining the actual day is the difficult part. One way to quickly solve that problem is to use the java.text.SimpleDate format class within an extension function to return a string formatted as we wish. But wait: notice that the day appears in bold text. This returns us to the initial problem. The reason we are even considering an extension function is because the original XML document failed to structure the date as a group of nodes. If our extension function returns a string, we will still find it difficult to style the day field differently than the rest of the date string. Here's a more useful format, at least from the perspective of an XSLT designer:

  11 30 2001  

We now create an XSLT extension function, taking a string as an argument and returning an XML node in this format:

  November 30 Friday 2001  

The class hosting our extension function doesn't implement or extend anything; we will call the class DateFormatter:

public class DateFormatter { public static Node format (String date) {} 

Wow, too easy, huh? There are absolutely no requirements placed on the type or interface of a Xalan extension function. Generally, most extension functions will take a String as an argument and return another String. Other common patterns are to send or receive org.w3c.dom.NodeLists or individual Nodes from an extension function, as we will do. See the Xalan documentation for details on how Java types convert to XSLT types.

In the code fragment above, the format() method's logic breaks into two parts. First, we need to parse the date string from the original XML document. Then we use some DOM programming techniques to create a Node and return it to the XSLT processor. The body of our format() method implementation reads:

 Document doc = DocumentBuilderFactory.newInstance(). newDocumentBuilder().newDocument(); Element dateNode = doc.createElement("formatted-date"); SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT, locale); df.setLenient(true); Date d = df.parse(date); df.applyPattern("MMMM"); addChild(dateNode, "month", df.format(d)); df.applyPattern("EEEE"); addChild(dateNode, "day-of-week", df.format(d)); df.applyPattern("yyyy"); dateNode.setAttribute("year", df.format(d)); return dateNode; 

dateNode will contain our formatted date values that we return to the stylesheet. Notice that we've utilized java.text.SimpleDateFormat() to parse the date. This allows us to take full advantage of Java's date support, including its localization features. SimpleDateFormat handles the numeric date conversion and returns month and day names that match the locale of the VM running our application.

Remember: the primary purpose of an extension function is simply to allow us access to existing Java functionality; write as little code as possible. An extension function, like any Java method, can use other methods within the same class. To simplify the format() implementation, I moved repetitive code into a small utility method:

private void addChild (Node parent, String name, String text) { Element child = parent.getOwnerDocument().createElement(name); child.appendChild(parent.getOwnerDocument().createTextNode(text)); parent.appendChild(child); } 

Use DateFormatter within a stylesheet

Now that we have implemented an extension function, we can call it from within a stylesheet. Just as before, we need to declare a namespace for our extension function:


  

Kali ini, kami sepenuhnya memenuhi syarat jalur ke kelas yang menghosting fungsi ekstensi. Ini opsional dan bergantung pada apakah Anda akan menggunakan kelas lain dalam paket yang sama atau hanya satu objek ekstensi. Anda dapat mendeklarasikan full CLASSPATHsebagai namespace atau menggunakan paket dan menentukan kelas tempat fungsi ekstensi dipanggil. Dengan menentukan full CLASSPATH, kita mengetik lebih sedikit saat kita memanggil fungsi.

Untuk memanfaatkan fungsi tersebut, cukup panggil dari dalam selecttag, seperti: