Kueri objek Java menggunakan JXPath

Dalam proyek baru-baru ini, saya membutuhkan cara mudah untuk melintasi pohon objek Java dan mengekstrak nilai dari objek. Alih-alih terus-menerus melalui penyiapan iterator-if-else yang besar, saya menginginkan alat yang memungkinkan saya untuk mengatakan, "Saya ingin objek dengan id = X, dan dari objek itu, saya memerlukan nilai properti A." Intinya, saya membutuhkan alat kueri objek.

JXPath adalah alat kueri objek. Ini adalah komponen Apache Commons yang memungkinkan Anda untuk menanyakan pohon objek yang kompleks menggunakan bahasa ekspresi XPath yang terkenal. Saya menggunakan JXPath secara luas dalam proyek saya, dan itu mempercepat banyak hal, membuat algoritme ekstraksi nilai menjadi mudah.

Namun, JXPath tidak didokumentasikan secara luas. Karena saya mengeksplorasi komponen secara mendalam, saya memutuskan untuk menuliskan temuan saya dalam tutorial JXPath yang ekstensif, yang dapat Anda temukan di situs web saya. Artikel ini adalah versi singkat dari tutorial tersebut untuk membantu Anda memulai dengan JXPath dengan cepat.

Catatan: Anda dapat mendownload kode sampel yang menyertai dari Resources.

Model contoh

Sebagai ilustrasi, kita akan menggunakan model sederhana: perusahaan dengan berbagai departemen , masing-masing dengan berbagai karyawan . Berikut model kelasnya:

Secara alami, kami memerlukan beberapa data sampel untuk model:

Perusahaan

Departemen

Karyawan (nama, jabatan, umur)

Acme Inc.

Penjualan

Johnny, Sales rep, 45

Sarah, Sales rep, 33

Magda, asisten kantor, 27

Akuntansi

Steve, Pengendali kepala, 51

Peter, Asisten pengontrol, 31

Susan, asisten kantor, 27

Dengan itu, mari mulai menggunakan JXPath!

Menjalankan kueri JXPath sederhana

Kueri yang paling sederhana mungkin mengekstrak satu objek dari pohon objek. Misalnya, untuk mengambilnya Company, gunakan kode berikut:

JXPathContext context = JXPathContext.newContext(company); Company c = (Company)context.getValue(".");

Baris pertama menunjukkan pembuatan sebuah context, titik awal untuk semua ekspresi XPath JXPath di pohon objek (sebanding dengan rootnodeelemen dalam dokumen XML). Baris kode kedua mengeksekusi kueri yang sebenarnya. Sejak kami contextmulai di tingkat perusahaan, untuk mengambil Companyobjek, kami cukup menggunakan pemilih elemen saat ini '.'.

Menggunakan predikat dan variabel

An Employeeadalah anak objek dari a Department. Untuk mendapatkan kembali yang Employeebernama "Johnny" gunakan kode berikut ( Companymasih merupakan contexttitik awal):

Employee emp = (Employee)context.getValue("/departmentList/employees[name='Johnny']");

Pada dasarnya, kode tersebut berbunyi: "Cari semua Departmentdari awal untuk Employeeobjek yang nameatributnya memiliki nilai 'Johnny'."

Potongan kode di atas menggambarkan cara menggunakan predikat untuk mencari objek dengan menggunakan nilai tertentu. Menggunakan predikat sebanding dengan menggunakan klausa WHERE di SQL. Kami bahkan dapat menggabungkan beberapa predikat dalam satu kueri:

Employee emp = (Employee)context.getValue("/departmentList/employees[name='Susan' and age=27]");

Kecuali Anda menggunakan kueri ad-hoc, satu kali saja, menerapkan kueri dengan kode keras biasanya tidak dapat dilakukan. Lebih baik menentukan kueri yang dapat digunakan kembali yang kemudian dapat Anda jalankan dengan parameter berbeda. Untuk mengakomodasi kueri berparameter, JXPath mendukung variabel dalam kueri. Menggunakan variabel, kode di atas sekarang terlihat seperti ini:

context.getVariables().declareVariable("name", "Susan"); context.getVariables().declareVariable("age", new Integer(27)); Employee emp = (Employee)context.getValue("/departmentList/employees[name=$name and age=$age]");

Mengulangi koleksi

JXPath dapat menyediakan iterator atas semua objek yang diambil oleh kueri, seperti mengiterasi kumpulan hasil. Cuplikan berikut menunjukkan bagaimana Anda dapat mengulangi semua Department:

