Memodifikasi Atribut XML di Java

1. Perkenalan

Satu aktivitas umum saat kita bekerja dengan XML bekerja dengan atributnya. Dalam tutorial ini, kita akan mempelajari cara memodifikasi atribut XML menggunakan Java.

2. Dependensi

Untuk menjalankan pengujian, kita perlu menambahkan dependensi JUnit dan xmlunit-assertj ke proyek Maven kita:

 org.junit.jupiter junit-jupiter 5.5.0 test 
 org.xmlunit xmlunit-assertj 2.6.3 test 

3. Menggunakan JAXP

Mari kita mulai dengan dokumen XML:

  [email protected] [email protected] 

Untuk memprosesnya, kami akan menggunakan Java API for XML Processing (JAXP) , yang telah dibundel dengan Java sejak versi 1.4.

Mari ubah atribut pelanggan dan ubah nilainya menjadi false .

Pertama, kita perlu membuat objek Dokumen dari file XML, dan untuk melakukannya, kita akan menggunakan DocumentBuilderFactory :

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); factory.setFeature("//apache.org/xml/features/disallow-doctype-decl", true); Document input = factory .newDocumentBuilder() .parse(resourcePath);

Perhatikan bahwa untuk menonaktifkan eksternal entitas pengolahan (XXE) untuk DocumentBuilderFactory kelas, kita mengkonfigurasi XMLConstants.FEATURE_SECURE_PROCESSING dan //apache.org/xml/features/disallow-doctype-decl fitur . Ini adalah praktik yang baik untuk mengonfigurasinya saat kita mengurai file XML yang tidak tepercaya.

Setelah menginisialisasi objek input kita, kita perlu mencari node dengan atribut yang ingin kita ubah. Mari gunakan ekspresi XPath untuk memilihnya:

XPath xpath = XPathFactory .newInstance() .newXPath(); String expr = String.format("//*[contains(@%s, '%s')]", attribute, oldValue); NodeList nodes = (NodeList) xpath.evaluate(expr, input, XPathConstants.NODESET);

Dalam kasus ini, metode evaluasi XPath mengembalikan kita daftar simpul dengan simpul yang cocok.

Mari mengulangi daftar untuk mengubah nilainya:

for (int i = 0; i < nodes.getLength(); i++) { Element value = (Element) nodes.item(i); value.setAttribute(attribute, newValue); }

Atau, sebagai ganti for loop, kita bisa menggunakan IntStream :

IntStream .range(0, nodes.getLength()) .mapToObj(i -> (Element) nodes.item(i)) .forEach(value -> value.setAttribute(attribute, newValue));

Sekarang, mari gunakan objek Transformer untuk menerapkan perubahan:

TransformerFactory factory = TransformerFactory.newInstance(); factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformer xformer = factory.newTransformer(); xformer.setOutputProperty(OutputKeys.INDENT, "yes"); Writer output = new StringWriter(); xformer.transform(new DOMSource(input), new StreamResult(output));

Jika kita mencetak konten objek keluaran , kita akan mendapatkan XML yang dihasilkan dengan atribut pelanggan yang dimodifikasi:

  [email protected] [email protected] 

Juga, kita dapat menggunakan assertThat metode XMLUnit jika kita perlu untuk verifikasi di tes unit:

assertThat(output.toString()).hasXPath("//*[contains(@customer, 'false')]");

4. Menggunakan dom4j

dom4j adalah kerangka kerja sumber terbuka untuk memproses XML yang terintegrasi dengan XPath dan mendukung penuh Koleksi DOM, SAX, JAXP, dan Java.

4.1. Ketergantungan Maven

Kita perlu menambahkan dependensi dom4j dan jaxen ke pom.xml kita untuk menggunakan dom4j dalam proyek kita:

 org.dom4j dom4j 2.1.1   jaxen jaxen 1.2.0 

Kami dapat mempelajari lebih lanjut tentang dom4j di artikel Dukungan Perpustakaan XML kami.

4.2. Menggunakan org.dom4j.Element.addAttribute

