Zarábaj až 6 000 € mesačne! Akreditované rekvalifikačné kurzy od 0 €. Viac informácií.

7. diel - Zápis XML súborov SAXom v Jave

V predchádzajúcom kvíze, Kvíz - Práca s CSV súbormi a úvod do XML v Jave, sme si overili nadobudnuté skúsenosti z predchádzajúcich lekcií.

V dnešnom Java tutoriále si vytvoríme XML s niekoľkými užívateľmi pomocou knižnice SAX, triedou XMLStreamWriter. Inštancie načítame z kolekcie ArrayList a zapíšeme do XML.

Zápis XML

Poďme si vytvoriť jednoduché XML, využijeme na to minule uvedený príklad s užívateľmi. Vytvoríme si nový projekt menom XmlSaxWriting a k projektu pridáme nasledujúcu triedu:

public class User {
    private String name;
    private int age;
    private LocalDate registered;
    public static DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("M/d/yyyy");

    public User(String name, int age, LocalDate registered) {
        this.name = name;
        this.age = age;
        this.registered = registered;
    }

    @Override
    public String toString() {
        return getName();
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public LocalDate getRegistered() {
        return registered;
    }
}

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íšu správne objektovo.

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. Pokiaľ budete chcieť uložiť objekt len jeden, bude úprava už hračkou :)

Najprv si nachystáme súbor, kam budeme objekty ukladať:

Path file = Paths.get(System.getProperty("user.home"), "ictdemy", "file.xml");
try {
    Files.createDirectories(file.getParent()); // creates neccesary directories in case they don't exist
} catch (IOException ex) {
    System.err.println("Error when creating necessary directories: " + ex.getMessage());
}

Hneď nato si vytvoríme testovaciu kolekciu ArrayList užívateľov:

ArrayList<User> users = new ArrayList<>();
LocalDate date1 = LocalDate.of(2000, Month.MARCH, 21);
LocalDate date2 = LocalDate.of(2012, Month.OCTOBER, 30);
LocalDate date3 = LocalDate.of(2011, Month.JANUARY, 1);
users.add(new User("John Smith", 22, date1));
users.add(new User("James Brown", 31, date2));
users.add(new User("Tom Hanks", 16, date3));

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:

