XSLT mekar dengan Java

Adakah anda pernah tersekat dengan masalah transformasi XML yang sukar dan tidak dapat anda selesaikan dengan XSLT (Extensible Stylesheet Language Transformation) sahaja? Contohnya, ambil lembaran gaya penapis sederhana yang hanya memilih nod yang bertarikh lebih awal daripada lima hari yang lalu. Anda pernah mendengar bahawa XSLT dapat menyaring dokumen XML, jadi anda fikir anda akan menyelesaikan masalah ini dalam masa yang singkat. Tugas pertama adalah mendapatkan tarikh hari ini dari dalam helaian gaya, dengan syarat maklumat tersebut tidak termasuk dalam dokumen XML yang asal. Malangnya, anda tidak dapat menyelesaikan tugas ini hanya dengan XSLT. Dalam keadaan seperti ini, anda dapat mempermudah kod XSLT anda dan menyelesaikan masalah dengan lebih cepat dengan sambungan Java.

Banyak pemproses XSLT membenarkan beberapa jenis mekanisme peluasan; spesifikasi tersebut menghendaki mereka melakukannya. Di dunia Java dan XML, pemproses XSLT yang paling banyak digunakan adalah pemproses Apache Xalan sumber terbuka. Ditulis di Java, Xalan memungkinkan untuk membuat sambungan di Java. Banyak pembangun menganggap kepanjangan Xalan sangat kuat kerana memungkinkan mereka memanfaatkan kemahiran Java mereka dari dalam konteks gaya gaya. Pertimbangkan cara JSP (JavaServer Pages), skrip, dan tag khusus menambah kekuatan pada HTML. Sambungan Xalan menambah daya ke lembaran gaya dengan cara yang sama: dengan membiarkan pemaju Java mengakses alat kegemaran mereka, Java.

Dalam artikel ini, saya akan menunjukkan bagaimana anda dapat menggunakan Java dari dalam lembaran gaya XSLT. Pertama, kami akan menggunakan kepanjangan Xalan untuk membuat instansi dan menggunakan kelas yang ada dalam JDK. Kemudian, saya akan menunjukkan kepada anda cara menulis fungsi lanjutan XSLT yang mengambil Stringargumen dan mengembalikan fragmen DOM (Model Objek Dokumen) ke pemproses gaya.

XSLT penting bagi pengembang J2EE (Java 2 Platform, Enterprise Edition) kerana menggayakan dokumen XML telah menjadi operasi di sisi pelayan. Juga, JAXP (Java API for XML Processing), yang termasuk dukungan untuk mesin XSLT, telah menjadi bagian dari spesifikasi J2EE (J2EE 2.6.11). Pada peringkat awal, XSLT bertujuan untuk memberi gaya XML pada klien; namun, kebanyakan aplikasi menggayakan XML sebelum menghantarnya kepada pelanggan. Bagi pembangun J2EE, ini bermaksud pemproses XSLT kemungkinan besar akan berjalan di dalam pelayan aplikasi.

Sebelum anda meneruskan artikel ini, berhati-hatilah bahawa menggunakan sambungan Java dalam helaian gaya XSLT anda akan mengurangkan mudah dibawa. Walaupun sambungan adalah sebahagian daripada spesifikasi XSLT, cara pelaksanaannya tidak. Sekiranya helaian gaya anda akan berjalan pada pemproses selain Xalan, seperti mesin gaya gaya Internet Explorer, anda harus mengelakkan penggunaan sambungan dengan segala cara.

Kelemahan XSLT

Kerana XSLT mempunyai beberapa titik lemah, sambungan XSLT terbukti cukup berguna. Saya tidak mengatakan bahawa XSLT tidak baik; namun, ia tidak menawarkan alat terbaik untuk memproses semua dalam dokumen XML. Pertimbangkan bahagian XML ini:

 XSLT tidak semudah digunakan kerana ada yang menginginkan anda ...   

Andaikan bos anda meminta anda mengubah lembaran gaya sehingga menukar semua contoh "tidak" menjadi "tidak" dan melokalkan label biasa. Sudah tentu XSLT menyediakan mekanisme untuk melakukan sesuatu seperti ini, bukan? Keliru. XSLT tidak memberikan cara mudah untuk menggantikan terjadinya perkataan atau corak dalam rentetan. Perkara yang sama berlaku untuk penyetempatan. Itu tidak boleh dikatakan tidak boleh dilakukan dengan sintaks XSLT standard. Ada cara, tetapi mereka tidak semudah yang kita mahukan. Sekiranya anda benar-benar mahu menulis fungsi manipulasi teks menggunakan templat rekursif, jadilah tetamu saya.

Kelemahan utama XSLT adalah pemprosesan teks, yang nampaknya masuk akal kerana tujuannya adalah membuat XML. Namun, kerana kandungan XML sepenuhnya teks, XSLT memerlukan pengendalian teks yang lebih kuat. Tidak perlu dikatakan, pereka bentuk gaya memerlukan kepanjangan dari semasa ke semasa. Dengan Xalan, Java memberikan kepanjangan ini.

Gunakan kelas JDK dalam XSLT

Anda mungkin gembira mengetahui bahawa anda tidak perlu menulis kod Java apa pun untuk memanfaatkan kepanjangan Xalan. Apabila anda menggunakan Xalan, anda boleh membuat dan menggunakan kaedah pada hampir semua objek Java. Sebelum menggunakan kelas Java, anda mesti memberikan ruang nama XSLT untuknya. Contoh ini menyatakan "java"sebagai ruang nama untuk semua perkara di dalam atau di bawah pakej Java (iaitu, keseluruhan JDK):


  

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

 Java Mungkin Menjadi Fad J. Burke 11/30/97  

