7. diel - Zápis XML súborov Saxe v Jave
V minulom dieli nášho seriálu tutoriálov pre Javu sme si popísali formát XML. Dnes si v Jave taký súbor vytvoríme pomocou prístupu SAX.
Zápis XML
Poďme si vytvoriť jednoduché XML, využijeme na to minule uvedený príklad s užívateľmi. Vytvorte si nový projekt menom XmlSaxZapis ak projektu pridajte nasledujúci triedu:
public class Uzivatel { private String jmeno; private int vek; private LocalDate registrovan; public static DateTimeFormatter formatData = DateTimeFormatter.ofPattern("d'.'MMMM yyyy H:mm"); public Uzivatel(String jmeno, int vek, LocalDate registrovan){ this.jmeno = jmeno; this.vek = vek; this.registrovan = registrovan; } @Override public String toString() { return getJmeno(); } public String getJmeno() { return jmeno; } public int getVek() { return vek; } public LocalDate getRegistrovan() { return registrovan; } }
Kód budeme pre jednoduchosť písať do metódy main (), len si vyskúšame funkčnosť SAXUM. Z minulých dielov viete, ako sa aplikácia píšu správne objektovo.
XMLStreamWriter vytvárame pomocou triedy XMLOutputFactory. Do XML môžeme uložiť samozrejme i len 1 objekt (napr. Nastavenie), my si tu ukážeme uloženie zoznamu niekoľkých objektov. Ak budete chcieť uložiť objekt len jeden, bude úprava už hračkou
Ako prvý si vytvoríme testovací ArrayList užívateľov:
ArrayList<Uzivatel> uzivatele = new ArrayList<>(); LocalDate datum1 = LocalDate.of(2000, Month.MARCH, 21); LocalDate datum2 = LocalDate.of(2012, Month.OCTOBER, 30); LocalDate datum3 = LocalDate.of(2011, Month.JANUARY, 1); uzivatele.add(new Uzivatel("Pavel Slavík", 22, datum1)); uzivatele.add(new Uzivatel("Jan Novák", 31, datum2)); uzivatele.add(new Uzivatel("Tomáš Marný", 16, datum3));
Teraz vytvoríme inštanciu triedy XMLStreamWriter pomocou XMLOutputFactory, tá samotná sa vytvára továrenské metódou newInstance (). Bohužiaľ nemôžeme použiť blok try-with-resources, pretože ho XMLStreamWriter nepodporuje. Inštanciu ako parameter odovzdáme FileWriter, ako tomu bolo u textových súborov.
XMLOutputFactory xof = XMLOutputFactory.newInstance(); XMLStreamWriter xsw = null; try{ xsw = xof.createXMLStreamWriter(new FileWriter("soubor.xml")); } catch (Exception e){ System.err.println("Chyba při zápisu: " + e.getMessage()); } finally{ try{ if (xsw != null){ xsw.close(); } } catch (Exception e){ System.err.println("Chyba při uzavírání souboru: " + e.getMessage()); } }
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.
Poďme sa pustiť do samotného zápisu. Najprv zapíšeme hlavičku dokumentu:
xsw.writeStartDocument();
Ďalej (ako už vieme) musí nasledovať koreňový element, v ktorom je
celý zvyšok XML obsiahnutý. K 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á. Otvorme
koreňový element, v našom prípade element uzivatele:
xsw.writeStartElement("uzivatele");
Teraz sa dostávame k zápisu jednotlivých užívateľov, ten bude teda prítomný vo foreach cyklu.
Zápis hodnoty do elementu prevedieme pomocou metódy
writeCharacters()
, parametrom je zapisovaná hodnota. Obdobne
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 String previesť. Cyklus a
zápis elementu užívateľ (zatiaľ ešte bez vnorených elementov) bude teda
vyzerať takto:
for (Uzivatel u : uzivatele) { xsw.writeStartElement("uzivatel"); xsw.writeAttribute("vek", Integer.toString(u.getVek())); xsw.writeEndElement(); }
Do programu pripíšeme ešte jeden EndElement k uzavretiu koreňového
elementu a EndDocument k ukončeniu celého dokumentu. Podobne ako u textových
súborov musíme aj tu vyprázdniť buffer metódou flush()
. Celý
kód programu teda teraz vyzerá takto:
// testovací kolekce uživatelů ArrayList<Uzivatel> uzivatele = new ArrayList<>(); LocalDate datum1 = LocalDate.of(2000, Month.MARCH, 21); LocalDate datum2 = LocalDate.of(2012, Month.OCTOBER, 30); LocalDate datum3 = LocalDate.of(2011, Month.JANUARY, 1); uzivatele.add(new Uzivatel("Pavel Slavík", 22, datum1)); uzivatele.add(new Uzivatel("Jan Novák", 31, datum2)); uzivatele.add(new Uzivatel("Tomáš Marný", 16, datum3)); // Zápis uživatelů XMLOutputFactory xof = XMLOutputFactory.newInstance(); XMLStreamWriter xsw = null; try { xsw = xof.createXMLStreamWriter(new FileWriter("soubor.xml")); xsw.writeStartDocument(); xsw.writeStartElement("uzivatele"); for (Uzivatel u : uzivatele) { xsw.writeStartElement("uzivatel"); xsw.writeAttribute("vek", Integer.toString(u.getVek())); xsw.writeEndElement(); } xsw.writeEndElement(); xsw.writeEndDocument(); xsw.flush(); } catch (Exception e) { System.err.println("Chyba při zápisu: " + e.getMessage()); } finally { try { if (xsw != null) { xsw.close(); } } catch (Exception e) { System.err.println("Chyba při uzavírání souboru: " + e.getMessage()); } }
Program si skúsime spustiť a uistíme sa, že všetko funguje. Výstup programu by mal vyzerať takto (zložka s projektom / soubor.xml):
<?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ť. Pod hlavné metódu main()
vytvoríme novú metódu,
ktorú nazveme formatuj(String soubor)
. Tá bude v parametri
prijímať cestu k súboru, ktorý má naformátovať.
private static void formatuj(String soubor) { // TODO sem napíšeme tělo formátovače }
Do tela metódy pridáme nasledujúce riadky:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = factory.newDocumentBuilder(); Document document = builder.parse(new InputSource(new InputStreamReader(new FileInputStream(soubor)))); // Získáme novou instanci transformeru Transformer xformer = TransformerFactory.newInstance().newTransformer(); // Nastavíme formátování pro XML xformer.setOutputProperty(OutputKeys.METHOD, "xml"); // Nastavíme odsazení xformer.setOutputProperty(OutputKeys.INDENT, "yes"); Source source = new DOMSource(document); Result result = new StreamResult(new File(soubor)); xformer.transform(source, result);
Výsledný sformátovaný zápis by mal vyzerať takto:
<?xml version="1.0" ?> <uzivatele> <uzivatel vek="22"></uzivatel> <uzivatel vek="31"></uzivatel> <uzivatel vek="16"></uzivatel> </uzivatele>
Vidíme, že SAX spoznal, že v elemente uzivatel nie je okrem atribútu žiadna hodnota a tak tag vyrenderoval ako nepárový. Teraz vložíme do elementu uzivatel 2 ďalšie elementy, presnejšie jeho atribúty meno a dátum registrácie. K tomu účelu si na triede Uzivatel vytvorme ešte statický DateTimeFormatter:
public static DateTimeFormatter formatData = DateTimeFormatter.ofPattern("d'.'MMMM yyyy H:mm");
Statika je tu dôvodná, je to pomocný formátovač pre prácu s atribútom triedy, ktorý sa hodí sprístupniť aj zvonku.
A kód zápisu v cykle sa rozrastie o:
xsw.writeStartElement("jmeno"); xsw.writeCharacters(u.getJmeno()); xsw.writeEndElement(); xsw.writeStartElement("registrovan"); xsw.writeCharacters(Uzivatel.formatData.format(u.getRegistrovan())); xsw.writeEndElement();
Kód vložíme do miesta zápisu elementu uzivatel, teda medzi jeho
writeAttribute()
a writeEndElement()
. Pre istotu si
ešte uveďme kompletný kód časti s cyklom:
for (Uzivatel u : uzivatele) { xsw.writeStartElement("uzivatel"); xsw.writeAttribute("vek", Integer.toString(u.getVek())); xsw.writeStartElement("jmeno"); xsw.writeCharacters(u.getJmeno()); xsw.writeEndElement(); xsw.writeStartElement("registrovan"); xsw.writeCharacters(Uzivatel.formatData.format(u.getRegistrovan())); xsw.writeEndElement(); xsw.writeEndElement(); }
A máme hotovo. Hotový program je ako vždy k stiahnutiu pod článkom. Nabudúce budeme cez SAX XML čítať.
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é 604x (4.24 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java