StAX
Frissítve: 2017. november 19.
Technológiák: JAXP 1.4, StAX 1.0
Ha már a webszolgáltatásokról volt szó, mely szorosan kapcsolódik az XML-hez, nézzük, hogy mi újítást hozott a JDK 6-ban bevezetett JAXP 1.4. A legnagyobb újdonság a StAX bevezetése, mely egy nagy teljesítményű stream alapú XML feldolgozó szűréssel (filter), mely támogatja a módosítást is.
A JAXP-ben már a W3C által definiált SAX és DOM feldolgozási modell régóta létezett. A SAX esetében esemény alapú feldolgozást lehet megvalósítani, ahol a feldolgozó (parser) hívja az osztályainkat (parser client). Ezt hívják ún. push parsernek, mikor a parser megy végig az XML-elen, és tolja nekünk az adatokat. Ezt viszonylag nehéz programozni, mert tárolni kell az állapotot, manuálisan kell pl. vermet kezelni, hogy tároljuk, hol tartunk a feldolgozásban. A DOM a teljes XML-t betölti egy faként a memóriába, melyen lehet fabejárást is végezni, sőt tetszőlegesen módosítható is. Ez könnyen használható, a fa adatszerkezetet is a legtöbben ismerik, viszont rengeteg memóriára van szüksége. Ennek feloldására a BEA kezdett el kidolgozni egy API-t, mely a JSR 173 specifikációban lett megfogalmazva, Streaming API for XML címmel.
Célja, hogy egyszerűbben programozható legyen, mint a SAX, de kevesebb memóriát fogyasszon, mint a DOM. Streaming API-nak nevezik, mert a parser XML dokumentumnak csak egy részét látja egyszerre. Itt jön képbe a consume (felemészt) fogalom is, ami azt jelenti, hogy a streamen nem haladhatunk visszafele, így ha egyszer átment rajta a parser, akkor a stream beolvasásra került, tehát ha újra fel akarjuk dolgozni, valamilyen módon biztosítani kell a stream újra rendelkezésre állását (pl. klónozás). Ezen kívül a parsert pull parsernek nevezik, mert a kliens irányítja, ő kéri el az adatokat. Ennek több előnye is van, pl. egyszerre több dokumentumot is lehet párhuzamosan feldolgozni, akár összefésülni az eredményeket, valamint a szálat teljes kontroll alatt lehet tartani, ugyanis akkor szüneteltetjük a végrehajtást, mikor akarjuk. A library is kisebb lesz, és a kliens kód is kisebb lesz.
A StAX további előnye, hogy nem csak olvasni (pl. SAX) képes a
dokumentumokat, hanem írni is képes azokat. A StAX alapvetően két
API-val is rendelkezik, az egyik a cursor API, a másik az iterator API.
E mögötti meggondolás az, hogy inkább két egyszerű API-t készítenek,
mint egy bonyolultat. Az előbbihez az XMLStreamReader
, és
XMLStreamWriter
osztályok tartoznak, míg a másodikhoz az XMLEventReader
és XMLEventWriter
osztályok.
A példa projekt letölthető a GitHubról. Nézzük is a cursor API használatával hogyan dolgoznánk fel a következő XML fájlt:
A kód, mely ezt feldolgozza cursor API használatával:
Látható, hogy először gyártatunk egy XMLInputFactory
példányt, majd
egy XMLStreamReader
példányt. Amíg tart a feldolgozás, addig
feldolgozzuk az adatokat, de mindig mi lépünk a következő adatra a
next()
metódus segítségével (pull API). Az adat típusa, melyen a
reader éppen áll, az XML-nél megszokottak lehetnek: XML deklaráció,
nyitó tag, záró tag, karakterek, megjegyzések, stb. Attól függően, hogy
mi, hívhatjuk meg a reader többi metódusát. Pl. nyitó tag esetén
lekérdezhető a getName
metódussal a neve, vagy getText
metódussal a
tartalma, sőt a getAttribute*
kezdetű metódusokkal az attribútumai is.
A XMLStreamException
kivételt kezelni kell.
Nézzük, hogyan írjunk ki egy hasonló XML dokumentumot:
Nézzük az XML feldolgozást most az iterator API segítségével:
Itt látható, hogy nem közvetlenül a reader
példányt szólítjuk meg,
hanem az event
példányt. Ezt aztán a megfelelő típusra kényszeríteni
kell, és már el is érhetjük a megfelelő metódusait.
Ahhoz, hogy eldöntsük, hogy a kettő közül melyiket érdemes választani, érdemes a következőket a fejben tartani:
- Az iterator API
XMLEvent
osztályai nem módosíthatóak, a parse-olás után is megőrzik az értéküket - Emiatt többlépéses (bővíthető, plug-inelhető) feldolgozásokat is könnyebben ki lehet dolgozni ezen példányok továbbadásával
- A fentiekből következik, hogy a cursor API kevesebb memóriát használ, és a példányosítások hiánya miatt gyorsabb is
- Az
XMLEvent
interfészt akár magunk is implementálhatjuk, akár teljesen új eseményt hozhatunk létre, akár egy meglévőt egészíthetünk ki utility metódusokkal - Az iterator API esetén módosítani is lehet a streamet
Összességében, ha nem a teljesítmény az elsődleges szempont, érdemes a magasabb szintű iterator API-t használni.