Anda telah diminta untuk menggayakan XML ini sehingga judulnya muncul dengan huruf besar. Pembangun yang baru menggunakan XSLT hanya akan membuka rujukan XSLT untuk mencari toUpper()fungsinya; namun, dia kecewa apabila mendapati bahawa rujukannya tidak ada. The translate()kaedah adalah pertaruhan terbaik anda, tetapi saya mempunyai kaedah yang lebih baik: java.lang.String.toUpperCase(). Untuk menggunakan kaedah ini, anda perlu membuat Stringobjek dengan isi tajuk. Inilah cara anda dapat membuat Stringcontoh baru dengan kandungan elemen tajuk:


  

The nameatribut menentukan pemegang untuk baru anda Stringmisalnya. Anda memanggil pembina dengan terlebih dahulu menentukan ruang nama bersama dengan jalan yang tersisa ke Stringkelas. Seperti yang anda perhatikan, Stringkekurangan new()kaedah. Anda gunakan new()untuk membina objek Java di Xalan; ia sesuai dengan newkata kunci Java . Argumen yang diberikan untuk new()menentukan versi konstruktor yang akan dipanggil. Setelah anda mempunyai isi judul dalam Stringobjek Java , anda dapat menggunakan toUpperCase()metode tersebut, seperti:


  

Ini mungkin kelihatan aneh bagi anda pada mulanya. Semasa menggunakan kaedah Java pada contoh tertentu, argumen pertama adalah contoh yang anda inginkan. Jelas Xalan menggunakan introspeksi untuk memberikan kemampuan ini.

Di bawah ini anda akan menemui satu lagi muslihat. Inilah cara anda memancarkan tarikh dan masa di mana sahaja dalam helaian gaya anda menggunakan java.lang.Date:


  

Inilah sesuatu yang akan menjadikan hari orang yang dikehendaki untuk melokalkan lembaran gaya umum antara dua atau lebih bahasa. Anda dapat menggunakan java.util.ResourceBundleuntuk melokalkan teks literal dalam lembar gaya. Oleh kerana XML anda mempunyai label pengarang, anda mungkin ingin mencetak di "Author:"sebelah nama orang tersebut.

Salah satu pilihan adalah membuat lembaran gaya yang terpisah untuk setiap tempat, iaitu satu untuk bahasa Inggeris, yang lain untuk bahasa Cina, dan sebagainya. Masalah yang wujud dalam pendekatan ini harus jelas. Menjaga pelbagai versi helaian gaya tetap konsisten. Anda juga perlu mengubah suai aplikasi anda sehingga memilih lembaran gaya yang betul berdasarkan lokasi pengguna.

Daripada menggandakan lembaran gaya untuk setiap bahasa, anda dapat memanfaatkan fitur penyetempatan Java. Melokalisasi dengan bantuan ResourceBundlemembuktikan pendekatan yang lebih baik. Dalam XSLT, muatkan ResourceBundlepada awal helaian gaya anda, seperti:


  

The ResourceBundlekelas menjangkakan untuk mencari fail yang dipanggil General.propertiesdalam anda CLASSPATH. Setelah kumpulan dibuat, ia dapat digunakan kembali di seluruh helaian gaya. Contoh ini mendapatkan authorsumber:


  

Perhatikan lagi tandatangan kaedah yang pelik. Biasanya, ResourceBundle.getString()hanya mengambil satu hujah; namun, dalam XSLT anda juga perlu menentukan objek yang anda ingin gunakan kaedahnya.

Tulis peluasan anda sendiri

Untuk beberapa situasi yang jarang berlaku, anda mungkin perlu menulis peluasan XSLT anda sendiri, dalam bentuk fungsi peluasan atau elemen peluasan. Saya akan membincangkan tentang mewujudkan fungsi lanjutan, konsep yang cukup mudah difahami. Apa-apa fungsi peluasan Xalan dapat mengambil rentetan sebagai rentetan input dan kembali ke pemproses XSLT. Sambungan anda juga boleh menggunakan NodeLists atau Nodeargumen dan mengembalikan jenis ini ke pemproses XSLT. Menggunakan Nodes atau NodeLists bermaksud anda dapat menambahkan ke dokumen XML asli dengan fungsi ekstensi, itulah yang akan kami lakukan.

Satu jenis item teks yang sering dihadapi adalah tarikh; ia memberikan peluang yang baik untuk peluasan XSLT baru. Tugas kami adalah untuk menggayakan elemen artikel sehingga tarikh dicetak dalam format berikut:

Jumaat, 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 memenuhi syarat sepenuhnya ke kelas yang menjadi tuan rumah fungsi peluasan. Ini adalah pilihan dan bergantung pada sama ada anda akan menggunakan kelas lain dalam pakej yang sama atau hanya satu objek lanjutan. Anda boleh menyatakan penuh CLASSPATHsebagai ruang nama atau menggunakan pakej dan menentukan kelas di mana fungsi pelanjutan dipanggil. Dengan menentukan yang lengkap CLASSPATH, kita menaip lebih sedikit ketika kita memanggil fungsi.

Untuk menggunakan fungsi, cukup memanggilnya dari dalam selecttag, seperti: