31
SVEUČILIŠTE U ZAGREBU FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA SEMINAR Upotreba XML-a u Javi Ivor Herak Voditelj: mr. sc. Marko Čupić Zagreb, svibanj, 2007

Dom - XML Seminar Ski

Embed Size (px)

Citation preview

Page 1: Dom - XML Seminar Ski

SVEUČILIŠTE U ZAGREBU

FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA

SEMINAR

Upotreba XML-a u Javi

Ivor Herak

Voditelj: mr. sc. Marko Čupić

Zagreb, svibanj, 2007

Page 2: Dom - XML Seminar Ski

Sadržaj

1. Uvod.....................................................................................................................1

1.1 Povijest XML-a..............................................................................................1

2. Osnove XML-a .....................................................................................................3

2.1 Osnovni pojmovi XML dokumenata...............................................................3

2.2 Sintaksna pravila XML-a ...............................................................................2

3. XML u Javi ...........................................................................................................4

3.1 SAX analizator ..............................................................................................4

3.2 DOM analizator ...........................................................................................10

3.3 Apache Digester..........................................................................................13

4. Literatura ............................................................................................................18

5. Sažetak ..............................................................................................................20

Page 3: Dom - XML Seminar Ski

Upotreba XML-a u Javi

1

1. Uvod

U ovom seminaru bit će objašnjeno što je XML, koje su njegove karakteristike i za što se koristi, i to na način razumljiv početnicima – ljudima koji se susreću s XML-om prvi puta u životu. Takoñer će se razmatrati uporaba XML-a u Javi, prvo pomoću standardnih XML analizatora, a kasnije i sa Apache Digester alatom. Bit će prikazano puno primjera koji će biti detaljno objašnjeni.

1.1 Povijest XML-a

XML je kratica od ''extensible markup language''. ''Extensible'' u prijevodu znači rastezljiv ili fleksibilan, dok je ''markup language'' jezik koji u sebi kombinira neki tekst i informacije o tom tekstu. Princip zapisa podataka u XML-u je vrlo jednostavan: odgovarajući podatci se uokviruju oznakama koje ga opisuju i imaju poznato, ili lako shvatljivo značenje. XML je bio dizajniran da bude relativno čitak i nastao je kao pojednostavljeni podskup SGML-a, metajezika koji je definirao takve ''markup language''-e. XML je izmislila radna grupa od jedanaest članova World Wide Web konzorcija. Najvažnije odluke su donesene u 20 tjedana intenzivnog rada izmeñu 7. i 11. mjeseca 1996, kada je izašla prva verzija. Grupa se nikada nije susrela uživo, već je sav posao obavljala preko e-maila i telekonferencija. Završni proizvod je opravdao očekivanja radne grupe: moglo ga se koristiti u općenite svrhe, moglo ga se koristiti na Internetu, bio je kompatibilan s SGML-om, a bio je čitak i koncizan. W3C (World Wide Web konzorcij) , glavna meñunarodna organizacija za standarde za World Wide Web, je 10. veljače 1998. objavio prvu verziju XML preporuke. Trenutno postoje dvije verzije XML-a. Verzija 1.0, koja je trenutno u 4. ediciji, je vrlo rasprostranjena i preporučuje se za opću uporabu, dok verzija 1.1 nije široko rasprostranjena. Glavna razlika je u tome što XML 1.0 dopušta uporabu samo onih znakova koji su definirani u Unicode 2.0, dok XML 1.1 dopušta uporabu skoro svih znakova. Preporučuje se uporaba verzije 1.0, ako posebne karakteristike dostupne u verziji 1.1 nisu potrebne.1

Zbog načina na koji je realiziran, XML ima veliki broj korisnih prednosti. Jedna od njegovih najvažnijih prednosti jest to što ga jednako dobro mogu razumjeti i stroj i čovjek, takoñer podržava Unicode, samim time i gotovo sve znakove poznate čovjeku. Zbog svoje hijerarhijske organizacije XML može predstavljati neke od najvažnijih struktura podataka računarske znanosti, kao što su liste i stabla. On ima i vrlo strogu sintaksu koja omogućuje da algoritmi za analiziranje budu relativno jednostavni. Ujedno, u svojoj osnovi XML dokument je obična datoteka koja sadrži neki tekst, te se može prepoznati na bilo kojoj platformi i, budući da je usklañen s meñunarodnim normama, može se koristiti bilo gdje u svijetu. No uz tako puno prednosti mora doći i par nedostataka. Jedan od većih nedostataka je to što je XML kodiranje podataka relativno veliko u usporedbi s binarnom reprezentacijom tih istih podataka što ima za posljedicu da je obrañivanje dokumenta puno sporije. Takoñer nije definiran niti

1 http://en.wikipedia.org/wiki/XML

Page 4: Dom - XML Seminar Ski

Upotreba XML-a u Javi

2

jedan tip podataka tako da se jednako predstavljaju npr. cijeli broj (integer) i običan tekst (string).

Zbog toga što ga bilo koja platforma može prepoznati, kao i zbog činjenice da opisuje podatke koje sadrži, XML je izrazito pogodan za razmjenu podataka izmeñu dva sustava. Isto tako XML se može koristiti i za pohranjivanje podataka. Podatci se pohranjuju na disku u obliku tekstualne datoteke koja se onda može pročitati ili običnim ureñivačem teksta ili nekim posebnim programom za rad s XML dokumentima. Takoñer se može koristiti i za ''DocumentDriven Programming'', gdje sadrži reference na odreñene komponente aplikacije koje se onda spajaju u jedno, ali se time ovdje nećemo previše baviti.

