Pertanyaan objek Java menggunakan JXPath

Dalam projek baru-baru ini, saya memerlukan cara mudah untuk melintasi pokok objek Java dan mengekstrak nilai dari objek tersebut. Daripada terus-menerus melalui penyiapan iterator-if-else, saya mahukan alat yang membolehkan saya hanya mengatakan, "Saya mahukan objek dengan id = X, dan dari objek itu, saya memerlukan nilai harta A." Pada dasarnya, saya memerlukan alat membuat pertanyaan.

JXPath adalah alat pertanyaan objek. Ia adalah komponen Apache Commons yang membolehkan anda membuat pertanyaan mengenai pokok objek kompleks dengan menggunakan bahasa ekspresi XPath yang terkenal. Saya menggunakan JXPath secara meluas dalam projek saya, dan mempercepat banyak perkara, menjadikan algoritma pengekstrakan nilai menjadi mudah.

Walau bagaimanapun, JXPath tidak didokumentasikan secara meluas. Oleh kerana saya masih meneroka komponen secara mendalam, saya memutuskan untuk menuliskan penemuan saya dalam tutorial JXPath yang luas, yang dapat anda temukan di laman web saya. Artikel ini adalah versi ringkas dari tutorial itu untuk memulakan JXPath dengan cepat.

Catatan: Anda boleh memuat turun kod contoh yang disertakan dari Sumber.

Contoh model

Untuk tujuan ilustrasi, kami akan menggunakan model ringkas: sebuah syarikat dengan pelbagai jabatan , masing-masing mempunyai pelbagai pekerja . Inilah model kelas:

Secara semula jadi, kami memerlukan beberapa contoh data untuk model:

Syarikat

Jabatan

Pekerja (nama, jawatan, umur)

Acme Inc.

Jualan

Johnny, wakil jualan, 45

Sarah, Jurujual, 33

Magda, pembantu pejabat, 27

Perakaunan

Steve, Ketua pengawal, 51

Peter, Penolong pengawal, 31

Susan, pembantu pejabat, 27

Dengan itu, mari kita mula menggunakan JXPath!

Melaksanakan pertanyaan JXPath yang mudah

Pertanyaan termudah mungkin mengeluarkan satu objek dari pokok objek. Contohnya, untuk mendapatkan semula Company, gunakan kod berikut:

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

Baris pertama menunjukkan penciptaan a context, titik permulaan untuk semua ekspresi XPath JXPath di pohon objek (setanding dengan rootnodeelemen dalam dokumen XML). Baris kedua kod melaksanakan pertanyaan sebenar. Sejak kita contextmulai di peringkat syarikat, untuk mengambil Companyobjek, kita hanya menggunakan pemilih elemen semasa '.'.

Menggunakan predikat dan pemboleh ubah

An Employeeadalah objek kanak-kanak a Department. Untuk mendapatkan semula Employeenama "Johnny" gunakan kod berikut ( Companymasih merupakan contexttitik permulaan):

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

Pada dasarnya, kodnya berbunyi: "Cari semua Departmentdari awal untuk Employeeobjek yang nameatributnya mempunyai nilai 'Johnny'."

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

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

Kecuali anda menggunakan pertanyaan ad-hoc, satu-satunya, melaksanakan pertanyaan dengan kod keras biasanya tidak dapat dilaksanakan. Lebih baik menentukan pertanyaan yang boleh digunakan semula yang kemudian anda dapat laksanakan dengan parameter yang berbeza. Untuk menampung permintaan parameter, JXPath menyokong pemboleh ubah dalam pertanyaan. Dengan menggunakan pemboleh ubah, kod di atas sekarang kelihatan 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 ke atas semua objek yang diambil oleh pertanyaan, seperti mengulang set hasil. Coretan berikut menunjukkan bagaimana anda boleh melakukan lelaran pada semua perkara Department:

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

Untuk mengambil semua Employees dari semua Departmentdan mengulanginya:

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

Untuk mendapatkan semua yang Employeeberumur lebih dari 30 tahun dari bahagian penjualan:

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

Dan contoh di atas dengan pemboleh ubah:

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(); //... }

Kedua-dua coretan kod terakhir ini juga menunjukkan penggunaan beberapa predikat dalam satu pertanyaan XPath.

Petunjuk

A Pointeradalah objek utiliti JXPath yang mewakili rujukan ke lokasi objek di pohon objek. Contohnya, Pointerkemungkinan merujuk kepada "pekerja pertama jabatan kedua." Berbanding dengan objek yang diambil terus dari pokok, Pointermenawarkan fungsi tambahan seperti pelaksanaan pertanyaan relatif melalui konteks relatif (lebih lanjut mengenai ini kemudian).

Menggunakan Penunjuk

Mempunyai Pointermerujuk pada objek di pohon objek hampir sama 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 pokok objek yang kompleks. Kerana menggunakan bahasa ekspresi XPath untuk pertanyaannya, banyak bahan rujukan tersedia untuk membantu anda membina pertanyaan pengambilan objek yang cekap namun kompleks. Lebih banyak fleksibiliti ditambah dengan menggunakan Pointerkonteks s dan relatif.

Artikel ringkas ini hanya menggaris permukaan kemungkinan JXPath, untuk perbincangan yang lebih mendalam dengan contoh penggunaan yang lebih maju, baca tutorial penuh saya.

Bart van Riel telah terlibat dalam dunia Jawa dan berorientasikan objek selama lebih dari tujuh tahun. Dia telah bekerja sebagai pengembang dan pelatih di bidang berorientasi objek dan Java. Dia kini bekerja di firma perunding IT global Capgemini sebagai arkitek perisian dan protagonis sumber terbuka.

Ketahui lebih lanjut mengenai topik ini

  • Muat turun kod sumber untuk artikel ini
  • Lihat tutorial JXPath penuh
  • Apache Commons JXPath
  • Tutorial XPath yang baik
  • Bebas melalui artikel dalam JavaWorld 's Tools Pembangunan Pusat Penyelidikan
  • Ikuti perkembangan yang baru di JavaWorld ! Daftar untuk mendapatkan buletin Enterprise Java percuma kami

Kisah ini, "Pertanyaan objek Java menggunakan JXPath" pada awalnya diterbitkan oleh JavaWorld.