Jobber med XML i Groovy

1. Introduksjon

Groovy tilbyr et betydelig antall metoder dedikert til å krysse og manipulere XML-innhold.

I denne opplæringen vil vi demonstrere hvordan du gjør det legge til, redigere eller slette elementer fra XML i Groovy ved hjelp av ulike tilnærminger. Vi viser også hvordan lage en XML-struktur fra bunnen av.

2. Definere modellen

La oss definere en XML-struktur i ressurskatalogen som vi bruker gjennom eksemplene våre:

  Første trinn i Java Siena Kerr 2018-12-01 Dockerize din SpringBoot-applikasjon Jonas Lugo 2018-12-01 SpringBoot tutorial Daniele Ferguson 12-06 2018 Java 12 innsikt Siena Kerr 22-07-2018 

Og les det inn i en InputStream variabel:

def xmlFile = getClass (). getResourceAsStream ("articles.xml")

3. XmlParser

La oss begynne å utforske denne strømmen med XmlParser klasse.

3.1. Lesning

Lesing og parsing av en XML-fil er sannsynligvis den vanligste XML-operasjonen en utvikler må gjøre. De XmlParser gir et veldig greit grensesnitt ment for akkurat det:

def artikler = ny XmlParser (). analyse (xmlFile)

På dette punktet kan vi få tilgang til attributtene og verdiene til XML-strukturen ved hjelp av GPath-uttrykk.

La oss nå implementere en enkel test ved hjelp av Spock for å sjekke om vår artikler objektet er riktig:

def "Bør lese XML-fil ordentlig" () {gitt: "XML-fil" når: "Bruke XmlParser til å lese fil" def artikler = ny XmlParser (). parse (xmlFile) deretter: "Xml er lastet riktig" artikler. '* '.størrelse () == 4 articles.article [0] .author.firstname.text () == "Siena" articles.article [2].' release-date'.text () == "2018-06- 12 "articles.article [3] .title.text () ==" Java 12 insights "articles.article.find {it.author. '@ Id'.text () ==" 3 "} .author.firstname. tekst () == "Daniele"}

For å forstå hvordan du får tilgang til XML-verdier og hvordan du bruker GPath-uttrykkene, la oss fokusere et øyeblikk på den interne strukturen til resultatet av XmlParser # analyse operasjon.

De artikler objekt er en forekomst av groovy.util.Node. Hver Node består av et navn, attributtskart, verdi og foreldre (som kan være en av dem null eller en annen Node).

I vårt tilfelle er verdien av artikler er en groovy.util.NodeList forekomst, som er en wrapper-klasse for en samling av Nodes. De NodeList utvider java.util.ArrayList klasse, som gir utvinning av elementer etter indeks. For å oppnå en strengverdi på en Node, vi bruker groovy.util.Node # tekst ().

