Pemrograman XML di Java, Bagian 1

Jadi, Anda memahami (kurang lebih) bagaimana Anda akan merepresentasikan data Anda dalam XML, dan Anda tertarik menggunakan XML untuk memecahkan banyak masalah manajemen data Anda. Namun Anda tidak yakin bagaimana menggunakan XML dengan program Java Anda.

TEXTBOX: TEXTBOX_HEAD: Pemrograman XML di Java: Baca keseluruhan seri!

  • Bagian 1. Gunakan Simple API for XML (SAX) untuk memproses XML di Java dengan mudah
  • Bagian 2. Pelajari tentang SAX dan validasi XML melalui contoh ilustrasi
  • Bagian 3. DOMinasi: Kendalikan dokumen terstruktur dengan Model Objek Dokumen

: END_TEXTBOX

Artikel ini adalah tindak lanjut dari artikel pengantar saya, "XML untuk pemula absolut", di JavaWorld edisi April 1999 (lihat bagian Sumberdaya di bawah untuk URL). Artikel itu menjelaskan XML; Sekarang saya akan membangun deskripsi itu dan menunjukkan secara detail cara membuat aplikasi yang menggunakan Simple API for Java (SAX), Java API standar yang ringan dan kuat untuk memproses XML.

Kode contoh yang digunakan di sini menggunakan SAX API untuk membaca file XML dan membuat struktur objek yang berguna. Pada saat Anda menyelesaikan artikel ini, Anda akan siap untuk membuat aplikasi berbasis XML Anda sendiri.

Keutamaan kemalasan

Larry Wall, pencipta Perl yang jenius dan gila (bahasa pemrograman terbesar kedua yang ada), telah menyatakan bahwa kemalasan adalah salah satu dari "tiga kebajikan besar" dari seorang programmer (dua lainnya adalah ketidaksabaran dan keangkuhan). Kemalasan adalah suatu kebajikan karena programmer yang malas akan melakukan apa saja untuk menghindari pekerjaan, bahkan sampai membuat kerangka kerja pemrograman umum yang dapat digunakan kembali yang dapat digunakan berulang kali. Membuat kerangka kerja semacam itu memerlukan banyak pekerjaan, tetapi waktu yang dihemat untuk tugas di masa depan lebih dari sekadar upaya awal yang diinvestasikan. Kerangka kerja terbaik memungkinkan pemrogram melakukan hal-hal menakjubkan dengan sedikit atau tanpa kerja sama sekali - dan itulah mengapa kemalasan itu bajik.

XML adalah teknologi yang memungkinkan untuk programmer yang berbudi luhur (malas). Pengurai XML dasar melakukan banyak pekerjaan untuk programmer, mengenali token, menerjemahkan karakter yang dikodekan, menegakkan aturan pada struktur file XML, memeriksa validitas beberapa nilai data, dan membuat panggilan ke kode khusus aplikasi, jika sesuai. Faktanya, standardisasi awal, dikombinasikan dengan pasar yang sangat kompetitif, telah menghasilkan sejumlah implementasi yang tersedia secara gratis dari parser XML standar dalam banyak bahasa, termasuk C, C ++, Tcl, Perl, Python, dan, tentu saja, Java.

SAX API adalah salah satu antarmuka paling sederhana dan paling ringan untuk menangani XML. Dalam artikel ini, saya akan menggunakan implementasi XML4J IBM dari SAX, tetapi karena API terstandarisasi, aplikasi Anda dapat menggantikan paket apa pun yang mengimplementasikan SAX.

SAX adalah API berbasis peristiwa, yang beroperasi dengan prinsip panggilan balik. Seorang programmer aplikasi biasanya akan membuat Parserobjek SAX , dan meneruskannya baik XML masukan dan penangan dokumen, yang menerima callback untuk peristiwa SAX. SAX Parsermengubah masukannya menjadi aliran peristiwa yang sesuai dengan fitur struktural masukan, seperti tag XML atau blok teks. Saat setiap peristiwa terjadi, itu diteruskan ke metode yang sesuai dari penangan dokumen yang ditentukan programmer, yang mengimplementasikan antarmuka callback org.xml.sax.DocumentHandler. Metode di kelas penangan ini menjalankan fungsionalitas khusus aplikasi selama penguraian.

Misalnya, bayangkan parser SAX menerima dokumen yang berisi dokumen XML kecil yang ditunjukkan pada Listing 1 di bawah ini. (Lihat Sumberdaya untuk file XML.)

 Ogden Nash Fleas Adam Punya.  

Daftar 1. XML mewakili puisi pendek

