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