I eksemplet ovenfor introduserte vi noen få GPath-uttrykk:

  • articles.article [0] .author.firstname - få forfatterens fornavn for den første artikkelen - artikler.artikkel [n] direkte tilgang til nartikkel
  • ‘*' - få en liste over artikkel’S barn - det tilsvarer groovy.util.Node # barn ()
  • forfatter.'@id ' - Hent forfatter elementets id Egenskap - forfatter.'@attributtnavn ' får tilgang til attributtverdien ved navn (ekvivalenter er: forfatter [‘@ id '] og [e-postbeskyttet])

3.2. Legge til en node

I likhet med forrige eksempel, la oss først lese XML-innholdet i en variabel. Dette vil tillate oss å definere en ny node og legge den til i artikellisten vår ved hjelp av groovy.util.Node # vedlegg.

La oss nå implementere en test som beviser poenget vårt:

def "Skal legge til node til eksisterende xml ved hjelp av NodeBuilder" () {gitt: "XML-objekt" def articles = new XmlParser (). parse (xmlFile) when: "Adding node to xml" def articleNode = new NodeBuilder (). article ( id: '5') {title ('Traversing XML in the nutshell') forfatter {firstname ('Martin') etternavn ('Schmidt')} 'release-date' ('2019-05-18')} articles.append (articleNode) deretter: "Node legges til xml ordentlig" artikler. '*'. size () == 5 articles.article [4] .title.text () == "Traversing XML in the nutshell"}

Som vi kan se i eksemplet ovenfor, er prosessen ganske grei.

La oss også legge merke til at vi brukte groovy.util.NodeBuilder, som er et pent alternativ til å bruke Node konstruktør for vår Node definisjon.

3.3. Endring av en node

Vi kan også endre verdiene til noder ved hjelp av XmlParser. For å gjøre det, la oss nok en gang analysere innholdet i XML-filen. Deretter kan vi redigere innholdsnoden ved å endre verdi felt av Node gjenstand.

La oss huske det mens XmlParser bruker GPath-uttrykkene, henter vi alltid forekomsten av NodeList, så for å endre det første (og eneste) elementet, må vi få tilgang til det ved hjelp av indeksen.

La oss sjekke antagelsene våre ved å skrive en rask test:

def "Bør endre node" () {gitt: "XML-objekt" def articles = new XmlParser (). parse (xmlFile) when: "Endring av verdien av en av nodene" articles.article.each {it.'release-date '[0] .value = "2019-05-18"} deretter: "XML er oppdatert" articles.article.findAll {it.'release-date'.text ()! = "18.05.2019"}. er tom() }

I eksemplet ovenfor har vi også brukt Groovy Collections API til å krysse NodeList.

3.4. Bytte ut en node

Deretter, la oss se hvordan du bytter ut hele noden i stedet for bare å endre en av dens verdier.

På samme måte som å legge til et nytt element, bruker vi NodeBuilder for Node definisjon og erstatt deretter en av eksisterende noder i den ved hjelp av groovy.util.Node # erstatteNode:

def "Skal erstatte node" () {gitt: "XML-objekt" def articles = new XmlParser (). parse (xmlFile) when: "Adding node to xml" def articleNode = new NodeBuilder (). article (id: '5' ) {title ('Traversing XML in the nutshell') author {firstname ('Martin') lastname ('Schmidt')} 'release-date' ('2019-05-18')} articles.article [0] .replaceNode (articleNode) deretter: "Node legges til xml ordentlig" artikler. '*'. størrelse () == 4 articles.article [0] .title.text () == "Traversing XML in the nutshell"}

3.5. Slette en node

Slette en node ved hjelp av XmlParser er ganske vanskelig. Selv om Node klasse gir fjerne (Node barn) metoden, i de fleste tilfeller vil vi ikke bruke den av seg selv.

I stedet viser vi hvordan du sletter en node hvis verdi oppfyller en gitt betingelse.

Som standard tilgang til de nestede elementene ved hjelp av en kjede av Node.NodeList referanser returnerer en kopi av de tilsvarende barnodene. På grunn av det kan vi ikke bruke java.util.NodeList # removeAll metode direkte på vår artikkel samling.

For å slette en node med et predikat, må vi først finne alle noder som samsvarer med tilstanden vår, og deretter gjenta dem og påkalle java.util.Node # fjern metode på foreldrene hver gang.

La oss implementere en test som fjerner alle artikler hvis forfatter har en annen id enn 3:

def "Bør fjerne artikkelen fra xml" () {gitt: "XML-objekt" def articles = new XmlParser (). parse (xmlFile) når: "Fjerne alle artiklene, men de med id == 3" articles.article .findAll { it.author. '@ id'.text ()! = "3"}. hver {articles.remove (it)} så: "Det er bare en artikkel igjen" articles.children (). størrelse () == 1 articles.article [0] .author. '@ id'.text () == "3"}

Som vi kan se, mottok vi en XML-struktur med bare en artikkel, og dens id er 3.

4. XmlSlurper

Groovy tilbyr også en annen klasse dedikert til å jobbe med XML. I denne delen viser vi hvordan du leser og manipulerer XML-strukturen ved hjelp av XmlSlurper.

4.1. Lesning

Som i våre tidligere eksempler, la oss begynne med å analysere XML-strukturen fra en fil:

def "Bør lese XML-fil ordentlig" () {gitt: "XML-fil" når: "Bruke XmlSlurper til å lese fil" def articles = new XmlSlurper (). parse (xmlFile) deretter: "Xml er lastet riktig" artikler. '* '.størrelse () == 4 articles.article [0] .author.firstname == "Siena" articles.article [2].' release date '== "2018-06-12" articles.article [3] .title == "Java 12 innsikt" articles.article.find {it.author.'@id '== "3"} .author.firstname == "Daniele"}

Som vi kan se, er grensesnittet identisk med det for XmlParser. Imidlertid bruker utgangsstrukturen groovy.util.slurpersupport.GPathResult, som er en innpakningsklasse for Node. GPathResult gir forenklede definisjoner av metoder som: er lik() og toString () ved å pakke inn Knutepunkt # tekst (). Som et resultat kan vi lese felt og parametere direkte ved å bare bruke navnene deres.

4.2. Legge til en node

Legge til en Node er også veldig lik å bruke XmlParser. I dette tilfellet groovy.util.slurpersupport.GPathResult # appendNode gir en metode som tar en forekomst av java.lang.Objekt som argument. Som et resultat kan vi forenkle nye Node definisjoner etter samme konvensjon introdusert av NodeBygger:

def "Skal legge til node til eksisterende xml" () {gitt: "XML-objekt" def articles = new XmlSlurper (). parse (xmlFile) når: "Legge til node til xml" articles.appendNode {artikkel (id: '5') {title ('Traversing XML in the nutshell') forfatter {firstname ('Martin') etternavn ('Schmidt')} 'release-date' ('2019-05-18')}} artikler = ny XmlSlurper (). parseText (XmlUtil.serialize (artikler)) deretter: "Node legges til xml ordentlig" artikler. '*'. Størrelse () == 5 artikler. Artikkel [4] .title == "Traversing XML in the nutshell"}

I tilfelle vi trenger å endre strukturen til XML med XmlSlurper, vi må starte på nytt artikler innvende for å se resultatene. Vi kan oppnå det ved å bruke kombinasjonen av groovy.util.XmlSlurper # parseText og groovy.xmlXmlUtil # serialize metoder.

4.3. Endring av en node

Som vi nevnte før, GPathResult introduserer en forenklet tilnærming til datamanipulering. Når det er sagt, i motsetning til XmlSlurper, vi kan endre verdiene direkte ved hjelp av nodenavnet eller parameternavnet:

def "Bør endre node" () {gitt: "XML-objekt" def articles = new XmlSlurper (). parse (xmlFile) when: "Endring av verdien av en av nodene" articles.article.each {it.'release-date '= "2019-05-18"} deretter: "XML er oppdatert" articles.article.findAll {it.'release-date'! = "2019-05-18"} .isEmpty ()}

La oss legge merke til at når vi bare endrer verdiene til XML-objektet, trenger vi ikke å analysere hele strukturen igjen.

4.4. Bytte ut en node

La oss nå gå over til å erstatte hele noden. Igjen, den GPathResult kommer til unnsetning. Vi kan enkelt erstatte noden ved hjelp av groovy.util.slurpersupport.NodeChild # erstatteNode, som strekker seg GPathResult og følger samme konvensjon for bruk av Gjenstand verdier som argumenter:

def "Bør erstatte node" () {gitt: "XML-objekt" def articles = new XmlSlurper (). parse (xmlFile) når: "Erstatte node" articles.article [0] .replaceNode {artikkel (id: '5') {title ('Traversing XML in the nutshell') forfatter {fornavn ('Martin') etternavn ('Schmidt')} 'release-date' ('2019-05-18')}} artikler = ny XmlSlurper (). parseText (XmlUtil.serialize (artikler)) deretter: "Node erstattes ordentlig" artikler. '*'. Størrelse () == 4 artikler.artikkel [0] .title == "Traversing XML in the nutshell"}

Som det var tilfelle når vi legger til en node, endrer vi strukturen til XML, så vi må analysere den igjen.

4.5. Slette en node

For å fjerne en node ved hjelp av XmlSlurper, vi kan gjenbruke groovy.util.slurpersupport.NodeChild # erstatteNode metode ganske enkelt ved å gi en tom Node definisjon:

def "Bør fjerne artikkelen fra xml" () {gitt: "XML-objekt" def articles = new XmlSlurper (). parse (xmlFile) når: "Fjerne alle artiklene, men de med id == 3" articles.article .findAll { it.author.'@id '! = "3"} .replaceNode {} artikler = ny XmlSlurper (). parseText (XmlUtil.serialize (artikler)) deretter: "Det er bare en artikkel igjen" articles.children (). størrelse () == 1 artikler.artikkel [0] .forfatter. '@ id' == "3"}

Igjen, endring av XML-strukturen krever reinitialisering av vår artikler gjenstand.

5. XmlParser vs. XmlSlurper

Som vi viste i eksemplene våre, bruk av XmlParser og XmlSlurper er ganske like. Vi kan mer eller mindre oppnå de samme resultatene med begge. Imidlertid kan noen forskjeller mellom dem vippe skalaene mot den ene eller den andre.

Først av alt,XmlParser analyserer alltid hele dokumentet i DOM-ish-strukturen. På grunn av det kan vi samtidig lese fra og skrive inn i det. Vi kan ikke gjøre det samme med XmlSlurper ettersom den vurderer stier latere. Som et resultat, XmlParser kan forbruke mer minne.

På den andre siden, XmlSlurper bruker mer enkle definisjoner, noe som gjør det enklere å jobbe med. Vi må også huske det eventuelle strukturelle endringer som er gjort i XML ved hjelp av XmlSlurper krever reinitialisering, noe som kan få et uakseptabelt ytelseshit i tilfelle du gjør mange endringer etter hverandre.

Beslutningen om hvilket verktøy du skal bruke skal tas med forsiktighet og avhenger helt av brukssaken.

6. MarkupBuilder

Bortsett fra å lese og manipulere XML-treet, gir Groovy også verktøy for å lage et XML-dokument fra bunnen av. La oss nå lage et dokument som består av de to første artiklene fra vårt første eksempel ved hjelp av groovy.xml.MarkupBuilder:

def "Skal opprette XML riktig" () {gitt: "Node strukturer" når: "Bruke MarkupBuilderTest til å opprette xml struktur" def forfatter = ny StringWriter () ny MarkupBuilder (forfatter) .artikler {artikkel {tittel ('Første trinn i Java ') forfatter (id:' 1 ') {fornavn (' Siena ') etternavn (' Kerr ')}' utgivelsesdato '(' 2018-12-01 ')} artikkel {tittel (' Dockerize din SpringBoot-applikasjon ') forfatter (id: '2') {fornavn ('Jonas') etternavn ('Lugo')} 'utgivelsesdato' ('2018-12-01')}} så: "Xml er opprettet riktig" XmlUtil.serialize ( writer.toString ()) == XmlUtil.serialize (xmlFile.text)}

I eksemplet ovenfor kan vi se det MarkupBuilder bruker den samme tilnærmingen for Node definisjoner vi brukte med NodeBuilder og GPathResult tidligere.

For å sammenligne produksjon fra MarkupBuilder med den forventede XML-strukturen, brukte vi groovy.xml.XmlUtil # serialize metode.

7. Konklusjon

I denne artikkelen undersøkte vi flere måter å manipulere XML-strukturer ved hjelp av Groovy.

Vi så på eksempler på parsing, tilføying, redigering, erstatning og sletting av noder ved hjelp av to klasser levert av Groovy: XmlParser og XmlSlurper. Vi diskuterte også forskjeller mellom dem og viste hvordan vi kunne bygge et XML-tre fra bunnen av ved hjelp av MarkupBuilder.

Som alltid er den komplette koden som brukes i denne artikkelen tilgjengelig på GitHub.


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