8. diel - Čítanie XML súborov Saxe v Jave
V minulej lekcii, Zápis XML súborov Saxe v Jave , sme si predstavili formát XML a ukázali si, ako pomocou SAXUM vytvoriť jednoduché XML. Teraz na minulý diel nadviažeme a napíšeme si proces opačný, teda načítanie XML súboru s používateľmi a zostavenie príslušnej objektovej štruktúry (listu užívateľov).
Pre úplnosť si opäť uvedieme náš XML súbor soubor.xml:
<?xml version="1.0" ?> <uzivatele> <uzivatel vek="22"> <jmeno>Pavel Slavík</jmeno> <registrovan>21.březen 2000</registrovan> </uzivatel> <uzivatel vek="31"> <jmeno>Jan Novák</jmeno> <registrovan>30.říjen 2012</registrovan> </uzivatel> <uzivatel vek="16"> <jmeno>Tomáš Marný</jmeno> <registrovan>1.leden 2011</registrovan> </uzivatel> </uzivatele>
A naši triedu Uzivatel.java:
public class Uzivatel { private String jmeno; private int vek; private LocalDate registrovan; public static DateTimeFormatter formatData = DateTimeFormatter.ofPattern("d'.'LLLL yyyy"); public Uzivatel(String jmeno, int vek, LocalDate registrovan){ this.jmeno = jmeno; this.vek = vek; this.registrovan = registrovan; } @Override public String toString() { return String.format("%s, %d, %s", jmeno, vek, formatData.format(registrovan)); } public String getJmeno() { return jmeno; } public int getVek() { return vek; } public LocalDate getRegistrovan() { return registrovan; } }
Založme si nový projekt, pôjde opäť o konzolovú aplikáciu. Pomenujeme
ju XmlSaxCteni a do zložky s projektom nakopírujeme náš XML súbor.
Vytvorenú triedu oddědíme od triedy
org.xml.sax.helpers.DefaultHandler
. Tým sa nám sprístupní
metódy, ktoré neskôr budeme potrebovať pri parsovanie súboru. K projektu
pripojíme tiež triedu Uzivatel. Užívateľa budeme chcieť načítať do
nejakej kolekcie, vytvorme si teda prázdny ArrayList uzivatele.
private List<Uzivatel> uzivatele = new ArrayList<>();
Konštanty
Než sa presunieme k samotnému čítanie, vytvoríme si pomocnú triedu, v ktorej si uložíme konštanty s názvami jednotlivých elementov v XML súboru:
public final class Konstanty { public static final String UZIVATELE = "uzivatele"; public static final String UZIVATEL = "uzivatel"; public static final String VEK = "vek"; public static final String JMENO = "jmeno"; public static final String REGISTROVAN = "registrovan"; }
Čítanie XML cez SAX
V hlavnej triede si založíme privátne metódu
parsuj(String soubor)
, ktorá bude ako parameter prijímať cestu k
XML súboru:
private void parsuj(String soubor) throws SAXException, IOException, ParserConfigurationException { // TODO zde vyplníme tělo }
V tele tejto metódy "odštartujeme" samotnej parsovanie. Na čítanie XML
cez SAX nám Java poskytuje abstraktné triedu SAXParser
.
Inštanciu tejto triedy získame pomocou továrne, ktorú poskytuje trieda
SAXParserFactory.newInstance().newSAXParser()
. Nad inštancií
parsera jednoducho zavoláme metódu parse()
, ktoré odovzdáme ako
parametre súbor, ktorý chceme naparsovat a handler, ktorý sa o parsovanie
postará. Telo metódy teda bude vyzerať nasledovne:
private void parsuj(String soubor) throws SAXException, IOException, ParserConfigurationException { // Vytvoření instance parseru SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); // Spuštění parsování parser.parse(new File(soubor), this); // Nakonec si uživatele vypíšeme do konzole uzivatele.forEach(System.out::println); }
Pripravíme si pomocné premenné pre atribúty používateľa. Nemôžeme ukladať priamo do inštancie, pretože trieda nemá setter. Druhou možnosťou môže byť Setter pridať, tým ale strácame časť zapuzdrenie. Premenné naplníme východiskovými hodnotami, tie sa dosadí v prípade, že daná hodnota nebude v XML zapísaná. Ďalej si vytvoríme premenné pre indikáciu, že spracovávame vek alebo dátum registrácie:
private String jmeno = ""; private int vek = 0; private LocalDate registrovan = LocalDate.now(); private boolean zpracovavamJmeno = false; private boolean zpracovavamRegistrovan = false;
Teraz prišiel čas prepísať metódy, ktoré nám trieda
DefaultHandler
ponúka. Prepíšeme celkom tri metódy:
startElement()
, endElement()
a
characters()
:
@Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { // Metoda se zavolá vždy, když parser narazí na nový element } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // Metoda se zavolá vždy, když parser narazí na zavírací element } @Override public void characters(char[] ch, int start, int length) throws SAXException { // Metoda se zavolá vždy, když nám parser nabízí přečíst hodnotu mezi elementy }
StartElement ()
V metóde startElement()
nás budú zaujímať predovšetkým
dva parametre: qName
a attributes
. Prvý menovaný
parameter obsahuje názov elementu, ktorý sa práve spracováva. Druhý
obsahuje atribúty spracovávaného elementu. Aby sme zistili, ktorý element sa
zrovna spracováva, použijeme jednoduchý switch
:
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { switch (qName) { case Konstanty.UZIVATEL: // Věk uživatele získáme z atributu uživatele vek = Integer.parseInt(attributes.getValue(Konstanty.VEK)); break; case Konstanty.JMENO: // Pro zpracování jména si musíme uložit indikátor, že zrovna zpracováváme jméno; čtení hodnoty provedeme jinde zpracovavamJmeno = true; break; case Konstanty.REGISTROVAN: // Pro zpracování data registrace si musíme uložit indikátor, že zrovna zpracováváme datum registrace; čtení hodnoty provedeme jinde zpracovavamRegistrovan = true; break; } }
EndElement ()
V metóde endElement()
, ktorá sa volá na pri narazenie na
uzatváracie tag, jednoducho prepneme príslušný indikátor späť na
false
:
public void endElement(String uri, String localName, String qName) throws SAXException { switch (qName) { case Konstanty.JMENO: // Pokud jsme zpracovávali jméno, tak přepněme indikátor jména na false zpracovavamJmeno = false; break; case Konstanty.REGISTROVAN: // Pokud jsme zpracovávali datum registrace, tak přepněme indikátor data registrace na false zpracovavamRegistrovan = false; break; case Konstanty.UZIVATEL: // Pokud jsme přečetli všechna data z uživatele, vytvoříme novou instanci a přidáme ji do kolekce Uzivatel uzivatel = new Uzivatel(jmeno, vek, registrovan); uzivatele.add(uzivatel); break; } }
Characters ()
Posledný metódu, ktorú este potrebujeme vyplniť, je metóda
characters()
, pomocou ktorej budeme čítať hodnotu medzi
elementy. Na zistenie, akú hodnotu práve chceme prečítať, využijeme naše
indikátory. Metóda teda bude vyzerať takto:
public void characters(char[] ch, int start, int length) throws SAXException { // Vytvoříme novou instanci textu String text = new String(ch, start, length); if (zpracovavamJmeno) { // Pokud zpracováváme jméno, tak ho jednoduše přiřadíme jmeno = text; } else if (zpracovavamRegistrovan) { // Pokud zpracováváme datum registrace, tak ho naparsujeme registrovan = LocalDate.parse(text, Uzivatel.formatData); } }
Ak máme veľa atribútov, ktoré musíme načítať, začne
nám metóda characters()
nepríjemne "napučiavať". Alternatívny
spôsob spracovania môže byť pomocou využitia HashMap
y, kedy
si pre spracovanie jednotlivých atribútov vytvoríme lambda funkciu, ktorú
uložíme práve do HashMap
y. Ako kľúč použijeme názov
atribútu. Viac o implementácii si môžete prečítať v článku
sa ZIP súbory.
Tým máme parsovanie hotové. Nakoniec pridáme main()
metódu,
kde vytvoríme novú inštanciu a spustíme parsovanie:
public static void main(String[] args) { try { new XmlSaxCteni().parsuj("soubor.xml"); } catch (SAXException | IOException | ParserConfigurationException e) { e.printStackTrace(); } }
Výsledkom spusteného kódu budú tri načítané mená zo súboru.
Konzolová aplikácia
Pavel Slavík, 22, 21.březen 2000
Jan Novák, 31, 30.říjen 2012
Tomáš Marný, 16, 1.leden 2011
Ak sa vám načítanie príliš nepáčilo, dám vám za pravdu. Kým generovanie nového XML súboru je Saxe veľmi jednoduché a prirodzené, načítanie je naozaj krkolomné. Nabudúce, v lekcii Kvíz - Práca s CSV súbormi a úvod do XML v Jave , sa pozrieme na DOM, teda objektový prístup k XML dokumentu.
V nasledujúcom kvíze, Kvíz - Práca s CSV súbormi a úvod do XML v Jave, si vyskúšame nadobudnuté skúsenosti z predchádzajúcich lekcií.
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é 495x (36.98 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java