U drugom poglavlju bit će obrañeni neki pojmovi koji su nužni za pravilno razumijevanje XML dokumenata, kao što su elementi i atributi. Takoñer će biti navedena i objašnjena najvažnija sintaksna pravila koja moraju vrijediti za svaki XML dokument. Treće poglavlje se bavi načinima na koje se može pristupati XML dokumentima u programskom jeziku Java. U sklopu toga obrañuju se SAX i DOM API, čija će upotreba biti demonstrirana na primjerima. Osim toga, objasnit će se princip rada alata Apache Digester te će njegova funkcionalnost biti prikazana na jednostavnom primjeru. U četvrtom poglavlju bit će ukratko izneseni najvažniji zaključci ovog seminara dok je u petom poglavlju popis korištene literature. U zadnjem poglavlju je napravljen kratak sažetak svega što je obrañeno u radu. Seminar sadrži i dodatak u kojem se nalaze izvorni kodovi svih primjera.

Page 5: Dom - XML Seminar Ski

Upotreba XML-a u Javi

3

2. Osnove XML-a

U ovom poglavlju bit će riječi o osnovnim pojmovima vezanim uz XML dokumente (elementi, atributi i entiteti), te koje uvjete moraju zadovoljavati svi takvi dokumenti. To sve bit će demonstrirano na primjerima.

2.1 Osnovni pojmovi XML dokumenata

Svaki XML dokument sastoji se od 2 glavna dijela. Prvi dio zove se prolog i u njemu se navode podatci koja se verzija koristi te koja kodna stranica:

<?xml version="1.0" encoding="utf-8" ?>

Nakon prologa slijedi sadržaj dokumenta. U tom se dijelu nalaze podatci koje dokument sadrži. Kao što je već prije rečeno, podatci se uokviruju oznakama. Slijedi primjer pohrane podataka o nekoj knjizi:

<knjiga>

<naziv>Trojica u Trnju</naziv>

<autor>Pavao Pavličić</autor>

<izdavač>Mladost</izdavač>

</knjiga>

Elementi opisuju odreñeni dio XML dokumenta, sastoje se od korisnog sadržaja omeñenog oznakama. Primjer elementa:

<poruka>Ovo je zanimljivo</poruka>

Ovdje je <poruka> početna oznaka, </poruka> završna oznaka, a "Ovo je zanimljivo" je sadržaj elementa. Imena oznaka (elemenata) mogu sadržavati brojeve, slova i posebne znakove. No, ima par pravila glede imena oznaka: imena moraju započinjati tekstom, ne smiju započinjati tekstom XML ili xml, te ne smiju sadržavati praznine. Takoñer se preporučuje izbjegavanje uporabe znakova . i – u imenima. Svaka početna oznaka mora imati odgovarajuću završnu oznaku istog imena. U protivnom će analizator koji obrañuje dokument javiti grešku (iznimka su prazne oznake o kojima će biti riječi kasnije). Znači, u općenitom slučaju, to izgleda ovako:

<oznaka>

Neki sadržaj ili ugniježñeni elementi

</oznaka>

Oznake mogu imati bilo koje ime koje odreñuje sadržaj elementa. Elementi unutar svojeg sadržaja mogu imati ugniježñene druge elemente. Za razliku od HTML-a u kojem se oznake odreñuju kako se sadržaj prikazuje, u XML-u oznake identificiraju sadržaj. Elementi takoñer mogu sadržavati atribute. Atributi se definiraju nakon početne oznake i njihove se vrijednosti upisuju unutar dvostrukih navodnika. U ovom slučaju atribut pošiljatelj govori tko je poslao poruku:

<poruka pošiljatelj="Marko">

Ovo je zanimljivo

</poruka>

Page 6: Dom - XML Seminar Ski

Upotreba XML-a u Javi

4

Postoje velike rasprave o tome kada se trebaju koristiti atributi, a kada elementi. Umjesto atributa pošiljatelj, mogli smo napraviti novi ugniježñeni element koji bi imao istu informaciju (<pošiljatelj>Marko</pošiljatelj>). Postoje 2 glavne struje u svezi s ovim pitanjem. Prva struja se zalaže za ''čistoću elemenata'' tj. oni propagiraju korištenje elemenata umjesto atributa, osim u slučajevima kada se radi o informacijama koje ne obogaćuju sadržaj (kao npr. font kojim se ova poruka treba ispisati), dok druga struja smatra da se atributi mogu koristiti za dodavanje korisnih informacija jer se time smanjuje inflacija elemenata.2

XML komentari se mogu pojavljivati na bilo kojem mjestu u XML dokumentu. Njihova sintaksa je:

<!-- Ovo je komentar. -->

Takoñer, XML dokument može sadržavati prazne elemente, takve oznake stoje same za sebe i ne uokviruju nikakav sadržaj:

<poruka pošiljatelj="Marko">

<važno/>

<tekst>Ovo je zanimljivo</tekst>

</poruka>

U gornjem smo primjeru praznu oznaku koristili kako bismo naglasili da je ova poruka važna. Isti bismo rezultat postigli da smo napisali <važno></važno>, ali bismo morali više pisati.

Entitet u XML-u je bilo kakva XML struktura koja ima ime. Kada se referenciramo na neki entitet preko imena, to ima za posljedicu da se na mjesto referenciranja ubaci tekst tog entiteta. Sintaksa referenciranja entiteta je:

&imeEntiteta;

XML ima odreñen broj predefiniranih entiteta. Način na koji se oni referenciraju i znak koji predstavljaju dan je u tablici 1.

<izvještaj>Prodaja < Troškovi</izvještaj>

Analizator koji obrañuje dokument nakon znaka '<' očekuje ime nove početne oznake, pa dolazi do greške jer analizator nije naišao na odgovarajuću završnu oznaku. Ispravan način zapisivanja gore navedenog teksta je:

<izvještaj>Prodaja &lt; Troškovi</izvještaj>

2 http://hr.wikipedia.org/wiki/XML

Page 7: Dom - XML Seminar Ski