dom4j menawarkan antarmuka Elemen sebagai abstraksi untuk elemen XML. Kami akan menggunakan metode addAttribute untuk memperbarui atribut pelanggan kami .

Mari kita lihat cara kerjanya.

Pertama, kita perlu membuat objek Dokumen dari file XML - kali ini, kita akan menggunakan SAXReader :

SAXReader xmlReader = new SAXReader(); Document input = xmlReader.read(resourcePath); xmlReader.setFeature("//apache.org/xml/features/disallow-doctype-decl", true); xmlReader.setFeature("//xml.org/sax/features/external-general-entities", false); xmlReader.setFeature("//xml.org/sax/features/external-parameter-entities", false);

Kami mengatur fitur tambahan untuk mencegah XXE.

Seperti JAXP, kita dapat menggunakan ekspresi XPath untuk memilih node:

String expr = String.format("//*[contains(@%s, '%s')]", attribute, oldValue); XPath xpath = DocumentHelper.createXPath(expr); List nodes = xpath.selectNodes(input);

Sekarang, kita dapat mengulang dan memperbarui atribut:

for (int i = 0; i < nodes.size(); i++) { Element element = (Element) nodes.get(i); element.addAttribute(attribute, newValue); }

Perhatikan bahwa dengan metode ini, jika atribut sudah ada untuk nama yang diberikan, itu akan diganti. Jika tidak, itu akan ditambahkan.

Untuk mencetak hasil, kita dapat menggunakan kembali kode dari bagian JAXP sebelumnya.

5. Menggunakan jOOX

jOOX (jOOX Object-Oriented XML) adalah pembungkus untuk paket org.w3c.dom yang memungkinkan pembuatan dan manipulasi dokumen XML yang lancar di mana DOM diperlukan tetapi terlalu bertele-tele. jOOX hanya membungkus dokumen yang mendasarinya dan dapat digunakan untuk meningkatkan DOM, bukan sebagai alternatif.

5.1. Ketergantungan Maven

Kita perlu menambahkan ketergantungan ke pom.xml kita untuk menggunakan jOOX dalam proyek kita.

Untuk digunakan dengan Java 9+, kita dapat menggunakan:

 org.jooq joox 1.6.2 

Atau dengan Java 6+, kami memiliki:

 org.jooq joox-java-6 1.6.2 

Kami dapat menemukan versi terbaru joox dan joox-java-6 di repositori Maven Central.

5.2. Using org.w3c.dom.Element.setAttribute

The jOOX API itself is inspired by jQuery, as we can see in the examples below. Let's see how to use it.

First, we need to load the Document:

DocumentBuilder builder = JOOX.builder(); Document input = builder.parse(resourcePath);

Now, we need to select it:

Match $ = $(input);

In order to select the customer Element, we can use the find method or an XPath expression. In both cases, we'll get a list of the elements that match it.

Let's see the find method in action:

$.find("to") .get() .stream() .forEach(e -> e.setAttribute(attribute, newValue));

To get the result as a String, we simply need to call the toString() method:

$.toString();

6. Benchmark

In order to compare the performance of these libraries, we used a JMH benchmark.

Let's see the results:

| Benchmark Mode Cnt Score Error Units | |--------------------------------------------------------------------| | AttributeBenchMark.dom4jBenchmark avgt 5 0.150 ± 0.003 ms/op | | AttributeBenchMark.jaxpBenchmark avgt 5 0.166 ± 0.003 ms/op | | AttributeBenchMark.jooxBenchmark avgt 5 0.230 ± 0.033 ms/op |

Seperti yang bisa kita lihat, untuk kasus penggunaan ini dan implementasi kami, dom4j dan JAXP memiliki skor yang lebih baik daripada jOOX.

7. Kesimpulan

Dalam tutorial singkat ini, kami telah memperkenalkan cara memodifikasi atribut XML menggunakan JAXP, dom4j, dan jOOX. Selain itu, kami mengukur kinerja pustaka ini dengan tolok ukur JMH.

Seperti biasa, semua contoh kode yang ditampilkan di sini tersedia di GitHub.