Ændring af en XML-attribut i Java

1. Introduktion

En almindelig aktivitet, når vi arbejder med XML, er at arbejde med dets attributter. I denne vejledning undersøger vi, hvordan du ændrer en XML-attribut ved hjælp af Java.

2. Afhængigheder

For at køre vores tests skal vi tilføje JUnit og xmlunit-assertj afhængigheder til vores Maven-projekt:

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

3. Brug af JAXP

Lad os starte med et XML-dokument:

  [email protected] [email protected] 

For at behandle det, vil vi brug Java API til XML Processing (JAXP), som er leveret med Java siden version 1.4.

Lad os ændre kunde attribut og ændre dens værdi til falsk.

Først skal vi bygge en Dokument objekt fra XML-filen, og for at gøre det bruger vi en DocumentBuilderFactory:

DocumentBuilderFactory fabrik = DocumentBuilderFactory.newInstance (); factory.setFeature (XMLConstants.FEATURE_SECURE_PROCESSING, sand); factory.setFeature ("// apache.org/xml/features/disallow-doctype-decl", sandt); Dokumentinput = fabrik .newDocumentBuilder () .parse (resourcePath);

Bemærk, at for at deaktiver behandling af ekstern enhed (XXE) til DocumentBuilderFactory klasse, konfigurerer vi XMLConstants.FEATURE_SECURE_PROCESSING og //apache.org/xml/features/disallow-doctype-decl funktioner. Det er en god praksis at konfigurere det, når vi analyserer ikke-tillid til XML-filer.

Efter initialisering af vores input objekt, skal vi finde noden med den attribut, vi gerne vil ændre. Lad os bruge et XPath-udtryk til at vælge det:

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

I dette tilfælde XPath vurdere metoden returnerer os en nodeliste med de matchede noder.

Lad os gentage listen for at ændre værdien:

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

Eller i stedet for en til loop, vi kan bruge en IntStream:

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

Lad os nu bruge en Transformer gør indsigelse mod at anvende ændringerne:

TransformerFactory fabrik = TransformerFactory.newInstance (); factory.setFeature (XMLConstants.FEATURE_SECURE_PROCESSING, sand); Transformer xformer = fabrik.newTransformer (); xformer.setOutputProperty (OutputKeys.INDENT, "ja"); Writer output = ny StringWriter (); xformer.transform (ny DOMSource (input), ny StreamResult (output));

Hvis vi udskriver produktion objektindhold, får vi den resulterende XML med kunde attribut ændret:

  [email protected] [email protected] 

Vi kan også bruge hævder det metode til XMLUnit, hvis vi har brug for at verificere det i en enhedstest:

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

4. Brug af dom4j

dom4j er en open source-ramme til behandling af XML, der er integreret med XPath og understøtter fuldt ud DOM, SAX, JAXP og Java Collections.

4.1. Maven afhængighed

Vi er nødt til at tilføje dom4j- og jaxen-afhængighederne til vores pom.xml at bruge dom4j i vores projekt:

 org.dom4j dom4j 2.1.1 jaxen jaxen 1.2.0 

Vi kan lære mere om dom4j i vores XML Libraries Support-artikel.

4.2. Ved brug af org.dom4j.Element.addAttribute

dom4j tilbyder Element interface som en abstraktion for et XML-element. Vi bruger addAttribute metode til at opdatere vores kunde attribut.

Lad os se, hvordan dette fungerer.

Først skal vi bygge en Dokument objekt fra XML-filen - denne gang bruger vi en SAXReader:

SAXReader xmlReader = ny SAXReader (); Dokumentinput = xmlReader.read (resourcePath); xmlReader.setFeature ("// apache.org/xml/features/disallow-doctype-decl", sandt); xmlReader.setFeature ("// xml.org/sax/features/external-general-entities", false); xmlReader.setFeature ("// xml.org/sax/features/external-parameter-entities", false);

Vi indstiller de ekstra funktioner for at forhindre XXE.

Som JAXP kan vi bruge et XPath-udtryk til at vælge noderne:

String expr = String.format ("// * [indeholder (@% s, '% s')]", attribut, oldValue); XPath xpath = DocumentHelper.createXPath (expr); Liste noder = xpath.selectNodes (input);

Nu kan vi gentage og opdatere attributten:

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

Bemærk, at hvis der allerede findes en attribut for det givne navn med denne metode, vil den blive erstattet. Ellers tilføjes det.

For at udskrive resultaterne kan vi genbruge koden fra det forrige JAXP-afsnit.

5. Brug af jOOX

jOOX (jOOX Object-Oriented XML) er en indpakning til org.w3c.dom pakke, der giver mulighed for flydende XML-dokument oprettelse og manipulation, hvor DOM er påkrævet, men for detaljeret. jOOX indpakker kun det underliggende dokument og kan bruges til at forbedre DOM, ikke som et alternativ.

5.1. Maven afhængighed

Vi er nødt til at tilføje afhængigheden af ​​vores pom.xml at bruge jOOX i vores projekt.

Til brug med Java 9+ kan vi bruge:

 org.jooq joox 1.6.2 

Eller med Java 6+ har vi:

 org.jooq joox-java-6 1.6.2 

Vi kan finde de nyeste versioner af joox og joox-java-6 i Maven Central-arkivet.

5.2. Ved brug af org.w3c.dom.Element.setAttribute

Selve jOOX API er inspireret af jQuery, som vi kan se i eksemplerne nedenfor. Lad os se, hvordan vi bruger det.

Først skal vi indlæse Dokument:

DocumentBuilder builder = JOOX.builder (); Dokumentinput = builder.parse (resourcePath);

Nu skal vi vælge det:

Match $ = $ (input);

For at vælge kundeelement, vi kan bruge finde metode eller et XPath-udtryk. I begge tilfælde får vi en liste over de elementer, der matcher den.

Lad os se finde metode i aktion:

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

For at få resultatet som en Snor, vi er simpelthen nødt til at ringe til toString () metode:

$ .toString ();

6. Benchmark

For at sammenligne ydeevnen for disse biblioteker brugte vi et JMH-benchmark.

Lad os se resultaterne:

| Benchmark Mode Cnt Score Fejlenheder | | ------------------------------------------------- ------------------- | | 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 |

Som vi kan se, har dom4j og JAXP for denne brugssag og vores implementering bedre score end jOOX.

7. Konklusion

I denne hurtige vejledning har vi introduceret, hvordan du ændrer XML-attributter ved hjælp af JAXP, dom4j og jOOX. Vi målte også ydeevnen for disse biblioteker med et JMH-benchmark.

Som normalt er alle kodeeksempler vist her tilgængelige på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found