Pertama-tama saya harus mengakui bahwa saya menyukai standar komputer. Jika semua orang mengikuti standar industri ini, Internet akan menjadi media yang lebih baik. Penggunaan format pertukaran data standar membuat model komputasi terbuka dan platform-independen menjadi layak dilakukan. Itu sebabnya saya penggemar XML.
Untungnya, bahasa skrip favorit saya tidak hanya mendukung XML tetapi semakin mendukungnya. PHP memungkinkan saya mempublikasikan dokumen XML dengan cepat ke Internet, mengumpulkan informasi statistik tentang dokumen XML, dan mengonversi dokumen XML ke format lain. Misalnya, saya sering menggunakan kemampuan pemrosesan XML PHP untuk mengelola artikel dan buku yang saya tulis dalam XML.
Pada artikel ini, saya akan membahas segala penggunaan parser Expat bawaan PHP untuk memproses dokumen XML. Melalui contoh, saya akan mendemonstrasikan metode pemrosesan Expat. Pada saat yang sama, contoh ini dapat menunjukkan kepada Anda cara:
Membuat fungsi pemrosesan Anda sendiri
Mengubah dokumen XML menjadi struktur data PHP Anda sendiri
Pendahuluan
Parser Expat XML, juga disebut prosesor XML, memungkinkan program mengakses struktur dan konten dokumen XML. Expat adalah parser XML untuk bahasa skrip PHP. Itu juga digunakan di proyek lain, seperti Mozilla, Apache dan Perl.
Apa itu parser berbasis peristiwa?
Ada dua tipe dasar parser XML:
Parser berbasis pohon: mengubah dokumen XML menjadi struktur pohon. Jenis parser ini mengurai seluruh artikel sambil menyediakan API untuk mengakses setiap elemen pohon yang dihasilkan. Standar umumnya adalah DOM (Document Object Model).
Parser berbasis peristiwa: Perlakukan dokumen XML sebagai rangkaian peristiwa. Ketika peristiwa khusus terjadi, parser akan memanggil fungsi yang disediakan pengembang untuk menanganinya.
Parser berbasis peristiwa memiliki tampilan dokumen XML yang berfokus pada data, yang berarti parser berfokus pada bagian data dokumen XML, bukan strukturnya. Parser ini memproses dokumen dari awal hingga akhir dan melaporkan peristiwa seperti - awal elemen, akhir elemen, awal data fitur, dll. - ke aplikasi melalui fungsi panggilan balik. Berikut ini adalah contoh dokumen XML untuk "Halo-Dunia":
<salam>
Halo Dunia
</greeting>
Parser berbasis peristiwa akan melaporkan sebagai tiga peristiwa:
elemen awal: salam
Awal dari item CDATA, nilainya adalah: Hello World
Elemen penutup: salam
Berbeda dengan parser berbasis pohon, parser berbasis peristiwa tidak menghasilkan struktur yang mendeskripsikan dokumen. Dalam item CDATA, parser berbasis peristiwa tidak akan membiarkan Anda mendapatkan informasi salam dari elemen induk.
Namun, ini memberikan akses tingkat yang lebih rendah, yang memungkinkan pemanfaatan sumber daya yang lebih baik dan akses yang lebih cepat. Dengan cara ini, tidak perlu memasukkan seluruh dokumen ke dalam memori; bahkan, keseluruhan dokumen bahkan bisa lebih besar dari nilai memori sebenarnya.
Expat adalah parser berbasis acara. Tentu saja, jika Anda menggunakan Expat, itu juga dapat menghasilkan struktur pohon asli yang lengkap di PHP jika diperlukan.
Contoh Hello-World di atas menyertakan format XML lengkap. Namun ini tidak valid karena tidak ada DTD (Document Type Definition) yang terkait dengannya maupun DTD yang tertanam.
Bagi Expat, hal ini tidak ada bedanya: Expat adalah parser yang tidak memeriksa validitas dan oleh karena itu mengabaikan DTD apa pun yang terkait dengan dokumen tersebut. Namun perlu dicatat bahwa dokumen tersebut masih perlu diformat sepenuhnya, jika tidak, Expat (seperti parser yang mendukung XML lainnya) akan berhenti dengan pesan kesalahan.
Sebagai parser yang tidak memeriksa validitas, kecepatan dan ringan Exapt membuatnya cocok untuk aplikasi Internet.
Kompilasi Expat
Expat dapat dikompilasi ke dalam versi PHP3.0.6 (atau lebih tinggi). Mulai dari Apache 1.3.9, Expat telah dimasukkan sebagai bagian dari Apache. Pada sistem Unix, Anda dapat mengkompilasinya ke dalam PHP dengan mengkonfigurasi PHP dengan opsi -with-xml.
Jika Anda mengkompilasi PHP sebagai modul Apache, Expat akan disertakan sebagai bagian dari Apache secara default. Di Windows, Anda harus memuat pustaka tautan dinamis XML.
Contoh XML: XMLstats
Salah satu cara untuk mempelajari fungsi Expat adalah melalui contoh. Contoh yang akan kita bahas adalah menggunakan Expat untuk mengumpulkan statistik dokumen XML.
Untuk setiap elemen dalam dokumen, informasi berikut akan dihasilkan:
berapa kali elemen tersebut digunakan dalam dokumen
Jumlah data karakter dalam elemen ini
elemen induk elemen
elemen anak dari elemen
Catatan: Demi demonstrasi, kami menggunakan PHP untuk menghasilkan struktur untuk menyimpan elemen induk dan elemen anak dari elemen tersebut.
yang disiapkan
untuk menghasilkan instance parser XML adalah xml_parser_create(). Contoh ini akan digunakan untuk semua fungsi masa depan. Ide ini sangat mirip dengan tag koneksi fungsi MySQL di PHP. Sebelum mengurai dokumen, parser berbasis peristiwa biasanya mengharuskan Anda mendaftarkan fungsi panggilan balik - untuk dipanggil ketika peristiwa tertentu terjadi. Ekspatriat tidak memiliki peristiwa pengecualian. Ini mendefinisikan tujuh kemungkinan peristiwa berikut:
objek XML parsing fungsi deskripsi
elemen xml_set_element_handler()
data karakter awal dan akhir elemen xml_set_character_data_handler() awal data karakter
entitas eksternal xml_set_external_entity_ref_handler() entitas eksternal
Entitas eksternal yang belum diurai xml_set_unparsed_entity_decl_handler ( ) Terjadinya
instruksi pemrosesan entitas eksternal yang belum terselesaikan xml_set_processing_instruction_handler() Terjadinya
deklarasi notasi instruksi pemrosesan xml_set_notation_decl_handler() Terjadinya deklarasi notasi
default xml_set_default_handler() Peristiwa lain tanpa fungsi handler yang ditentukan
Semua fungsi callback harus menggunakan instance dari parser sebagai parameter pertamanya (ada parameter lain selain itu).
Untuk contoh script di akhir artikel ini. Yang perlu Anda perhatikan adalah ia menggunakan fungsi pemrosesan elemen dan fungsi pemrosesan data karakter. Fungsi pengendali panggilan balik elemen didaftarkan melalui xml_set_element_handler().
Fungsi ini mengambil tiga parameter:
sebuah instance dari parser
Nama fungsi panggilan balik yang menangani elemen awal
Nama fungsi panggilan balik yang menangani elemen penutup
Fungsi panggilan balik harus ada saat penguraian dokumen XML dimulai. Mereka harus didefinisikan sesuai dengan prototipe yang dijelaskan dalam manual PHP.
Misalnya, Expat meneruskan tiga argumen ke fungsi handler untuk elemen awal. Dalam contoh skrip, didefinisikan sebagai berikut:
function start_element($parser, $name, $attrs)
Parameter pertama adalah pengidentifikasi parser, parameter kedua adalah nama elemen awal, dan parameter ketiga berisi semua atribut dan nilai array elemen.
Setelah Anda mulai menguraikan dokumen XML, Expat akan memanggil fungsi start_element() Anda dan meneruskan parameter setiap kali ia menemukan elemen awal.
Opsi Pelipatan Kasus XML
menggunakan fungsi xml_parser_set_option () untuk mematikan opsi Pelipatan Kasus. Opsi ini aktif secara default, menyebabkan nama elemen yang diteruskan ke fungsi handler secara otomatis dikonversi ke huruf besar. Namun XML peka terhadap huruf besar-kecil (jadi huruf besar-kecil sangat penting untuk dokumen XML statistik). Sebagai contoh kita, opsi pelipatan casing harus dimatikan.
Mengurai dokumen
Setelah menyelesaikan semua persiapan, sekarang skrip akhirnya dapat mengurai dokumen XML:
Xml_parse_from_file(), fungsi khusus, membuka file yang ditentukan dalam parameter dan menguraikannya dalam ukuran 4kb
xml_parse(), seperti xml_parse_from_file(), akan mengembalikan false ketika terjadi kesalahan, yaitu ketika dokumen XML tidak diformat sepenuhnya.
Anda dapat menggunakan fungsi xml_get_error_code() untuk mendapatkan kode numerik dari kesalahan terakhir. Berikan kode numerik ini ke fungsi xml_error_string() untuk mendapatkan informasi teks kesalahan.
Menghasilkan nomor baris XML saat ini, membuat proses debug menjadi lebih mudah.
Selama proses parsing, fungsi panggilan balik dipanggil.
Mendeskripsikan struktur dokumen
Saat menguraikan dokumen, pertanyaan yang perlu dijawab dengan Expat adalah: bagaimana mempertahankan deskripsi dasar struktur dokumen?
Seperti disebutkan sebelumnya, parser berbasis peristiwa itu sendiri tidak menghasilkan informasi struktural apa pun.
Namun, struktur tag merupakan fitur penting XML. Misalnya, urutan elemen <book><title> mempunyai arti yang berbeda dengan <figure><title>. Meskipun demikian, penulis mana pun akan memberi tahu Anda bahwa judul buku dan judul gambar tidak ada hubungannya satu sama lain, meskipun keduanya menggunakan istilah "judul". Oleh karena itu, untuk memproses XML secara efisien dengan parser berbasis peristiwa, Anda harus menggunakan tumpukan atau daftar Anda sendiri untuk memelihara informasi struktural tentang dokumen.
Untuk mencerminkan struktur dokumen, skrip perlu mengetahui setidaknya elemen induk dari elemen saat ini. Hal ini tidak mungkin dilakukan dengan API Exapt. Ini hanya melaporkan peristiwa elemen saat ini tanpa informasi kontekstual apa pun. Oleh karena itu, Anda perlu membangun struktur tumpukan Anda sendiri.
Contoh skrip menggunakan struktur tumpukan first-in-last-out (FILO). Melalui array, tumpukan akan menyimpan semua elemen awal. Untuk fungsi pemrosesan elemen awal, elemen saat ini akan didorong ke puncak tumpukan oleh fungsi array_push(). Sejalan dengan itu, fungsi pemrosesan elemen akhir menghapus elemen teratas melalui array_pop().
Untuk urutan <book><title></title></book>, tumpukan diisi sebagai berikut:
elemen awal buku: tetapkan "buku" ke elemen pertama tumpukan ($tumpukan[0]).
Judul elemen awal: Tetapkan "judul" ke bagian atas tumpukan ($tumpukan[1]).
Judul elemen akhir: Hapus elemen teratas dari tumpukan ($stack[1]).
Judul elemen akhir: Hapus elemen teratas dari tumpukan ($stack[0]).
PHP3.0 mengimplementasikan contoh ini dengan mengontrol susunan elemen secara manual melalui variabel $ depth. Hal ini membuat skrip terlihat lebih kompleks. PHP4.0 menggunakan fungsi array_pop() dan array_push() untuk membuat skrip terlihat lebih ringkas.
Mengumpulkan data
Untuk mengumpulkan informasi tentang setiap elemen, skrip perlu mengingat peristiwa untuk setiap elemen. Simpan semua elemen berbeda dalam dokumen dengan menggunakan variabel array global $elements. Item dalam array adalah turunan dari kelas elemen dan memiliki 4 properti (variabel kelas)
$count - berapa kali elemen ditemukan dalam dokumen
$chars - Jumlah byte peristiwa karakter dalam elemen
$parents - elemen induk
$childs - elemen anak
Seperti yang Anda lihat, menyimpan instance kelas dalam array adalah hal yang mudah.
Catatan: Salah satu fitur PHP adalah Anda dapat melintasi seluruh struktur kelas melalui perulangan while(list() = every()) , sama seperti Anda melintasi seluruh array yang terkait. Semua variabel kelas (dan nama metode saat Anda menggunakan PHP3.0) dikeluarkan sebagai string.
Ketika sebuah elemen ditemukan, kita perlu menambah penghitung yang sesuai untuk melacak berapa kali elemen tersebut muncul dalam dokumen. Elemen count pada item $elements yang bersangkutan juga bertambah satu.
Kita juga perlu memberi tahu elemen induk bahwa elemen saat ini adalah elemen turunannya. Oleh karena itu, nama elemen saat ini akan ditambahkan ke item dalam array $childs elemen induk. Terakhir, elemen saat ini harus mengingat siapa induknya. Oleh karena itu, elemen induk ditambahkan ke item dalam array $parents dari elemen saat ini.
Menampilkan statistik
Kode yang tersisa mengulang array $elements dan subarraynya untuk menampilkan statistiknya. Ini adalah perulangan bersarang yang paling sederhana. Meskipun menghasilkan hasil yang benar, kode ini tidak ringkas dan tidak memiliki keahlian khusus. Ini hanyalah perulangan yang dapat Anda gunakan setiap hari untuk menyelesaikan pekerjaan Anda.
Contoh skrip dirancang untuk dipanggil dari baris perintah melalui pendekatan CGI PHP. Oleh karena itu, format keluaran hasil statistik adalah format teks. Jika Anda ingin menggunakan skrip di Internet, maka Anda perlu memodifikasi fungsi keluaran untuk menghasilkan format HTML.
Ringkasan
Exapt adalah parser XML untuk PHP. Sebagai parser berbasis peristiwa, ini tidak menghasilkan deskripsi struktural dokumen. Namun dengan menyediakan akses tingkat rendah, hal ini memungkinkan pemanfaatan sumber daya yang lebih baik dan akses yang lebih cepat.
Sebagai parser yang tidak memeriksa validitas, Expat mengabaikan DTD yang dilampirkan pada dokumen XML, namun akan berhenti dengan pesan kesalahan jika format dokumen tidak baik.
Menyediakan event handler untuk memproses dokumen
Bangun struktur acara Anda sendiri seperti tumpukan dan pohon untuk memanfaatkan markup informasi terstruktur XML.
Program XML baru muncul setiap hari, dan dukungan PHP untuk XML terus diperkuat (misalnya, dukungan untuk parser XML berbasis DOM, LibXML telah ditambahkan).
Dengan PHP dan Expat, Anda dapat bersiap menghadapi standar mendatang yang valid, terbuka, dan tidak bergantung pada platform.
Contoh
<?
/****************************************************** ***** *******************************
* Nama: Contoh parsing XML: Statistik informasi dokumen XML
* menggambarkan
* Contoh ini menggunakan parser Expat PHP untuk mengumpulkan dan menghitung informasi dokumen XML (misalnya: jumlah kemunculan setiap elemen, elemen induk, dan elemen turunan
* File XML sebagai parameter./xmlstats_PHP4.php3 test.xml
* $Membutuhkan: Persyaratan Ekspatriat: Ekspatriat PHP4.0 dikompilasi ke dalam mode CGI
******************************************************* * ***************************/
// Parameter pertama adalah file XML
$file = $argv[1];
// Inisialisasi variabel
$elemen = $tumpukan = array();
$total_elements = $total_chars = 0;
//Kelas elemen dasar
elemen kelas
{
var $hitungan = 0;
var $karakter = 0;
var $orang tua = array();
var $anak = array();
}
// Berfungsi untuk mengurai file XML
fungsi xml_parse_from_file($parser, $file)
{
if(!file_exists($file))
{
die("Tidak dapat menemukan file "$file".");
}
if(!($fp = @fopen($file, "r")))
{
die("Tidak dapat membuka file "$file".");
}
while($data = ketakutan($fp, 4096))
{
if(!xml_parse($parser, $data, feof($fp)))
{
kembali (salah);
}
}
fclose($fp);
kembali(benar);
}
// Fungsi hasil keluaran (bentuk kotak)
fungsi print_box($judul, $nilai)
{
printf("n+%'-60s+n", "");
printf("|%20s", "$judul:");
printf("%14s", $nilai);
printf("%26s|n", "");
printf("+%'-60s+n", "");
}
// Fungsi hasil keluaran (bentuk garis)
fungsi print_line($judul, $nilai)
{
printf("%20s", "$judul:");
printf("%15sn", $nilai);
}
// Fungsi penyortiran
fungsi my_sort($a, $b)
{
return(is_object($a) && is_object($b) ? $b->hitungan - $a->hitungan: 0);
}
fungsi start_element($parser, $nama, $attrs)
{
global $elements, $stack;
// Apakah elemen sudah ada di array $elements global?
if(!isset($elemen[$nama]))
{
// Tidak - tambahkan instance kelas dari suatu elemen
$elemen = elemen baru;
$elemen[$nama] = $elemen;
}
// Menambah penghitung elemen ini sebanyak satu
$elements[$name]->count++;
// Apakah ada elemen induk?
if(isset($tumpukan[hitung($tumpukan)-1]))
{
// Ya - tetapkan elemen induk ke $last_element
$last_element = $stack[count($stack)-1];
// Jika array elemen induk dari elemen saat ini kosong, inisialisasi ke 0
if(!isset($elements[$name]->parents[$last_element]))
{
$elemen[$nama]->orang tua[$elemen_terakhir] = 0;
}
// Menambah penghitung elemen induk elemen ini sebanyak satu
$elements[$name]->parents[$last_element]++;
// Jika array elemen anak dari elemen induk elemen saat ini kosong, maka akan diinisialisasi ke 0
if(!isset($elements[$last_element]-> anak[$ nama]))
{
$elemen[$last_element]->anak[$nama] = 0;
}
// Tambahkan satu ke penghitung elemen anak dari elemen induk elemen.
$elements[$last_element]->anak[$nama]++;
}
//Tambahkan elemen saat ini ke tumpukan
array_push($tumpukan, $nama);
}
fungsi stop_element($parser, $nama)
{
global $stack;
// Hapus elemen teratas dari tumpukan
array_pop($tumpukan);
}
fungsi char_data($parser, $data)
{
global $element, $stack, $kedalaman;
// Menambah jumlah karakter elemen saat ini
$elements[$stack][count($stack)-1]]->karakter += strlen(trim($data));
}
// Menghasilkan instance parser
$parser = xml_parser_create();
// Mengatur fungsi pemrosesan
xml_set_element_handler($parser, "start_element", "stop_element");
xml_set_character_data_handler($parser, "char_data");
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
// Parsing file
$ret = xml_parse_from_file($parser, $file);
jika(!$ret)
{
die(sprintf("Kesalahan XML: %s pada baris %d",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)));
}
// Lepaskan pengurai
xml_parser_free($parser);
// Bebaskan elemen pembantu
tidak disetel($elemen["elemen_saat ini"]);
unset($elements["last_element"]);
// Urutkan berdasarkan jumlah elemen
uasort($elements, "my_sort");
// Ulangi $elements untuk mengumpulkan informasi elemen
while(daftar($nama, $elemen) = masing-masing($elemen))
{
print_box("Nama elemen", $nama);
print_line("Jumlah elemen", $elemen->jumlah);
print_line("Jumlah karakter", $element->chars);
printf("n%20sn", "* Elemen induk");
// Ulangi induk elemen dan keluarkan hasilnya
while(daftar($kunci, $nilai) = masing-masing($elemen->orang tua))
{
print_line($kunci, $nilai);
}
if(count($element->orang tua) == 0)
{
printf("%35sn", "[elemen akar]");
}
// Ulangi turunan elemen ini dan keluarkan hasilnya
printf("n%20sn", "* Elemen turunan");
while(daftar($kunci, $nilai) = masing-masing($elemen->anak))
{
print_line($kunci, $nilai);
}
if(count($element->anak) == 0)
{
printf("%35sn", "[tidak ada anak]");
}
$total_elements += $element->hitungan;
$total_chars += $elemen->karakter;
}
// hasil akhir
print_box("Jumlah elemen", $total_elemen);
print_box("Jumlah karakter", $total_chars);
?>