5. díl - Zápis XML souborů SAXem v Javě

Java Práce se soubory Zápis XML souborů SAXem v Javě

V minulém dílu našeho seriálu tutoriálů pro Javu jsme si popsali formát XML. Dnes si v Javě takový soubor vytvoříme pomocí přístupu SAX.

Zápis XML

Pojďme si vytvořit jednoduché XML, využijeme k tomu minule uvedený příklad s uživateli. Vytvořte si nový projekt jménem XmlSaxZapis a k projektu přidejte následující třídu:

public class Uzivatel
{
        private String jmeno;
        private int vek;
        private Calendar registrovan;

        public Uzivatel(String jmeno, int vek, Calendar registrovan)
        {
                this.jmeno = jmeno;
                this.vek = vek;
                this.registrovan = registrovan;
        }

        public String getJmeno() {
        return jmeno;
    }

        public int getVek() {
        return vek;
    }

        public Calendar getRegistrovan() {
        return registrovan;
    }

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

}

Kód budeme pro jednoduchost psát do metody main(), pouze si vyzkoušíme funkčnost SAXu. Z minulých dílů víte, jak se aplikace píší správně objektově.

XMLStreamWriter vytváříme pomocí třídy XMLOutputFactory. Do XML můžeme uložit samozřejmě i jen 1 objekt (např. nastavení), my si zde ukážeme uložení seznamu několika objektů. Pokud budete chtít uložit objekt jen jeden, bude úprava již hračkou :)

Jako první si vytvoříme testovací ArrayList uživatelů:

ArrayList<Uzivatel> uzivatele = new ArrayList<>();
Calendar datum1 = Calendar.getInstance();
datum1.set(2000, Calendar.MARCH, 21);
Calendar datum2 = Calendar.getInstance();
datum2.set(2012, Calendar.OCTOBER, 30);
Calendar datum3 = Calendar.getInstance();
datum3.set(2011, Calendar.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));

Nyní vytvoříme instanci třídy XMLStreamWriter pomocí XMLOutputFactory, ta samotná se vytváří tovární metodou newInstance(). Bohužel nemůžeme použít blok try-with-resources, protože ho XMLStreamWriter nepodporuje. Instanci jako parametr předáme FileWriter, jako tomu bylo u textových souborů. Aby to nebylo moc jednoduché, obalíme výsledek ještě do instance IndentingXMLStre­amWriter, docílíme tím správně naformátovaného výstupu:

XMLOutputFactory xof = XMLOutputFactory.newInstance();
XMLStreamWriter xsw = null;
try
{
        xsw = new IndentingXMLStreamWriter(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žít try-with-resources poněkud krkolomný, později si ukážeme i další přístupy ke XML dokumentu.

Pojďme se pustit do samotného zápisu. Nejprve zapíšeme hlavičku dokumentu:

xsw.writeStartDocument();

Dále (jak již víme) musí následovat kořenový element, ve kterém je celý zbytek XML obsažen. K zapisování elementů máme metody writeStartElement() a writeEndElement(). První bere v atributu název elementu, který otevíráme. Druhá metoda pozná název otevřeného elementu sama z kontextu dokumentu a parametry tedy nemá. Otevřme kořenový element, v našem případě element uzivatele:

xsw.writeStartElement("uzivatele");

Nyní se dostáváme k zápisu jednotlivých uživatelů, ten bude tedy přítomen ve foreach cyklu.

Zápis hodnoty do elementu provedeme pomocí metody writeCharacters(), parametrem je zapisovaná hodnota. Obdobně můžeme elementu přidat atribut metodou writeAttribute(), jejíž parametry jsou název atributu a jeho hodnota. Hodnota je vždy typu String, čili v našem případě musíme věk na String převést. Cyklus a zápis elementu uživatel (zatím ještě bez vnořených elementů) bude tedy vypadat takto:

for (Uzivatel u : uzivatele)
{
        xsw.writeStartElement("uzivatel");
        xsw.writeAttribute("vek", Integer.toString(u.getVek()));
        xsw.writeEndElement();
}

Do programu připíšeme ještě jeden EndElement k uzavření kořenového elementu a EndDocument k ukončení celého dokumentu. Podobně jako u textových souborů musíme i zde vyprázdnit buffer metodou flush(). Celý kód programu tedy nyní vypadá takto:

// testovací kolekce uživatelů
ArrayList<Uzivatel> uzivatele = new ArrayList<>();
Calendar datum1 = Calendar.getInstance();
datum1.set(2000, Calendar.MARCH, 21);
Calendar datum2 = Calendar.getInstance();
datum2.set(2012, Calendar.OCTOBER, 30);
Calendar datum3 = Calendar.getInstance();
datum3.set(2011, Calendar.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 = new IndentingXMLStreamWriter(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 zkusíme spustit a ujistíme se, že vše funguje. Výstup programu by měl vypadat takto (složka s projektem/sou­bor.xml):

<?xml version="1.0" ?>
<uzivatele>
  <uzivatel vek="22"></uzivatel>
  <uzivatel vek="31"></uzivatel>
  <uzivatel vek="16"></uzivatel>
</uzivatele>

Vidíme, že SAX poznal, že v elementu uzivatel není kromě atributu žádná hodnota a tak tag vyrenderoval jako nepárový. Nyní vložíme do elementu uzivatel 2 další elementy, přesněji jeho atributy jméno a datum registrace. K tomu účelu si na třídě Uzivatel vytvořme ještě statický SimpleDateFormat:

public static DateFormat formatData = new SimpleDateFormat("d.MMMM yyyy H:mm");

Statika je zde opodstatněná, je to pomocný formátovač pro práci s atributem třídy, který se hodí zpřístupnit i zvenčí.

A kód zápisu v cyklu se rozroste o:

xsw.writeStartElement("jmeno");
xsw.writeCharacters(u.getJmeno());
xsw.writeEndElement();
xsw.writeStartElement("registrovan");
xsw.writeCharacters(Uzivatel.formatData.format(u.getRegistrovan().getTime()));
xsw.writeEndElement();

Kód vložíme do místa zápisu elementu uzivatel, tedy mezi jeho writeAttribute() a writeEndElement(). Pro jistotu si ještě uveďme kompletní kód části s cyklem:

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().getTime()));
        xsw.writeEndElement();
        xsw.writeEndElement();
}

A máme hotovo. Hotový program je jako vždy ke stažení pod článkem. Příště budeme přes SAX XML číst.


 

Stáhnout

Staženo 396x (17.55 kB)
Aplikace je včetně zdrojových kódů v jazyce java

 

  Aktivity (1)

Článek pro vás napsal David Čápka
Avatar
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (1 hlasů) :
55555


 


Miniatura
Všechny články v sekci
Práce se soubory v Javě
Miniatura
Následující článek
Čtení XML souborů SAXem v Javě

 

 

Komentáře
Zobrazit starší komentáře (2)

Avatar
Hartrik
Redaktor
Avatar
Hartrik:

Pokud někomu nepůjde program zkompilovat jako mě, můžete zkusit vyměnit

xsw = new IndentingXMLStreamWriter(xof.createXMLStreamWriter(new FileWriter("")));

za

xsw = XMLOutputFactory.newInstance().createXMLStreamWriter(new FileWriter(""));

Navíc takto nevzniká odsazení, které pak jen zabírá místo na disku. (u mě to bylo 0.5 z 3 MB)
Rychlost vypadá stejná.

Editováno 3.6.2013 19:09
 
Odpovědět  +2 3.6.2013 19:09
Avatar
Hartrik
Redaktor
Avatar
Hartrik:

aha, už vidím že to byl záměr, tak alespoň víte co dělat když kompilátor nebude moci najít tu třídu :)

 
Odpovědět 3.6.2013 19:16
Avatar
NotBeginner
Neregistrovaný
Avatar
NotBeginner:

