7. diel - Zápis XML súborov SAXom v Kotline
V minulom dieli nášho seriálu tutoriálov pre Kotlin, v lekcii Úvod do formátu XML súborov v Kotlin , sme si popísali formát XML.
V dnešnom Kotline tutoriále si vytvoríme XML s niekoľkými užívateľmi
pomocou knižnice SAX, reprezentovanej triedou XMLStreamWriter
.
Inštancie načítame z kolekcie ArrayList
a zapíšeme do XML
súboru.
Zápis XML pomocou SAX
Poďme si vytvoriť jednoduché XML, využijeme na to minule uvedený
príklad s užívateľmi. Vytvoríme si nový projekt menom
XmlSaxZapis
a pridáme k nemu triedu Uzivatel
.
Trieda Uzivatel
Kód triedy Uzivatel
bude jednoduchý:
class Uzivatel(val jmeno: String, var vek: Int, val registrovan: LocalDate) { override fun toString(): String { return jmeno } companion object { var formatData = DateTimeFormatter.ofPattern("d'.'MMMM yyyy")!! } }
U užívateľa evidujeme meno, vek a dátum registrácie. Následne
prepisujeme metódu toString()
, aby vracala meno používateľa.
Nakoniec pripájame formátovanie dátumu.
Ukladanie do súboru
XMLStreamWriter
vytvárame pomocou triedy
XMLOutputFactory
. Do XML môžeme uložiť
samozrejme aj len jeden objekt (napr. nastavenie), my si tu ukážeme uloženie
zoznamu niekoľkých objektov.
Ďalší kód budeme pre jednoduchosť písať do metódy
main()
. Iba si vyskúšame funkčnosť knižnice SAX. Z minulých
dielov vieme, ako sa aplikácia píše správne objektovo.
Najprv si nachystáme súbor, kam budeme objekty ukladať:
// soubor pro uložení xml val soubor = Paths.get(System.getProperty("user.home"), "itnetwork", "soubor.xml") try { Files.createDirectories(soubor.parent) // vytvoří potřebné podadresáře v případě, že neexistují } catch (ex: IOException) { println("Chyba při vytváření potřebných adresářů: " + ex.message) }
Kolekcia používateľov
Ďalej si vytvoríme testovaciu kolekciu ArrayList
užívateľov:
// testovací kolekce uživatelů val uzivatele = ArrayList<Uzivatel>() val datum1 = LocalDate.of(2000, Month.MARCH, 21) val datum2 = LocalDate.of(2012, Month.OCTOBER, 30) val datum3 = LocalDate.of(2011, Month.JANUARY, 1) uzivatele.add(Uzivatel("Pavel Slavík", 22, datum1)) uzivatele.add(Uzivatel("Jan Novák", 31, datum2)) uzivatele.add(Uzivatel("Tomáš Marný", 16, datum3))
Použitie triedy
XMLStreamWriter
Teraz vytvoríme inštanciu triedy XMLStreamWriter
pomocou
XMLOutputFactory
, tá samotná sa vytvára továrenskou metódou
newInstance()
. Žiaľ, nemôžeme použiť blok
try-with-resources
, pretože ho XMLStreamWriter
nepodporuje. Inštanciu ako parameter odovzdáme FileWriter
:
// zápis uživatelů val xof = XMLOutputFactory.newInstance() var xsw: XMLStreamWriter? = null try { xsw = xof.createXMLStreamWriter(FileWriter(soubor.toString(), StandardCharsets.UTF_8)) } catch (e: IOException) { println("Chyba při zápisu: " + e.message) } catch (e: XMLStreamException) { println("Chyba při zápisu: " + e.message) } finally { try { if (xsw != null) { xsw.close() } } catch (e: XMLStreamException) { println("Chyba při uzavírání souboru: " + e.message) } }
Kód je kvôli nemožnosti použiť
try-with-resources
trochu krkolomný, neskôr si ukážeme aj
ďalšie prístupy ku XML dokumentu.
Zápis užívateľov
Poďme sa pustiť do samotného zápisu. Najprv zapíšeme hlavičku dokumentu:
xsw.writeStartDocument()
Ďalej musí nasledovať koreňový element, v ktorom je
celý zvyšok XML obsiahnutý. Na zapisovanie elementov máme metódy
writeStartElement()
a writeEndElement()
. Prvý berie v
atribúte názov elementu, ktorý otvárame. Druhá metóda
spozná názov otvoreného elementu sama z kontextu dokumentu a parametre teda
nemá. Otvoríme koreňový element, v našom prípade element
uzivatele
:
xsw.writeStartElement("uzivatele")
Teraz sa dostávame k zápisu jednotlivých používateľov, ten bude
prebiehať vo foreach
cykle.
Zápis hodnoty do elementu vykonáme pomocou metódy
writeCharacters()
, kedy parametrom je zapisovaná hodnota. Podobne
môžeme elementu pridať atribút metódou writeAttribute()
,
ktorej parametre sú názov atribútu a jeho hodnota.
Hodnota je vždy typu String
, čiže v našom
prípade musíme vek na typ String
previesť.
Cyklus a zápis elementu uzivatel
(zatiaľ ešte bez vnorených
elementov) bude teda vyzerať takto:
for (u in uzivatele) { xsw.writeStartElement("uzivatel") xsw.writeAttribute("vek", u.vek.toString()) xsw.writeEndElement() }
Do programu pripíšeme ešte jeden EndElement
na uzavretie
koreňového elementu a EndDocument
na ukončenie celého
dokumentu. Podobne, ako pri textových súboroch, musíme aj tu vyprázdniť
buffer metódou flush()
.
Celý kód teda teraz vyzerá takto:
// zápis uživatelů val xof = XMLOutputFactory.newInstance() var xsw: XMLStreamWriter? = null try { xsw = xof.createXMLStreamWriter(FileWriter(soubor.toString(), StandardCharsets.UTF_8)) xsw.writeStartDocument() xsw.writeStartElement("uzivatele") for (u in uzivatele) { xsw.writeStartElement("uzivatel") xsw.writeAttribute("vek", u.vek.toString()) xsw.writeEndElement() } xsw.writeEndElement() xsw.writeEndDocument() xsw.flush() } catch (e: IOException) { println("Chyba při zápisu: " + e.message) } catch (e: XMLStreamException) { println("Chyba při zápisu: " + e.message) } finally { try { xsw?.close() } catch (e: XMLStreamException) { println("Chyba při uzavírání souboru: " + e.message) } }
Program si skúsime spustiť a uistíme sa, že všetko funguje. Obsah súboru bude vyzerať takto:
<?xml version="1.0" ?><uzivatele><uzivatel vek="22"></uzivatel><uzivatel vek="31"></uzivatel><uzivatel vek="16"</uzivatel></uzivatele>
Dáta vyzerajú v poriadku, ale formátovanie nie je žiadne. Poďme to napraviť.
Formátovanie XML
Pod hlavnú metódu main()
vytvoríme novú metódu
formatuj()
. Tá bude v parametri prijímať cestu k
súboru, ktorý má naformátovať:
@Throws(IOException::class, ParserConfigurationException::class, TransformerException::class, SAXException::class) private fun formatuj(soubor: String) { // sem napíšeme tělo formátovače }
Do tela metódy pridáme nasledujúce riadky:
val factory = DocumentBuilderFactory.newInstance() val builder = factory.newDocumentBuilder() val document: Document = builder.parse("file:///$soubor") // získáme novou instanci transformeru val xformer: Transformer = TransformerFactory.newInstance().newTransformer() // nastavíme formátování pro XML xformer.setOutputProperty(OutputKeys.METHOD, "xml") // nastavíme odsazení xformer.setOutputProperty(OutputKeys.INDENT, "yes") val source: Source = DOMSource(document) val result = StreamResult(File(soubor)) xformer.transform(source, result)
A na koniec metódy main()
pridáme volanie metódy
formatuj()
:
try { formatuj(soubor.toString()) } catch (ex: IOException) { println("Chyba při formátování souboru: " + ex.message) } catch (ex: ParserConfigurationException) { println("Chyba při formátování souboru: " + ex.message) } catch (ex: TransformerException) { println("Chyba při formátování souboru: " + ex.message) } catch (ex: SAXException) { println("Chyba při formátování souboru: " + ex.message) }
Skontrolujeme, že sa nám zápis správne sformátoval:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <uzivatele> <uzivatel vek="22"/> <uzivatel vek="31"/> <uzivatel vek="16"/> </uzivatele>
Vidíme, že SAX spoznal, že v elemente
uzivatel
nie je okrem atribútu žiadna hodnota a tak tag
vyrenderoval ako nepárový.
Doplnenie atribútov užívateľov
Teraz vložíme do elementu uzivatel
dva ďalšie elementy,
presnejšie jeho atribúty meno a dátum
registrácie.
A kód zápisu v cykle sa zmení na:
xsw.writeStartElement("uzivatel") xsw.writeAttribute("vek", u.vek.toString()) xsw.writeStartElement("jmeno") xsw.writeCharacters(u.jmeno) xsw.writeEndElement() xsw.writeStartElement("registrovan") xsw.writeCharacters(Uzivatel.formatData.format(u.registrovan)) xsw.writeEndElement() xsw.writeEndElement()
Kód vložíme do miesta zápisu elementu uzivatel
, teda medzi
jeho writeAttribute()
a writeEndElement()
.
A máme hotovo. Výsledný súbor vyzerá, ako sme chceli:
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <uzivatele> <uzivatel vek="22"> <jmeno>Pavel Slavík</jmeno> <registrovan>21.March 2000</registrovan> </uzivatel> <uzivatel vek="31"> <jmeno>Jan Novák</jmeno> <registrovan>30.October 2012</registrovan> </uzivatel> <uzivatel vek="16"> <jmeno>Tomáš Marný</jmeno> <registrovan>1.January 2011</registrovan> </uzivatel> </uzivatele>
Hotový program je na stiahnutie pod článkom.
V nasledujúcej lekcii, Čítanie XML súborov SAXom v Kotline , si ukážeme, ako môžeme pomocou SAXu XML súbory čítať a vytvárať potom inštancie užívateľov, ktoré uložíme do kolekcie.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 2x (6.92 MB)
Aplikácia je vrátane zdrojových kódov v jazyku Kotlin