Saat parser SAX menemukan tag, ia memanggil yang ditentukan pengguna DocumentHandler.startElement()dengan string POEMsebagai argumen. Anda menerapkan startElement()metode untuk melakukan apa pun yang seharusnya dilakukan aplikasi saat a POEMdimulai. Aliran peristiwa dan panggilan yang dihasilkan untuk bagian XML di atas muncul pada Tabel 1 di bawah.

Tabel 1. Urutan callback yang dihasilkan SAX saat mengurai Kode 1
Item ditemukan Callback pengurai
{Awal dokumen} startDocument()
startElement("POEM", {AttributeList})
"\ n" characters("\n...", 6, 1)
startElement("AUTHOR", {AttributeList})
"Ogden Nash" characters("\n...", 15, 10)
endElement("AUTHOR")
"\ n" characters("\n...", 34, 1)
startElement("TITLE", {AttributeList})
"Kutu" characters("\n...", 42, 5)
endElement("TITLE")
"\ n" characters("\n...", 55, 1)
startElement("LINE", {AttributeList})
"Adam" characters("\n...", 62, 4)
endElement("LINE")
startElement("LINE", {AttributeList})
"Sudah." characters("\n...", 67, 8)
endElement("LINE")
"\ n" characters("\n...", 82, 1)
endElement("POEM")
{Akhir dokumen} endDocument()

Anda membuat kelas yang mengimplementasikan DocumentHandleruntuk menanggapi peristiwa yang terjadi di parser SAX. Ini kejadian tidak acara Java karena Anda mungkin mengenal mereka dari Abstract Windowing Toolkit (AWT). Ini adalah kondisi yang dideteksi parser SAX saat diurai, seperti awal dokumen atau terjadinya tag penutup di aliran input. Saat setiap kondisi (atau peristiwa) ini terjadi, SAX memanggil metode yang sesuai dengan kondisi di dalamnya DocumentHandler.

Jadi, kunci untuk menulis program yang memproses XML dengan SAX adalah untuk mengetahui apa yang DocumentHandlerharus dilakukan dalam menanggapi aliran callback metode dari SAX. Pengurai SAX menangani semua mekanisme untuk mengidentifikasi tag, mengganti nilai entitas, dan seterusnya, sehingga Anda bebas berkonsentrasi pada fungsionalitas khusus aplikasi yang menggunakan data yang dikodekan dalam XML.

Tabel 1 hanya menunjukkan peristiwa yang terkait dengan elemen dan karakter. SAX juga menyertakan fasilitas untuk menangani fitur struktural lain dari file XML, seperti entitas dan instruksi pemrosesan, tetapi ini berada di luar cakupan artikel ini.

Pembaca yang cerdik akan melihat bahwa dokumen XML dapat direpresentasikan sebagai pohon objek yang diketik, dan bahwa urutan aliran peristiwa yang disajikan DocumentHandlersesuai dengan traversal dalam urutan, kedalaman pertama dari pohon dokumen. (Tidaklah penting untuk memahami poin ini, tetapi konsep dokumen XML sebagai struktur data pohon berguna dalam jenis pemrosesan dokumen yang lebih canggih, yang akan dibahas di artikel selanjutnya dalam seri ini.)

Kunci untuk memahami cara menggunakan SAX adalah memahami DocumentHandlerantarmuka, yang akan saya bahas selanjutnya.

Sesuaikan parser dengan org.xml.sax.DocumentHandler

Karena DocumentHandlerantarmuka sangat penting untuk memproses XML dengan SAX, ada baiknya untuk memahami apa yang dilakukan metode dalam antarmuka. Saya akan membahas metode penting di bagian ini, dan melewatkan metode yang berhubungan dengan topik yang lebih maju. Ingat, DocumentHandlerini adalah antarmuka, jadi metode yang saya jelaskan adalah metode yang akan Anda terapkan untuk menangani fungsionalitas khusus aplikasi setiap kali peristiwa terkait terjadi.

Inisialisasi dan pembersihan dokumen

Untuk setiap dokumen yang diurai, parser XML SAX memanggil DocumentHandlermetode antarmuka startDocument()(dipanggil sebelum pemrosesan dimulai) dan endDocument()(dipanggil setelah pemrosesan selesai). Anda dapat menggunakan metode ini untuk menginisialisasi Anda DocumentHandlerguna mempersiapkannya untuk menerima peristiwa dan untuk membersihkan atau menghasilkan keluaran setelah penguraian selesai. endDocument()sangat menarik, karena ini hanya dipanggil jika dokumen masukan telah berhasil diurai. Jika Parsermenghasilkan kesalahan fatal, itu hanya membatalkan aliran acara dan berhenti parsing, dan endDocument()tidak pernah dipanggil.

Memproses tag