Pokud to někomu bude dělat problémy jako mě zde :

xsw = new IndentingXMLStreamWriter(xof.createXMLStreamWriter(new FileWriter("")));

pak řešením je v projektu odebrat JRE systémovou knihovnu a opětovně přidat.

 
Odpovědět 6.1.2014 15:11
Avatar
ucenidolazni
Člen
Avatar
ucenidolazni:

Zdravím všechny :-),
prosím vás chtěl bych se zeptat....pokud ukládám textové záznamy do XML, jak bych měl udělat, aby se každý nový záznam přidal pod již existující a nepřepisoval se ? Možné je to vyřešit že pro každý záznam vytvořím nový XML soubor, ale to by bylo neefektivní. Děkuji všem za odpovědi, už jsem hledal na youtube, google a nemůžu na to přijít :-(. Proto se na vás obracím.
Hezký den.

 
Odpovědět 19.5.2014 14:34
Avatar
ucenidolazni
Člen
Avatar
Odpovídá na ucenidolazni
ucenidolazni:

Mohlo by být vhodné řešení nejprve zápis provést do .txt a poté vždý XML dokument přepsat daty z .txt ?

 
Odpovědět 19.5.2014 14:39
Avatar
Hartrik
Redaktor
Avatar
Odpovídá na ucenidolazni
Hartrik:

Pokud to API opravdu neumožňuje, tak můžeš jednoduše načíst stávající obsah, přidat k němu nový a znovu uložit.

Editováno 19.5.2014 15:13
 
Odpovědět 19.5.2014 15:12
Avatar
ucenidolazni
Člen
Avatar
Odpovídá na Hartrik
ucenidolazni:

Jojo to mě taky došlo, jen mě napadlo jestli není jednodušší způsob :-( No jelikož je to evidence tak budu každý vytvořený záznam ukládat zvlášť jako xml a bude jednodušší pak záznamy mazat...

 
Odpovědět 19.5.2014 16:11
Avatar
Jaroslav Zakouřil:

Ahoj Davide, přetvořil jsem si Tvůj kód pro svou potřebu a v NetBeans funguje perfektně. Já ale potřebuju, aby fungoval v telefonu pod Androidem. A když jsem ho tam přenesl, tak nelze importovat IndentingXMLStre­amWriter, XMLOutputFactory a XMLStreamWriter a jejich metody použité v kódu. Jde to nějak vyřešit nebo musím pro Android použít jiný zápis do souboru ? A pokud ano, tak jaký ? Díky za odpověď. Jarda Zakouřil

 
Odpovědět 17.11.2015 11:14
Avatar
karolko
Člen
Avatar
karolko:

preco nejde ten kod so zanorenim
xsw = new IndentingXMLStre­amWriter(xof.cre­ateXMLStreamWri­ter(new FileWriter("")));

bez zanorenia sa to tako prehliada a kazdy prehliadac mi vypise, ze dokuemnt je zle sformatovany...
som tak trosku beginner, ale mam snahu :)

 
Odpovědět 22. ledna 12:19
Avatar
Jan Kašpar
Člen
Avatar
Odpovídá na karolko
Jan Kašpar:

Změň encoding v nastavení celého svého projektu a pak už nebudeš mít problém se špatným formátováním

Editováno 11. července 9:28
 
Odpovědět 11. července 9:28
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 12. Zobrazit vše