8. diel - Čítanie XML súborov SAXom v Jave
V minulej lekcii, Zápis XML súborov SAXom v Jave, sme si predstavili formát XML a ukázali si, ako pomocou SAXu vytvoriť jednoduché XML.
V dnešnom Java tutoriále si ukážeme načítanie XML súboru s užívateľmi a zostavenie príslušnej objektovej štruktúry (listu užívateľov).
Založme si nový projekt, pôjde opäť o
konzolovú aplikáciu. Pomenujeme ju
XmlSaxReading
.
Súbor file.xml
Do adresára ictdemy
, v domovskom adresári, nakopírujeme tento
náš XML súbor file.xml
:
<?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>
Trieda User
A tu je naša trieda User
:
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 String.format("%s, %d, %s", name, age, dateTimeFormatter.format(registered)); } public String getName() { return name; } public int getAge() { return age; } public LocalDate getRegistered() { return registered; } }
Trieda Constants
Než sa presunieme k samotnému čítaniu, vytvoríme si pomocnú triedu
nazvanú Constants
, v ktorej si uložíme konštanty s názvami
jednotlivých elementov v XML súbore:
public final class Constants { public static final String USERS = "users"; public static final String USER = "user"; public static final String AGE = "age"; public static final String NAME = "name"; public static final String REGISTERED = "registered"; }
Trieda XmlSaxReading
Vytvorenú triedu XmlSaxReading
oddedíme od triedy
org.xml.sax.helpers.DefaultHandler
. Tým sa nám sprístupnia
metódy, ktoré neskôr budeme potrebovať pri parsovaní súboru. K projektu
pripojíme aj triedu User
. Užívateľa budeme chcieť načítať
do nejakej kolekcie, vytvorme si teda prázdny list ArrayList
nazvaný users
.
private final List<User> users = new ArrayList<>();
Pripravíme si pomocné premenné pre atribúty používateľa. Nemôžeme ukladať priamo do inštancie, pretože trieda nemá settery.
Druhou možnosťou môže byť settery pridať, tým ale strácame časť zapuzdrenia.
Premenné naplníme predvolenými hodnotami, tie sa dosadia 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 name = ""; private int age = 0; private LocalDate registered = LocalDate.now(); private boolean processingName = false; private boolean processingRegistered = false;
Metóda parse()
V hlavnej triede XmlSaxReading
si založíme privátnu metódu
parse()
, ktorá bude ako parameter prijímať cestu k XML
súboru v podobe inštancie triedy Path
:
private void parse(Path file) throws SAXException, IOException, ParserConfigurationException { // TODO implement the method body }
V tele tejto metódy odštartujeme samotné parsovanie. Na čítanie XML
pomocou SAX nám Java poskytuje abstraktnú triedu SAXParser
.
Inštanciu tejto triedy získame pomocou metódy newSAXParser()
,
ktorú poskytuje továrenská trieda SAXParserFactory
, ktorej
inštanciu získame zavolaním SAXParseFactory.newInstance()
. Nad
inštanciou parseru jednoducho zavoláme metódu parse()
, ktoré
odovzdáme ako parametre súbor, ktorý chceme naparzovať a handler, ktorý sa
o parsovanie postará.
Telo metódy teda bude vyzerať nasledovne:
private void parse(Path file) throws SAXException, IOException, ParserConfigurationException { // Create of a instance of a parser SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); // Start parsing parser.parse(file.toFile(), this); // Print the users to the console users.forEach(System.out::println); }
Metódy
startElement()
, endElement()
a
characters()
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 { // This method is called every time the parser finds a new element } @Override public void endElement(String uri, String localName, String qName) throws SAXException { // This method is called every time the parser finds a closing tag } @Override public void characters(char[] ch, int start, int length) throws SAXException { // This method is called every time the parser offers us to read the element value }
Metóda 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
práve spracováva, použijeme jednoduchý switch
:
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { switch (qName) { case Constants.USER: // We'll get the user's age from the attribute age = Integer.parseInt(attributes.getValue(Constants.AGE)); break; case Constants.NAME: // To process the name, we need to store an information we're processing it since we'll read the value at a different place processingName = true; break; case Constants.REGISTERED: // To process the registration date, we need to store a similar information processingRegistered = true; break; } }
Metóda endElement()
V metóde endElement()
, ktorá sa volá na pri stretnutí s
uzatváracím tagom, jednoducho prepneme príslušný indikátor späť na
false
:
public void endElement(String uri, String localName, String qName) throws SAXException { switch (qName) { case Constants.NAME: // If we were processing the name, we'll set this indicator to false processingName = false; break; case Constants.REGISTERED: // If we were processing the registration date, we'll set this indicator to false processingRegistered = false; break; case Constants.USER: // If we've read all the user data, we can create a new user instance and add it to the collection User user = new User(name, age, registered); users.add(user); break; } }
Metóda characters()
Poslednou metódou, ktorú ešte potrebujeme vyplniť, je metóda
characters()
, pomocou ktorej budeme čítať hodnotu medzi
elementmi. 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 { // We create a new String instance String text = new String(ch, start, length); if (processingName) { // When processing the name, we simple assign it name = text; } else if (processingRegistered) { // When processing the registration date, we parse it registered = LocalDate.parse(text, User.dateTimeFormatter); } }
Pokiaľ máme veľa atribútov, ktoré musíme načítať,
začne nám metóda characters()
nepríjemne „pučať“.
Alternatívny spôsob spracovania môže byť pomocou využitia kolekcie typu
HashMap
, kedy si pre spracovanie jednotlivých atribútov
vytvoríme lambda funkciu, ktorú uložíme práve do kolekcie typu
HashMap
. Ako kľúč použijeme názov atribútu. Viac o
implementácii si môžete prečítať v článku
so ZIP súbormi.
Metóda main()
Nakoniec pridáme main()
metódu, kde vytvoríme novú
inštanciu a spustíme parsovanie:
public static void main(String[] args) { Path file = Paths.get(System.getProperty("user.home"), "ictdemy", "file.xml"); try { new XmlSaxReading().parse(file); } catch (SAXException | IOException | ParserConfigurationException e) { e.printStackTrace(); } }
Testovanie
Výsledkom spusteného kódu budú tri načítané mená zo súboru:
Konzolová aplikácia
John Smith, 22, 3/21/2000
James Brown, 31, 10/30/2012
Tom Hanks, 16, 1/1/2011
Pokiaľ sa vám načítanie príliš nepáčilo, dám vám za pravdu. Zatiaľ čo generovanie nového XML súboru je SAXom veľmi jednoduché a prirodzené, načítanie je naozaj krkolomné.
V budúcej lekcii Čítanie a zápis XML súborov pomocou DOM v Jave, sa pozrieme na DOM, teda objektový prístup k XML dokumentu.
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.82 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Java