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 tutoriáli Java 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 naposledy uvedený
príklad s užívateľmi. Vytvoríme si nový projekt s 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 objektovo správne.
XMLStreamWriter vytvárame pomocou triedy
XMLOutputFactory. Do XML môžeme uložiť
samozrejme aj len jeden objekt (napr. nastavenie), no my si tu ukážeme
uloženie zoznamu niekoľkých objektov.
Pokiaľ budete chcieť uložiť len jeden objekt, úprava bude 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, ktorá 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, aj tu musíme 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 do elementu user vložíme ďalšie dva 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 XML čítať prostredníctvom SAXu.
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é 42x (5.84 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java

David sa informačné technológie naučil na