Endring av et XML-attributt i Java

1. Introduksjon

En vanlig aktivitet når vi jobber med XML er å jobbe med attributtene. I denne opplæringen vil vi utforske hvordan du endrer et XML-attributt ved hjelp av Java.

2. Avhengigheter

For å kunne kjøre testene våre, må vi legge til JUnit og xmlunit-assertj avhengigheter til vårt Maven-prosjekt:

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

3. Bruke JAXP

La oss starte med et XML-dokument:

  [e-postbeskyttet] [e-postbeskyttet] 

For å behandle det, vil vi bruk Java API for XML Processing (JAXP), som har blitt pakket med Java siden versjon 1.4.

La oss endre kunde attributt og endre verdien til falsk.

Først må vi bygge en Dokument objekt fra XML-filen, og for å gjøre det, bruker vi a DocumentBuilderFactory:

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

Merk at for å deaktivere behandling av ekstern enhet (XXE) for DocumentBuilderFactory klasse, konfigurerer vi XMConstants.FEATURE_SECURE_PROCESSING og //apache.org/xml/features/disallow-doctype-decl funksjoner. Det er en god praksis å konfigurere den når vi analyserer ikke-klarerte XML-filer.

Etter å ha initialisert vår inngang objekt, må vi finne noden med attributtet vi vil endre. La oss bruke et XPath-uttrykk for å velge det:

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

I dette tilfellet XPath evaluere metoden gir oss en nodeliste med de samsvarende nodene.

La oss gjenta over listen for å endre verdien:

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

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

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

La oss nå bruke en Transformator innvende mot å bruke endringene:

TransformerFactory fabrikk = TransformerFactory.newInstance (); factory.setFeature (XMLConstants.FEATURE_SECURE_PROCESSING, true); Transformator xformer = fabrikk.newTransformer (); xformer.setOutputProperty (OutputKeys.INDENT, "yes"); Skriverutgang = ny StringWriter (); xformer.transform (ny DOMSource (input), ny StreamResult (output));

Hvis vi skriver ut produksjon objektinnhold, får vi den resulterende XML med kunde attributt endret:

  [e-postbeskyttet] [e-postbeskyttet] 

Vi kan også bruke hevder det metoden for XMLUnit hvis vi trenger å verifisere den i en enhetstest:

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

4. Bruke dom4j

dom4j er et open source-rammeverk for behandling av XML som er integrert med XPath og støtter fullt ut DOM, SAX, JAXP og Java Collections.

4.1. Maven avhengighet

Vi må legge til avhengighetene dom4j og jaxen til vår pom.xml å bruke dom4j i prosjektet vårt:

 org.dom4j dom4j 2.1.1 jaxen jaxen 1.2.0 

Vi kan lære mer om dom4j i vår artikkel om støtte for XML-biblioteker.

4.2. Ved hjelp av org.dom4j.Element.addAttribute

dom4j tilbyr Element grensesnitt som en abstraksjon for et XML-element. Vi bruker addAttribute metode for å oppdatere vår kunde Egenskap.

La oss se hvordan dette fungerer.

Først må vi bygge en Dokument objekt fra XML-filen - denne gangen bruker vi en SAXReader:

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

Vi setter tilleggsfunksjonene for å forhindre XXE.

Som JAXP kan vi bruke et XPath-uttrykk for å velge nodene:

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

Nå kan vi itere og oppdatere attributtet:

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

Merk at hvis det allerede eksisterer et attributt for det gitte navnet med denne metoden, vil det bli erstattet. Ellers blir det lagt til.

For å skrive ut resultatene kan vi bruke koden på nytt fra forrige JAXP-seksjon.

5. Bruke jOOX

jOOX (jOOX Object-Oriented XML) er en innpakning for org.w3c.dom pakke som tillater flytende XML-dokumentoppretting og -manipulering der DOM er påkrevd, men for ordentlig. jOOX pakker bare det underliggende dokumentet og kan brukes til å forbedre DOM, ikke som et alternativ.

5.1. Maven avhengighet

Vi må legge avhengigheten til vår pom.xml å bruke jOOX i prosjektet vårt.

For bruk med Java 9+ kan vi bruke:

 org.jooq joox 1.6.2 

Eller med Java 6+ har vi:

 org.jooq joox-java-6 1.6.2 

Vi finner de nyeste versjonene av joox og joox-java-6 i Maven Central repository.

5.2. Ved hjelp av org.w3c.dom.Element.setAttribute

Selve jOOX API er inspirert av jQuery, som vi kan se i eksemplene nedenfor. La oss se hvordan du bruker den.

Først må vi laste Dokument:

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

Nå må vi velge det:

Match $ = $ (input);

For å velge kundeelement, vi kan bruke finne metode eller et XPath-uttrykk. I begge tilfeller får vi en liste over elementene som samsvarer med den.

La oss se finne metode i aksjon:

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

For å få resultatet som en String, vi trenger bare å ringe toString () metode:

$ .toString ();

6. Referanse

For å sammenligne ytelsen til disse bibliotekene, brukte vi en JMH-referanse.

La oss se resultatene:

| Referansemodus 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 |

Som vi kan se, har dom4j og JAXP bedre score enn jOOX for denne brukssaken og vår implementering.

7. Konklusjon

I denne raske opplæringen har vi introdusert hvordan du endrer XML-attributter ved hjelp av JAXP, dom4j og jOOX. Vi målte også ytelsen til disse bibliotekene med en JMH-referanse.

Som vanlig er alle kodeeksemplene som vises her tilgjengelig på GitHub.