for(Iterator iter = context.iterate("/departmentList"); iter.hasNext();){ Department d = (Department)iter.next(); //... }

Untuk mengambil semua Employeedari semua Departmentdan mengulanginya:

for(Iterator iter = context.iterate("/departmentList/employees"); iter.hasNext();){ Employee emp = (Employee)iter.next(); //... }

Untuk mengambil semua Employeeyang lebih tua dari 30 tahun dari departemen penjualan:

for(Iterator iter = context.iterate ("/departmentList[name='Sales']/employees[age>30]"); iter.hasNext();){ Employee emp = (Employee)iter.next(); //... }

Dan contoh di atas dengan variabel:

context.getVariables().declareVariable("deptName", "Sales"); context.getVariables().declareVariable("minAge", new Integer(30)); for(Iterator iter = context.iterate("/departmentList [name=$deptName]/employees[age>$minAge]"); iter.hasNext();){ Employee emp = (Employee)iter.next(); //... }

Dua cuplikan kode terakhir tersebut juga mendemonstrasikan penggunaan beberapa predikat dalam satu kueri XPath.

Pointer

A Pointeradalah objek utilitas JXPath yang mewakili referensi ke lokasi objek di pohon objek. Misalnya, a Pointermungkin merujuk pada "karyawan pertama dari departemen kedua." Dibandingkan dengan objek yang diambil langsung dari pohon, Pointers menawarkan fungsi tambahan seperti eksekusi kueri relatif melalui konteks relatif (lebih lanjut tentang ini nanti).

Menggunakan Pointer

Memiliki Pointerreferensi ke objek di pohon objek hampir identik dengan mengambil objek secara langsung:

JXPathContext context = JXPathContext.newContext(company); Pointer empPtr = context.getPointer("/departmentList[name='Sales']/employees[age>40]"); System.out.println(empPtr); //output: /departmentList[1]/employees[1] System.out.println(((Employee)empPtr.getValue()).getName()); //output: Johnny

Note that the Pointer's output demonstrates that a Pointer describes an object's location, rather than the object itself. Also note that the actual object the Pointer refers to can be retrieved through the Pointer's getValue() method.

Pointers can also be iterated over, as the following snippet demonstrates:

for(Iterator iter = context.iteratePointers("/departmentList[name='Sales'] /employees[age>30]"); iter.hasNext();){ Pointer empPtr = (Pointer)iter.next(); //... }

Relative context and relative queries

Since a Pointer describes a location, it can be used as a reference point for navigating through the entire object tree. To do that, use the Pointer as the root object (Remember using the Company object for that earlier?) in a so called relative context. From this relative context, you can query the entire object tree by executing relative queries. This advanced use of Pointers offers great flexibility as the examples below illustrate.

To begin, here's how you create a relative context:

for(Iterator iter = context.iteratePointers("/departmentList[name='Sales'] /employees[age>30]"); iter.hasNext();){ Pointer empPtr = (Pointer)iter.next(); JXPathContext relativeContext = context.getRelativeContext(empPtr); }

In this code snippet, a new relative context is created for consecutive employee pointers.

Using the relative context, XPath queries can be executed on the entire object tree of siblings, children, and parent/grandparent objects, as the following snippet demonstrates:

//Current employee Employee emp = (Employee)relativeContext.getValue("."); //Employee name String name = (String)relativeContext.getValue("./name"); //Name of the Department this Employee belongs to (a parent object) String deptName = (String)relativeContext.getValue("../name"); //Name of the Company this Employee belongs to (a 'grandparent' object) String compName = (String)relativeContext.getValue("../../name"); //All coworkers of this Employee (sibling objects) for(Iterator empIter = relativeContext.iterate("../employees"); empIter.hasNext();){ Employee colleague = (Employee)empIter.next(); //... }

Summary

JXPath adalah alat yang sangat berguna untuk melintasi, menavigasi, dan menanyakan pohon objek yang kompleks. Karena menggunakan bahasa ekspresi XPath untuk kuerinya, sejumlah besar materi referensi tersedia untuk membantu Anda membuat kueri pengambilan objek yang efisien namun kompleks. Lebih banyak fleksibilitas ditambahkan dengan menggunakan Pointers dan konteks relatif.

Artikel singkat ini hanya menggores permukaan kemungkinan JXPath, untuk diskusi yang lebih mendalam dengan contoh penggunaan yang lebih canggih, baca tutorial lengkap saya.

Bart van Riel telah berkecimpung di Jawa dan dunia berorientasi objek selama lebih dari tujuh tahun. Dia telah bekerja sebagai pengembang dan pelatih di bidang berorientasi objek dan Java. Dia saat ini bekerja di perusahaan konsultan IT global Capgemini sebagai arsitek perangkat lunak dan protagonis open source.

Pelajari lebih lanjut tentang topik ini

  • Unduh kode sumber untuk artikel ini
  • Lihat tutorial JXPath lengkap
  • Apache Commons JXPath
  • Tutorial XPath yang bagus
  • Telusuri melalui artikel di JavaWorld 's Development Tools Research Center
  • Ikuti terus apa yang baru di JavaWorld ! Daftar untuk buletin Enterprise Java gratis kami

Artikel ini, "kueri objek Java menggunakan JXPath", awalnya diterbitkan oleh JavaWorld.