XMLOutputFactory xof = XMLOutputFactory.newInstance();
XMLStreamWriter xsw = null;
try {
    xsw = xof.createXMLStreamWriter(new FileWriter(file.toString(), StandardCharsets.UTF_8));
} catch (Exception e) {
    System.err.println("Unable to write the file: " + e.getMessage());
}
finally {
    try {
        if (xsw != null) {
            xsw.close();
        }
    } catch (Exception e) {
        System.err.println("Unable to close the file: " + 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 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 users:

xsw.writeStartElement("users");

Teraz sa dostávame k zápisu jednotlivých užívateľov, ten bude teda prítomný vo foreach cykle.

Zápis hodnoty do elementu vykonáme pomocou metódy writeCharacters(), 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 user (zatiaľ ešte bez vnorených elementov) bude teda vyzerať takto:

for (User u : user) {
    xsw.writeStartElement("user");
    xsw.writeAttribute("age", Integer.toString(u.getAge()));
    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 programu teda teraz vyzerá takto:

// user test collection
ArrayList<User> users = new ArrayList<>();
LocalDate date1 = LocalDate.of(2000, Month.MARCH, 21);
LocalDate date2 = LocalDate.of(2012, Month.OCTOBER, 30);
LocalDate date3 = LocalDate.of(2011, Month.JANUARY, 1);
users.add(new User("John Smith", 22, date1));
users.add(new User("James Brown", 31, date2));
users.add(new User("Tom Hanks", 16, date3));

// writing users
XMLOutputFactory xof = XMLOutputFactory.newInstance();
XMLStreamWriter xsw = null;
try {
    xsw = xof.createXMLStreamWriter(new FileWriter(file.toString(), StandardCharsets.UTF_8));
    xsw.writeStartDocument();
    xsw.writeStartElement("users");

    for (User u : users) {
        xsw.writeStartElement("user");
        xsw.writeAttribute("age", Integer.toString(u.getAge()));
        xsw.writeEndElement();
    }

    xsw.writeEndElement();
    xsw.writeEndDocument();
    xsw.flush();
} catch (Exception e) {
    System.err.println("Unable to write the file: " + e.getMessage());
}
finally {
    try {
        if (xsw != null) {
            xsw.close();
        }
    } catch (Exception e) {
        System.err.println("Unable to close the file: " + e.getMessage());
    }
}

Program si skúsime spustiť a uistíme sa, že všetko funguje. Obsah súboru by mal vyzerať takto:

<?xml version="1.0" ?><users><user age="22"></user><user age="31"></user><user age="16"></user></users>

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 format(). Tá bude v parametri prijímať cestu k súboru, ktorý má naformátovať:

private static void format(String file) {
    //  we'll write the formatter body here
}

Do tela metódy pridáme nasledujúce riadky:

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse("file:///" + file);

// Gets a new transformer instance
Transformer xformer = TransformerFactory.newInstance().newTransformer();

// Sets XML formatting
xformer.setOutputProperty(OutputKeys.METHOD, "xml");

// Sets indent
xformer.setOutputProperty(OutputKeys.INDENT, "yes");
Source source = new DOMSource(document);
Result result = new StreamResult(new File(file));
xformer.transform(source, result);

A na koniec metódy main() pridáme volanie metódy format():

try {
    format(file.toString());
} catch (IOException | ParserConfigurationException | TransformerException | SAXException ex) {
    System.err.println("Error formating file: " + ex.getMessage());
}

Výsledný sformátovaný zápis by mal vyzerať takto:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<users>
  <user age="22"/>
  <user age="31"/>
  <user age="16"/>
</users>

Vidíme, že SAX spoznal, že v elemente user nie je okrem atribútu žiadna hodnota a tak tag vyrenderoval ako nepárový. Teraz vložíme do elementu user dva ďalšie elementy, presnejšie jeho atribúty meno a dátum registrácie.

A kód zápisu v cykle sa rozrastie o:

xsw.writeStartElement("name");
xsw.writeCharacters(u.getName());
xsw.writeEndElement();
xsw.writeStartElement("registered");
xsw.writeCharacters(User.dateTimeFormatter.format(u.getRegistered()));
xsw.writeEndElement();

Kód vložíme do miesta zápisu elementu user, teda medzi jeho writeAttribute() a writeEndElement(). Pre istotu si ešte uveďme kompletný kód časti s cyklom:

for (User u : users) {
    xsw.writeStartElement("user");
    xsw.writeAttribute("age", Integer.toString(u.getAge()));
    xsw.writeStartElement("name");
    xsw.writeCharacters(u.getName());
    xsw.writeEndElement();
    xsw.writeStartElement("registered");
    xsw.writeCharacters(User.dateTimeFormatter.format(u.getRegistered()));
    xsw.writeEndElement();
    xsw.writeEndElement();
}

A máme hotovo. Výsledný súbor by mal vyzerať takto:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<users>
    <user age="22">
        <name>John Smith</name>
        <registered>3/21/2000</registered>
    </user>
    <user age="31">
        <name>James Brown</name>
        <registered>10/30/2012</registered>
    </user>
    <user age="16">
        <name>Tom Hanks</name>
        <registered>1/1/2011</registered>
    </user>
</users>

Hotový program je ako vždy na stiahnutie pod článkom.

Nabudúce, Čítanie XML súborov SAXom v Jave, 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é 0x (5.41 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java

 

Predchádzajúci článok
Kvíz - Práca s CSV súbormi a úvod do XML v Jave
Všetky články v sekcii
Práca so súbormi v Jave
Preskočiť článok
(neodporúčame)
Čítanie XML súborov SAXom v Jave
Článok pre vás napísal David Hartinger
Avatar
Užívateľské hodnotenie:
1 hlasov
David je zakladatelem ITnetwork a programování se profesionálně věnuje 15 let. Má rád Nirvanu, nemovitosti a svobodu podnikání.
Unicorn university David sa informačné technológie naučil na Unicorn University - prestížnej súkromnej vysokej škole IT a ekonómie.
Aktivity