Upotreba XML-a u Javi

5

Tablica 1. Predefinirani entiteti

Znak Referenca & &amp; < &lt; > &gt; " &quot; ' &apos;

Kada se koristi puno specijalnih znakova, nije baš praktično svakog od njih zamijeniti odgovarajućim referencama. U tim se slučajevima koristi CDATA odsječak. Tekst koji se nalazi u CDATA odsječku analizator neće tretirati kao XML tekst, već će ga pohraniti baš onakvog kakav jest. Sintaksa CDATA odsječka je:

<![CDATA[ tekst pun posebnih znakova ]]>

CDATA odsječci se najčešće upotrebljavaju kada se zapisuju odreñeni grafovi ili skice3. Sljedeći primjer neće izazvati grešku analizatora:

<skica><![CDATA[Skica:

Stanica - > Atom - > Subatomske čestice

]]></skica>

U XML dokumentu ponekad može doći do sukoba imena elemenata. Sukob imena elemenata predstavlja veliki problem pri analizi dokumenta ako je ime elementa upotrijebljeno u dva različita konteksta, primjerice:

<posuda>

<sadrži>jabuka</sadrži>

<sadrži>banana</sadrži>

</posuda>

<posuda>

<radius>25cm</radius>

<debljina>2cm</debljina>

</posuda>

Ovdje se element posuda javlja u dva različita konteksta; u prvom slučaju se popisuje što sadrži posuda, a u drugom slučaju se opisuju njene dimenzije. Kao što je već prije rečeno, ovo je veliki problem pri analizi dokumenta. XML Namespace nam omogućava da koristimo ista imena elemenata, ali iz različitih XML vokabulara. Svakom elementu možemo deklarirati namespace pomoću rezerviranog atributa xmlns čija vrijednost mora biti URI – skup znakova

3 http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/4_refs.html

Page 8: Dom - XML Seminar Ski

Upotreba XML-a u Javi

1

kojim identificiramo neki resurs. Ako sada svakom elementu <posuda> dodijelimo različiti namespace, sukob imena neće nastupiti4:

<posuda xmlns="http://www.w3.org/TR/html4/">

<sadrži>jabuka</sadrži>

<sadrži>banana</sadrži>

</posuda>

<posuda xmlns="http://www.w3schools.com/furniture">

<radius>25cm</radius>

<debljina>2cm</debljina>

</posuda>

Takoñer namespace naveden za element <posuda> vrijedi i za svu njegovu djecu. Namespace možemo takoñer zadati i pomoću prefiksa, tada sva djeca s istim prefiksom takoñer koriste taj namespace:

<f:posuda xmlns:f="http://www.w3schools.com/furniture">

<f:radius>25cm</f:radius>

<f:debljina>2cm</f:debljina>

</f:posuda>

Koristeći dosad usvojena znanja možemo napraviti prvi malo ozbiljniji XML dokument, primjerice dokument koji sadrži podatke o pjesmama na nekom kompilacijskom CD-u:

<?xml version="1.0" encoding="utf-8" ?>

<!-- Popis pjesama -->

<glazba>

<pjesma id="1">

<ime>Space Oddity</ime>

<izvoñač>David Bowie</izvoñač>

</pjesma>

<pjesma id="2">

<ime>Dirty Harry</ime>

<izvoñač>Gorillaz</izvoñač>

</pjesma>

</glazba>

4 http://www.w3schools.com/xml/xml_namespaces.asp

Page 9: Dom - XML Seminar Ski

Upotreba XML-a u Javi

2

2.2 Sintaksna pravila XML-a

Svaki XML dokument mora zadovoljavati 2 glavna uvjeta : on mora biti dobro formiran (well-formed) i mora biti valjan (valid). Prvi uvjet zahtijeva da svaka početna oznaka bude terminirana odgovarajućom završnom (o tome je već bilo riječi kod objašnjavanja elemenata). Takoñer zahtijeva da elementi u dokumentu budu hijerarhijski organizirani ili ugniježñeni, tj. da jedan element bude potpuno sadržan u nekom drugom elementu i da postoji jedan element koji u sebi sadrži sve druge elemente – korijenski ili root element. Ovaj smo uvjet poštivali u svim dosadašnjim primjerima. Ovaj kod je netočan, jer elementi nisu pravilno ugniježñeni:

<poruka>

<tekst>Neka poruka.</poruka>

</tekst>

Da bismo razumjeli uvjet valjanosti, moramo objasniti što su to sheme. U XML-u sheme se koriste kako bi se unaprijed odredilo koje elemente taj dokument smije sadržavati i u kojem odnosu oni moraju biti. Može se propisati i koje atribute smiju imati odreñeni elementi i koje oznake smiju biti prazne. Dvije najpoznatije vrste shema su DTD (Document Type Definition) i XML shema. DTD se koristi za jednostavnije dokumente jer ne može prikazati složenije odnose meñu elementima, a XML shema, iako može prikazati složene odnose meñu elementima, nije baš praktična jer zahtijeva dosta vremena da bi se izradila. Dokument sheme navodi se u prologu dokumenta. Atribut standalone označava da dokument koristi neke datoteke koje nisu definirane unutar samog dokumenta:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>

<!DOCTYPE glazba SYSTEM "Shema.dtd">

Napravit ćemo shemu za primjer sa glazbom u kojoj ćemo definirati gdje će se nalaziti podatci i koje ćemo elemente koristiti u dokumentu

<?xml version="1.0" encoding="utf-8"?>

<!ELEMENT glazba (pjesma+)>

<!ELEMENT pjesma (ime,izvoñač)>

<!ATTLIST pjesma id CDATA #REQUIRED>