Parser SAX memanggil startElement()setiap kali menemukan tag terbuka, dan endElement()setiap kali menemukan tag dekat. Metode ini sering kali berisi kode yang melakukan sebagian besar pekerjaan saat mengurai file XML. startElement()Argumen pertama adalah string, yang merupakan nama tag dari elemen yang ditemukan. Argumen kedua adalah objek bertipe AttributeList, antarmuka yang ditentukan dalam paket org.xml.saxyang menyediakan akses berurutan atau acak ke atribut elemen berdasarkan nama. (Anda pasti pernah melihat atribut sebelumnya dalam HTML; di baris

BORDER

Since SAX doesn't provide any information about the context of the elements it encounters (that appears inside in Listing 1 above, for example), it is up to you to supply that information. Application programmers often use stacks in startElement() and endElement(), pushing objects onto a stack when an element starts, and popping them off of the stack when the element ends.

Process blocks of text

The characters() method indicates character content in the XML document -- characters that don't appear inside an XML tag, in other words. This method's signature is a bit odd. The first argument is an array of bytes, the second is an index into that array indicating the first character of the range to be processed, and the third argument is the length of the character range.

It might seem that an easier API would have simply passed a String object containing the data, but characters() was defined in this way for efficiency reasons. The parser has no way of knowing whether or not you're going to use the characters, so as the parser parses its input buffer, it passes a reference to the buffer and the indices of the string it is viewing, trusting that you will construct your own String if you want one. It's a bit more work, but it lets you decide whether or not to incur the overhead of String construction for content pieces in an XML file.

The characters() method handles both regular text content and content inside CDATA sections, which are used to prevent blocks of literal text from being parsed by an XML parser.

Other methods

Ada tiga metode lain dalam DocumentHandlerantarmuka: ignorableWhitespace(), processingInstruction(), dan setDocumentLocator(). ignorableWhitespace()melaporkan kemunculan spasi, dan biasanya tidak digunakan dalam parser SAX yang tidak memvalidasi (seperti yang kami gunakan untuk artikel ini); processingInstruction()menangani banyak hal di dalamnya and ?> delimiters; and setDocumentLocator() is optionally implemented by SAX parsers to give you access to the locations of SAX events in the original input stream. You can read up on these methods by following the links on the SAX interfaces in Resources.

Implementing all of the methods in an interface can be tedious if you're only interested in the behavior of one or two of them. The SAX package includes a class called HandlerBase that basically does nothing, but can help you take advantage of just one or two of these methods. Let's examine this class in more detail.

HandlerBase: A do-nothing class

Often, you're only interested in implementing one or two methods in an interface, and want the other methods to simply do nothing. The class org.xml.sax.HandlerBase simplifies the implementation of the DocumentHandler interface by implementing all of the interface's methods with do-nothing bodies. Then, instead of implementing DocumentHandler, you can subclass HandlerBase, and only override the methods that interest you.

For example, say you wanted to write a program that just printed the title of any XML-formatted poem (like TitleFinder in Listing 1). You could define a new DocumentHandler, like the one in Listing 2 below, that subclasses HandlerBase, and only overrides the methods you need. (See Resources for an HTML file of TitleFinder.)

012 /** 013 * SAX DocumentHandler class that prints the contents of "TITLE" element 014 * of an input document. 015 */ 016 public class TitleFinder extends HandlerBase { 017 boolean _isTitle = false; 018 public TitleFinder() { 019 super(); 020 } 021 /** 022 * Print any text found inside a  element. 023 */ 024 public void characters(char[] chars, int iStart, int iLen) { 025 if (_isTitle) { 026 String sTitle = new String(chars, iStart, iLen); 027 System.out.println("Title: " + sTitle); 028 } 029 } 030 /** 031 * Mark title element end. 032 */ 033 public void endElement(String element) { 034 if (element.equals("TITLE")) { 035 _isTitle = false; 036 } 037 } 038 /** 039 * Find contents of titles 040 */ 041 public static void main(String args[]) { 042 TitleFinder titleFinder = new TitleFinder(); 043 try { 044 Parser parser = ParserFactory.makeParser("com.ibm.xml.parsers.SAXParser"); 045 parser.setDocumentHandler(titleFinder); 046 parser.parse(new InputSource(args[0])); 047 } catch (Exception ex) { 048 ; // OK, so sometimes laziness *isn't* a virtue. 049 } 050 } 051 /** 052 * Mark title element start 053 */ 054 public void startElement(String element, AttributeList attrlist) { 055 if (element.equals("TITLE")) { 056 _isTitle = true; 057 } 058 } 

Listing 2. TitleFinder: A DocumentHandler derived from HandlerBase that prints TITLEs


#####


, adalah atribut yang nilainya "1"). Karena Listing 1 tidak menyertakan atribut, mereka tidak muncul di Tabel 1. Anda akan melihat contoh atribut dalam aplikasi contoh nanti di artikel ini.