<!ELEMENT ime (#PCDATA)>

<!ELEMENT izvoñač (#PCDATA)>

U prvom redu sheme deklariramo verziju koju koristimo i kodnu stranicu. U sljedećem retku odreñujemo da unutar elementa <glazba> može biti jedan ili više ugniježñenih elemenata <pjesma>, to odreñuje operator plus, u tablici 2 je dan popis svih operatora i njihovo značenje.

Tablica 2. Operatori u DTD shemi

Operator Značenje ? nula ili jedan * nula ili više + jedan ili više

Page 10: Dom - XML Seminar Ski

Upotreba XML-a u Javi

3

Nakon toga u sljedećem retku odreñujemo da se unutar elementa pjesma nalazi po jedan element ime i element izvoñač. Poslije toga definiramo da pjesma ima jedan atribut id i sa ključnom riječi #REQUIRED kažemo da taj atribut mora imati svaka pjesma. Ostale ključne riječi tog tipa i njihova značenja prikazana su u tablici 3.

Tablica 3. Ključne riječi DTD sheme

Ključna riječ Značenje #REQUIRED Element mora imati taj atribut odreñen u dokumentu. #IMPLIED Element ne mora imati taj atribut odreñen u dokumentu.

"defaultValue" Početna vrijednost, koristi se ako atribut nije odreñen u dokumentu

#FIXED "fixedValue"

Fiksirana vrijednost. Vrijednost odreñena u dokumentu mora biti ista

CDATA odreñuje da se radi o običnom tekstu. U sljedeća dva retka se propisuje da elementi ime i izvoñač nemaju ugniježñenih drugih elemenata već da sadrže tekst koji nosi informaciju. PCDATA (parsed character dana) označava upravo to, dok # označava da slijedi ključna riječ, a ne ime nekog elementa5.

Iz ovog kratkog primjera sheme vidljiv je i najveći nedostatak DTD sheme. Budući da se za svaki element samo jednom definira što može sadržavati, DTD ne prepoznaje kontekst u kojem se odreñen element pojavljuje. To stvara probleme kada se koriste elementi koji se isto zovu, ali u različitom kontekstu i ulogama.

Za dokument kažemo da je valjan kada je napravljen prema odreñenim semantičkim pravilima koja su definirana ili u shemi koju je napravio korisnik ili u XML shemi. Npr. XML dokument koji sadrži neku oznaku koja nije definirana u shemi ne smatra se valjanim.

5 http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/5a_dtd.html

Page 11: Dom - XML Seminar Ski

Upotreba XML-a u Javi

4

3. XML u Javi

U ovom poglavlju upoznat ćemo se sa standardnim načinom analize (parsiranja) XML dokumenata u programskom jeziku Java. Poslije toga proučit ćemo malo napredniji način obrade pomoću alata Apache Digester.

3.1 SAX analizator

SAX (Simple API for XML) je skup API –a koji obrañuju XML dokument serijski – element po element. Razredi koje sadrži SAX API i načini na koji meñudjeluju dan je na slici 1. Sve počinje od razreda SAXParserFactory koja se koristi za generiranje instance razreda SAXParser. Proces analize počinje pozivom odgovarajuće parse metode tog razreda. Tada će analizator početi čitati XML dokument i zvati odreñene metode za svaki dogañaj na koji naiñe u dokumentu. Te metode koje analizator zove pri analizi definirane su sučeljima ContentHandler, ErrorHandler, DTDHandler i EntityResolver. Na nama je da te metode implementiramo i na taj način odredimo kako će se analizator ponašati pri svakom dogañaju. Takoñer je definiran razred Default Handler koji ima implementirane sve metode od gore spomenuta 4 sučelja sa metodama koje ništa ne rade. Pomoću tog razreda možemo implementirati samo one metode koje nas zbilja zanimaju, tako da 'pregazimo' njihovu implementaciju u Default Handler-u. Obično se metodi parse preko argumenata predaje dokument koji parsiramo i instanca razreda Default Handler. ContentHandler ima definirane metode koje se pozivaju na početku i na kraju samog dokumenta, te metode koje se pozivaju na početku i na kraju elemenata. ErrorHandler sadrži metode koje definiraju ponašanje analizatora pri pojavi grešaka. DTDHandler ima metode za procesiranje DTD sheme, a EntityResolver metode koje se pozivaju pri referenciranju nekog entiteta zadanog pomoću URI –a6.

6 http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/index.html

Page 12: Dom - XML Seminar Ski

Upotreba XML-a u Javi

5

Slika 1. SAX API

Uporabu SAX analizatora prikazat ćemo na vrlo jednostavnom primjeru. Napravit ćemo program koji će ispisati sadržaj XML dokumenta na ekran (točnije System.out). Počet ćemo sa stvaranjem novog razreda, nazovimo ga Echo, koji će nasljeñivati sve metode razreda Default Handler. Metode koje bismo željeli implementirati su:

startDocument() – metoda koja se poziva na početku dokumenta

endDocument() – metoda koja se poziva na kraju dokumenta

startElement() – metoda koja se poziva kod početne oznake nekog elementa

endElement() – metoda koja se poziva kod završne oznake nekog elementa

characters() – metoda koja se poziva kada analizator naiñe na podatke

Pri izradi ovog programa moramo imati na umu da analizator tabulatore, koje mi koristimo kako bi dokument bio što pregledniji, interpretira isto kao znakove koji nose odreñenu informaciju. To je zbog toga što nismo definirali shemu, pa analizator ne zna gdje treba očekivati podatke. Ta činjenica može uzrokovati neželjeno ponašanje našeg programa, zato ćemo indentaciju rješavati pomoću privatne varijable brojIndentacije i metode indentiraj().

private int brIndentacija = 0;

public void indentiraj(){

for (int i = 0; i < brIndentacija; i++){

System.out.print(" ");

}

}

Page 13: Dom - XML Seminar Ski

Upotreba XML-a u Javi

6

Krenimo od najjednostavnijih metoda, metoda startDocument() i endDocument(), na početku samo ispisujemo oznaku ''POČETAK:'', a na kraju oznaku ''KRAJ'':

public void startDocument(){

System.out.println("POČETAK:");

System.out.println("<?xml version='1.0' encoding='UTF-8'?>");

}

public void endDocument(){

System.out.println("KRAJ");

}

Metoda startElement() ima četiri argumenta. Nama trebaju samo posljednja dva: ime elementa i lista njegovih atributa. Prva dva argumenta se upotrebljavaju kada dokument koristi namespace tj. alat pomoću kojeg se sprečavaju 'sukobi imena'. No, nama to neće trebati pa se time više nećemo baviti. Sam kod, uz objašnjene argumente, je prilično jasan:

public void startElement(String namespaceURI, String sName,

String ime, Attributes atributi) {

indentiraj();

System.out.print("ELEMENT:<" + ime);

this.brIndentacija++;

if (atributi != null) {

for (int i = 0; i < atributi.getLength(); i++) {

System.out.print(" " + atributi.getQName(i) +

"=" + atributi.getValue(i));

}

}

System.out.println(">");

}

Metoda endElement() ima tri argumenta. Nama je potreban samo posljednji, ime elementa, dok se ostali argumenti upotrebljavaju kada dokument koristi namespace.

Page 14: Dom - XML Seminar Ski

Upotreba XML-a u Javi

7

public void endElement(String namespaceURI,

String sName, String ime) {

this.brIndentacija--;

indentiraj();

System.out.print("KRAJ_EL:");

System.out.println("</" + ime + ">");

}

Još nam je preostala metoda characters() koja ima tri argumenta. O argumentima je dovoljno znati da ih možemo proslijediti konstruktoru razreda String te da ćemo na taj način dobiti odgovarajući podatak.

public void characters(char buf[], int offset, int len){

String s = new String(buf, offset, len);

if (!s.trim().equals("")){

indentiraj();

System.out.println("PODATAK: " + s);

}

}

Takoñer ćemo napraviti main metodu koja će stvoriti novu instancu razreda SAXParser i pozvati parse metodu nad XML dokumentom, u ovom slučaju ''Glazba.xml'' koja se spominje u prošlom poglavlju.

public static void main(String[] args){

//deklariramo ovu klasu kao novi DefaultHandler

DefaultHandler handler = new Echo();

//stvaramo novu tvornicu analizatora

SAXParserFactory factory = SAXParserFactory.newInstance();

try{

//stvaramo novi analizator

SAXParser analizator = factory.newSAXParser();

//i analiziramo dokument

analizator.parse("Glazba.xml", handler);

Page 15: Dom - XML Seminar Ski

Upotreba XML-a u Javi

8

}catch(Throwable t){

t.printStackTrace();

}

}

Takoñer je potrebno pozvati i odgovarajuće pakete u kojima se nalaze svi razredi koje upotrebljavamo:

import org.xml.sax.*;

import org.xml.sax.helpers.DefaultHandler;

import javax.xml.parsers.SAXParserFactory;

import javax.xml.parsers.SAXParser;

Kada sve ove dijelove koda spojimo u jednu cjelinu, dobili smo program koji možemo prevesti i pokrenuti. Kompletni kod je dan u dodatku kao ''Primjer 1''. Na ovom primjeru možemo vidjeti par velikih nedostataka pri uporabi SAX analizatora. Najveći nedostatak je to što je za čak ovako banalan primjer potrebno relativno puno kodiranja. Veliki nedostatak je i to što analizator ne prepoznaje kontekst u kojem nailazi na odreñene dogañaje što otežava analizu nekih složenijih dokumenata. Ovaj program je ispravan što potvrñuje i njegov ispis (na sljedećoj strani).

Page 16: Dom - XML Seminar Ski

Upotreba XML-a u Javi

9

POČETAK:

<?xml version='1.0' encoding='UTF-8'?>

ELEMENT:<glazba>

ELEMENT:<pjesma id=1>

ELEMENT:<ime>

PODATAK: Space Oddity

KRAJ_EL:</ime>

ELEMENT:<izvoñač>

PODATAK: David Bowie

KRAJ_EL:</izvoñač>

KRAJ_EL:</pjesma>

ELEMENT:<pjesma id=2>

ELEMENT:<ime>

PODATAK: Dirty Harry

KRAJ_EL:</ime>

ELEMENT:<izvoñač>

PODATAK: Gorillaz

KRAJ_EL:</izvoñač>

KRAJ_EL:</pjesma>

KRAJ_EL:</glazba>

KRAJ

Page 17: Dom - XML Seminar Ski

Upotreba XML-a u Javi

10

3.2 DOM analizator

DOM (Document Object Model) je skup API –a koji obrañuje XML dokument na način da ga cijelog pročita i pohrani u memoriji u obliku stabla što je ilustrirano na slici 2. Svaki čvor tog stabla sadrži neku od komponenti našeg dokumenta. Najčešće su to čvorovi koji sadrže elemente ili čvorovi koji sadrže podatke (tekst). Koristi se razred DocumentBuilderFactory koji onda stvara novu instancu DocumentBuilder –a koji se onda koristi za stvaranje odgovarajućeg DOM stabla u memoriji pozivom metode parse() za neki XML dokument.

Slika 2. DOM API

Napravimo jednostavan program koji će u memoriji stvoriti odgovarajuće stablo za dokument ''Glazba.xml''. Nazovimo ga DomEcho. Izvorni kod se nalazi u dodatku kao ''Primjer 2''.

public class DomEcho {

private static Document dokument;

public static void main(String argv[]){

//stvaramo novu tvornicu

DocumentBuilderFactory factory =

DocumentBuilderFactory.newInstance();

try{

//pomoću tvornice stvaramo novi DocumentBuilder

Page 18: Dom - XML Seminar Ski

Upotreba XML-a u Javi

11

DocumentBuilder builder =

factory.newDocumentBuilder();

//analiziramo dokument

dokument = builder.parse("Glazba.xml");

}catch(Throwable t) {

t.printStackTrace();

}

}

}

Program radi i može ga se prevesti i pokrenuti, no mi nemamo nikakvih dokaza da se u memoriji zapravo stvorila odgovarajuća struktura podataka. Da bismo to provjerili, možemo napraviti program koji će sadržaj DOM stabla ispisivati na ekran pomoću grafičkog sučelja Swing. Kod je vrlo opsežan, te se ovdje neće razmatrati, prikazat ćemo samo rezultat izvoñenja.

Slika 3. DOM stablo kao JTree

Page 19: Dom - XML Seminar Ski

Upotreba XML-a u Javi

12

Kada smo jednom stvorili odgovarajuće DOM stablo u memoriji, možemo pristupiti njegovim čvorovima pomoću razreda org.w3c.dom.Node koji ima definirane metode za dohvaćanje djece i sadržaja čvora. Metode koje imaju čvorovi i vrijednosti koje vraćaju za neke najosnovnije komponente XML dokumenta dane su u tablici 4.

Tablica 4. Metode razreda Node

Čvor nodeName() nodeValue() attributes nodeType() Atribut ime atributa vrijednost atributa null 2 Komentar #comment sadržaj komentara null 8 Element ime oznake null NamedNodeMap 1 Tekst #text tekst (podatci) null 3

Takoñer za svaki čvor možemo pozvati metodu getChildNodes() koja vraća djecu tog čvora. Pomoću svih tih metoda možemo obraditi neki XML dokument na koji god način želimo. DOM analizator je jednostavniji za uporabu od SAX analizatora, ali zahtijeva više memorije jer cijelo vrijeme mora imati pohranjeno DOM stablo.7

7 http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/dom/index.html

Page 20: Dom - XML Seminar Ski

Upotreba XML-a u Javi

13

3.3 Apache Digester

U paketu org.apache.commons.digester je definiran razred Digester. Pomoću njega možemo na lak i prirodan način analizirati neki XML dokument tako da mi zadamo odreñena pravila kako se Digester ponaša kada naiñe na neki element. Pomoću tih pravila Digester konstruira odgovarajuće strukture podataka koje onda sprema na svoj interni stog. Rad alata objasnit ćemo na jednostavnom primjeru. Analizirat ćemo dokument Glazba.xml. Prvo trebamo stvoriti odgovarajući razred koji može pohraniti podatke o pjesmama:

public class Pjesma {

private String izvoñač;

private String ime;

private int id;

public void setIzvoñač(String izvoñač) {

this.izvoñač = izvoñač;

}

public void setIme(String ime) {

this.ime = ime;

}

public String toString(){

StringBuffer ispis = new StringBuffer(40);

ispis.append(id).append(". ");

ispis.append(izvoñač).append(": ").append(ime);

return ispis.toString();

}

public void setId(int id) {

this.id = id;

}

}

Page 21: Dom - XML Seminar Ski

Upotreba XML-a u Javi

14

Kod je prilično jednostavan i u dodatku je dan pod 'Pimjer 4'. Imamo tri članske varijable čije se vrijednosti mogu podesiti odgovarajućim setter-ima. Takoñer je implementirana i metoda toString() koja vraća tekstualni zapis pjesme. Moramo i implementirati neku kolekciju u koju ćemo pospremati podatke o različitim pjesmama. Kod je na sljedećoj strani.

public class Kompilacija {

private List<Pjesma> lista;

public Kompilacija(){

lista = new ArrayList<Pjesma>();

}

public void dodajPjesmu(Pjesma pjesma){

lista.add(pjesma);

}

public void print(){

System.out.println("Broj pjesama u kompilaciji: " +

lista.size());

for( Pjesma p : lista){

System.out.println(p);

}

}

}

Opet prilično jednostavno, razred Kompilacija je lista u koju pohranjujemo pjesme. Implementirana je metoda dodajPjesmu(Pjesma pjesma) koja dodaje pjesmu u listu i metoda print() koja ispisuje listu na ekran. Izvorni kod se nalazi u dodatku kao ''Primjer 3'' Takoñer trebamo napraviti neki razred koji ima definiranu main metodu ( ''Primjer 5'' u dodatku) koji će pokrenuti proces analize. U tom razredu ćemo implementirati i metodu dodajPravila(Digester digester) koja će zadanome analizatoru odrediti pravila. Kod metode main :

public static void main(String[] args) {

Digester digester = new Digester();

Kompilacija kompilacija = new Kompilacija();

digester.push(kompilacija);

dodajPravila(digester);

Page 22: Dom - XML Seminar Ski

Upotreba XML-a u Javi

15

try{

File srcfile = new File("Glazba.xml");

digester.parse(srcfile);

}catch(IOException ioe) {

System.out.println("Greška pri čitanju:"

+ ioe.getMessage());

System.exit(-1);

}

catch(org.xml.sax.SAXException se) {

System.out.println("Error pri analizi:"

+ se.getMessage());

System.exit(-1);

}

kompilacija.print();

}

Najprije se stvara nova instanca razreda Digester, a nakon toga i nova instanca razreda Kompilacija koja se stavlja na vrh stog Digester-a. Dodaju se pravila po kojima se analizator treba ponašati te se analizira odgovarajući dokument. Na kraju se još i ispisuje sadržaj kompilacije. Kod metode dodajPravila(Digester digester) dan je u nastavku.

public static void dodajPravila(Digester digester){

digester.addObjectCreate("glazba/pjesma", Pjesma.class);

digester.addSetProperties("glazba/pjesma");

digester.addSetNext("glazba/pjesma", "dodajPjesmu");

digester.addSetNestedProperties("glazba/pjesma");

}

Kod ove metode ćemo komentirati red po red detaljno jer se u njoj nalaze neke od ključnih metoda razreda Digester kojima se modelira njegovo ponašanje.

digester.addObjectCreate("glazba/pjesma", Pjesma.class);

Page 23: Dom - XML Seminar Ski

Upotreba XML-a u Javi

16

Ovom naredbom kažemo analizatoru, da kada naiñe na oznaku pjesma (u zadanom kontekstu), neka stvori novu instancu razreda Pjesma i neka je stavi na vrh stoga.

digester.addSetProperties("glazba/pjesma");

Za svaki atribut koji sadrži početnu oznaku pjesma neka se pozove odgovarajuća setter metoda objekta koji je na vrhu stoga. Npr. početna oznaka pjesma sadrži atribut id pa će se pozvati metoda setId(int id) za objekt koji je na vrhu stoga (u ovom slučaju instanca razreda Pjesma). Za argument setter-a se uzima vrijednost atributa. Atributi za koje ne postoje odgovarajući setteri se ignoriraju.

digester.addSetNext("glazba/pjesma", "dodajPjesmu");

Ovime se odreñuje da se, u zadanom kontekstu, poziva metoda dodajPjesmu(Pjesma pjesma) nad objektom koji je prvi ispod vrha stoga (u ovom slučaju će to biti objekt razreda Kompilacija) i kao argument se predaje objekt koji je na vrhu stoga (instanca razreda Pjesma).

digester.addSetNestedProperties("glazba/pjesma");

Za svaki ugniježñeni element koji se nañe unutar elementa pjesma poziva se odgovarajuća setter metoda objekta na vrhu stoga (objekt razreda Pjesma u ovom slučaju). Znači, kada analizator naiñe na oznaku ime pozvat će metodu setIme(String ime) i predati kao argument sadržaj elementa ime. Program se može prevesti i pokrenuti i radi ispravno što potvrñuje ispis:

Broj pjesama u kompilaciji: 2

1. David Bowie: Space Oddity

2. Gorillaz: Dirty Harry

Takoñer ovo nije jedini mogući način za postizanje željene funkcionalnosti, mogli smo umjesto digester.addSetNestedProperties("glazba/pjesma"); napisati sljedeća dva pravila:

digester.addCallMethod("glazba/pjesma/ime", "setIme", 0);

digester.addCallMethod("glazba/pjesma/izvoñač", "setIzvoñač",0);

Ovim linijama se odreñuje, kada se naiñe na zadani kontekst, da se pozove metoda setIme(String ime) odnosno setIzvoñač(String izvoñač) za objekt na vrhu stoga (u ovom slučaju instanca razreda Pjesma) i da te metode nemaju dodatnih parametara, to

Page 24: Dom - XML Seminar Ski

Upotreba XML-a u Javi

17

označava treći argument, kao jedini parametar se predaje sadržaj elementa ime odnosno elementa izvoñač.8

Postoji još mnogo drugih metoda razreda Digester kojima se može regulirati ponašanje analizatora. Iz ovog primjera se vide mnoge prednosti alata Apache Digester. Jedna od prednosti je to što analizator prepoznaje kontekst u kojem se nalazi pojedini element, zato jer mu hijerarhiju elemenata predajemo kao argument. Još jedna prednost je relativno mala količina koda potrebna za reguliranje ponašanja analizatora. No, s druge strane, potrebno je dosta koda da bi se pripremile strukture u koje ćemo spremati podatke. Sve u svemu, Apache Digester se čini kao bolje rješenje od DOM ili SAX parsera.

8 http://jakarta.apache.org/commons/digester/commons-digester-1.8/docs/api/

Page 25: Dom - XML Seminar Ski

Upotreba XML-a u Javi

18

4. Zaključak

Iz svega navedenoga može se lako zaključiti da je XML jedan vrlo jednostavan i fleksibilan format. Njegovoj je sveopćoj uporabi puno doprinijela i činjenica da ga može prepoznati bilo koja platforma i on je postao standardni način pohrane podataka na Internetu.

Što se tiče XML-a u Javi, standardni SAX i DOM analizatori zahtijevaju dosta koda i stoga u nekim slučajevima nisu previše praktični. Iz tih razloga preporučuje se uporaba alata Apache Digester – alata koji se najčešće koristi za inicijaliziranje odreñenih struktura podataka u memoriji iz zadanog XML dokumenta. Takoñer alat je vrlo jednostavan i svoj posao obavlja programski 'čisto' i 'elegantno'.

Osim što je i sam jezik, XML može služiti i kao platforma za izradu drugih jezika koji označavaju podatke, kao štu su MathML i Chemical Markup Language. Takoñer postoje još i mnoge tehnologije koje pojednostavljuju uporabu XML-a, kao što XPath – jezik za pretraživanje sadržaja dokumenta i XQuery – upitni jezik za XML dokumente. Nije zato čudo da je primjena XML-a već i sad vrlo velika, a postoje još mnogi projekti (primjerice DDP) u razvoju koji će koristiti XML u različite svrhe i mnoge uporabe koje još nisu ni otkrivene te je XML zasigurno jezik budućnosti.9

9 http://en.wikipedia.org/wiki/XML

Page 26: Dom - XML Seminar Ski

Upotreba XML-a u Javi

19

5. Literatura

XML, http://en.wikipedia.org/wiki/XML, 11. 5. 2007

XML, http://hr.wikipedia.org/wiki/XML, 11. 5. 2007

Creating a Document Type Definition, http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/5a_dtd.html, 14. 5. 2007

An Overview of the APIs, http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/overview/3_apis.html, 14. 5. 2007

Creating a Document Type Definition, http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/5a_dtd.html, 14. 5. 2007

Serial Access with the Simple API for XML, http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/index.html, 12. 5. 2007

XML and the Document Object Model, http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/dom/index.html, 13. 5. 2007

Digester 1.8 API, http://jakarta.apache.org/commons/digester/commons-digester-1.8/docs/api/, 13. 5. 2007

Substituting and Inserting Text, http://java.sun.com/webservices/jaxp/dist/1.1/docs/tutorial/sax/4_refs.html, 11. 5. 2007

Namespaces in XML 1.0, http://www.w3.org/TR/REC-xml-names/, 15. 5. 2007

XML Namespaces, http://www.w3schools.com/xml/xml_namespaces.asp, 15. 5. 2007

Page 27: Dom - XML Seminar Ski

Upotreba XML-a u Javi

20

6. Sažetak

U ovom seminaru se obrañuju osnove jezika XML, objašnjavaju se njegove elementarne komponente te načini na koji se te komponente upotrebljavaju. Isto tako obrañuje se upotreba XML dokumenata u programskom jeziku Java. Razmatra se uporaba standardnih API-a dostupnih u Javi i ''open source'' alata koji su besplatno dostupni na internetu (Apache Digester). Njihova se funkcionalnost vrlo detaljno objašnjava na par jednostavnih primjera čiji su kodovi dostupni u dodatku.

Page 28: Dom - XML Seminar Ski

Upotreba XML-a u Javi

21

Dodatak: Primjer 1 – Echo:

import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.SAXParserFactory;

import javax.xml.parsers.SAXParser;

public class Echo extends DefaultHandler{ public static void main(String[] args){ //deklariramo ovu klasu kao novi DefaultHandler DefaultHandler handler = new Echo2(); //stvaramo novu tvornicu analizatora SAXParserFactory factory = SAXParserFactory.newInstance(); try{ //stvaramo novi analizator SAXParser analizator = factory.newSAXParser(); //i analiziramo dokument analizator.parse("Glazba.xml", handler); }catch(Throwable t){ t.printStackTrace(); } } public void startDocument(){ System.out.println("POČETAK:"); System.out.println("<?xml version='1.0' encoding='UTF-8'?>"); } public void endDocument(){ System.out.println("KRAJ"); } public void startElement(String namespaceURI, String sName, String ime, Attributes atributi) { indentiraj(); System.out.print("ELEMENT:<" + ime); this.brIndentacija++; if (atributi != null) { for (int i = 0; i < atributi.getLength(); i++) { System.out.print(" " + atributi.getQName(i) + "=" + atributi.getValue(i)); } } System.out.println(">"); } public void endElement(String namespaceURI, String sName, String ime) { this.brIndentacija--; indentiraj(); System.out.print("KRAJ_EL:"); System.out.println("</" + ime + ">"); }

Page 29: Dom - XML Seminar Ski

Upotreba XML-a u Javi

22

public void characters(char buf[], int offset, int len){ String s = new String(buf, offset, len); if (!s.trim().equals("")){ indentiraj(); System.out.println("PODATAK: " + s); } } private int brIndentacija = 0; public void indentiraj(){ for (int i = 0; i < brIndentacija; i++){ System.out.print(" "); } }

}

Primjer 2 – DomEcho:

import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import org.w3c.dom.Document; public class DomEcho { private static Document dokument; public static void main(String argv[]){ //stvaramo novu tvornicu DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); try{ //pomoću tvornice stavaramo novi DocumentBuilder DocumentBuilder builder = factory.newDocumentBuilder(); //analiziramo dokument dokument = builder.parse("Glazba.xml"); }catch(Throwable t) { t.printStackTrace(); } }

}

Primjer 3 – Kompilacija:

import java.util.ArrayList; import java.util.List; public class Kompilacija { private List<Pjesma> lista; public Kompilacija(){ lista = new ArrayList<Pjesma>(); } public void dodajPjesmu(Pjesma pjesma){ lista.add(pjesma); }

Page 30: Dom - XML Seminar Ski

Upotreba XML-a u Javi

23

public void print(){ System.out.println("Broj pjesama u kompilaciji: " + lista.size()); for( Pjesma p : lista){ System.out.println(p); } }

}

Primjer 4 – Pjesma:

public class Pjesma { private String izvoñač; private String ime; private int id; public void setIzvoñač(String izvoñač) { this.izvoñač = izvoñač; }

public void setIme(String ime) { this.ime = ime; } public String toString(){ StringBuffer ispis = new StringBuffer(40); ispis.append(id).append(". "); ispis.append(izvoñač).append(": ").append(ime); return ispis.toString(); } public void setId(int id) { this.id = id; }

}

Primjer 5 – Main:

import java.io.File; import java.io.IOException; import org.apache.commons.digester.Digester; public class Main { public static void main(String[] args) { Digester digester = new Digester(); Kompilacija kompilacija = new Kompilacija(); digester.push(kompilacija);

Page 31: Dom - XML Seminar Ski

Upotreba XML-a u Javi

24

dodajPravila(digester); try{ File srcfile = new File("Glazba.xml"); digester.parse(srcfile); }catch(IOException ioe) { System.out.println("Greška pri čitanju:" + ioe.getMessage()); System.exit(-1); } catch(org.xml.sax.SAXException se) { System.out.println("Greska pri analizi:" + se.getMessage()); System.exit(-1); } kompilacija.print(); } public static void dodajPravila(Digester digester){ digester.addObjectCreate("glazba/pjesma", Pjesma.class); digester.addSetProperties("glazba/pjesma"); digester.addSetNext("glazba/pjesma", "dodajPjesmu"); //digester.addSetNestedProperties("glazba/pjesma"); digester.addCallMethod("glazba/pjesma/ime", "setIme", 0);

digester.addCallMethod("glazba/pjesma/izvoñač","setIzvoñač",0); }

}