Tabeli enese, rea ning lahtri alguse ja lõpu elemendid paigutatakse lihtsalt sobivatesse
kohtadesse vahele. Paljas punkt xsl:value-of elemendi sees palub kirjutada jooksva elemendi
väärtuse. Nõnda kui välimene for-each käib läbi kõik inimesed ning sisemine iga inimese
alamtunnused ning andmefailis on kõigil inimestel sama palju tunnuseid saabki kokku täiesti
viisaka HTML-tabeli.
Tabel ise selline nagu ikka seda ette kujutada võib. Et ta loodud programmikoodi abil ning
kood paistis küllalt kergesti kontrollitav olema, siis võib loota, et loodud tabelis kõik read ja
lahtrid ilusti alustatud ja lõpetatud on.
Juku | Juurikas | 1963 |
Juku | Kaalikas | 1961 |
Kalle | Kaalikas | 1975 |
Mari | Maasikas | 1981 |
Oskar | Ohakas | 1971 |
Mallid
Tabeli saab algandmete põhjal kokku panna ka täiesti tsükleid kasutamata. Juhul,
kui soovitakse andmed algses failis ning tulemusfailis enamjaolt samasse järjekorda jätta, siis
sobivad elementide nimede muutmiseks ja väärtuste lisamiseks malllid. Iga elemendi puhul
saab määrata, millisel kujul teda väljundis näidatakse. Järgnevat näidet täheepanelikumalt
silmitsedes võib näha plokke, kus elemendi nimeks on xsl:template ning sees HTML-i käsud
ja keskel xsl:apply-templates. Lahtiseletatult tähendavad koostatud template'd juhiseid XSLi
järgi algandmeid töötlevale programmile. Kogu dokumendi algust tähistab "/", ülejäänud
mallid vastavad igaüks oma elemendile, mille nimi match-atribuudis kirjas on.
Sellline kirjeldus tähendab näiteks, et kui faili töötlemisel on jõutud elemendini
nimega "inimesed", siis kirjutatakse väljundisse kõigepealt . Edasi töödeldakse
inimesed-nimelise elemendi olemasolev sisu ning lõppu kirjutatakse
. Sarnaselt
asendatakse element "inimene" tabeli ühe reaga. Elemendi sisu väljatrükk on näidatud
järnevas lõigus. Malli sees olles saab jooksva elemendi poole pöörduda sümboli "." kaudu.
Siin on pandud igale väärtusele ka tabeli lahtrit tähistab element ümber. Vaikimisi juhul,
kui palutakse apply-templates käsu abil faili dokumenti edasi analüüsida, siis ettejääv tekst
trükitaks samuti lihtsalt ekraanile.
|
Ning nüüd siis tervikuna XSLi kood, kus mallide abil muudetakse inimeste andmete
loetelu tabeliks, kus igal real inimese andmed. Kogu dokumendi algusesse ja lõppu
paigutatakse vastavad HTML-märgendid. Kõiki inimesi ühendav element inimesed
muudetakse HTML-i elemendiks . Igale inimesele hakkab vastama tabeli rida
ning iga inimese iga üksiku tunnuse väärtusele tabeli lahter .
|
Tekstikontroll
Ehkki XSL pole mõeldud suuremamahulisteks arvutusteks ja tekstitöötluseks,
õnnestub lihtsamad võrdlused ja kokkuvõtted siin täiesti teha. Järgnevalt siis loetelu nende
inimeste perekonnanimedest, kelle eesnimi algab J-iga. Algandmete peale vaadates leiame
sealt kaks Jukut: üks Juurikas ning teine Kaalikas. Vastavad perekonnanimed saadakse jätte
järgneva avaldise abil.
Kandiliste sulgude sees määratakse ära, millistele tingimustele vastavaid inimesi
loetellu võetakse. Siin juhul siis kontrolliks XSLi funktsioon nimega starts-with,
parameetriteks kontrollitav tekst ning otsitav algustekst. Ning nagu muud
tõeväärtusfunktsioonid, nii ka siin on väärtuseks jah või ei. Ning loetellu jäävad need
inimesed, kel avaldise puhul väärtuseks jah. Ning nõnda saab tsükli sees otsitud tulemused
välja kirjutada.
;
Käivitamine nii nagu eelnenud näite puhul
E:\kasutaja\jaagup\xml>java XSLMuundur inimesed.xml inimesed4.xsl inimesed4.txt
Ning faili sisu piiludes võime just soovitud read selle seest avastada.
E:\kasutaja\jaagup\xml>more inimesed4.txt
Juurikas;
Kaalikas;
XSL-i funktsioone
Võrreldes "päris" programmeerimiskeeltega võib XSLi käsustikku väikeseks
pidada, kuid ega algses Basicus neid kuigi palju rohkem polnud. Järgnevalt on ära toodud
suurem osa levinumatest käsklustest.
last() viimase järjekorranumber
position() jooksva järjekorranumber
count(plokk) elementide arv plokis
name(plokk) ploki juurelemendi nimi
Funktsiooni name läheb näiteks vaja, kui soovitakse luua mõnd üldist malli, mis
saaks hakkama mitmesuguse struktuuriga algandmete korral ning kus soovitakse algse
elemendi nime säilitada või näiteks tabeli lahtri pealkirjana kasutada.
Tõeväärtusfunktsioonid nagu ikka arvata võib; not keerab olemasoleva väärtuse
vastupidiseks, ülejäänud kahe puhul on tegemist lihtsalt konstandiga.
not(toevaartus)
true()
false()
Samuti võib nime järgi ära aimata enamike arvudega tegelevate funktsioonide
ülesanded. Käsklust number kasutatakse lihtsalt tüübimuunduseks, samuti nagu käsuga string
saab andmed taas tagasi tekstikujule.
number(objekt)
string(objekt)
sum(plokk) väljastab summa juhul, kui elemendid on numbrid
floor(number)
round(number)
Sõnefunktsioonid
concat(s1, s2, s3*)
Parameetritena antud tekstid liidetakse. Elementide arv ei ole piiratud.
starts-with(s1, s2)
Kontrollitakse, kas esimesena antud tekst algab teisena antud tekstiga.
contains(s1, s2)
Võrreldes eelmisega ei pruugita alustada algusest, vaid otsitakse lõigu leidmist kogu
teksti ulatuses.
substring-before(s1, s2)
substring-after(s1, s2)
substring(s1, start, nr?)
Käsud lõigu eraldamiseks tekstist
string-length(s1)
Nagu nimest näha, küsitakse teksti pikkust.
normalize-space(s1)
Võtab algusest ja otstest tühikud, muud vahed teeb üheks tühikuks. Kasulik näiteks
erikujuliste sisestatud tekstide võrdlemisel või lihtsalt väljundi viisakamaks muutmisel.
XMLi andmete juures ei mängi korduvad tühikud rolli, küll aga neist võib tüli tekkida
mõnda muusse kohta suunduva väljundi puhul.
translate (s1, algsümbolid, lõppsümbolid)
Tähtede asendamiseks leiab harjumatu kujuga funktsiooni. Näite järgi on aga ehk
toimimine mõistetav: translate('pann', 'an', 'ek') -> 'pekk'
Parameetrid
Kui samade algandmete põhjal tahetakse kokku panna märgatavalt erinevaid
tulemusi, siis tuleb üldjuhul igaks muundamiseks valmis kirjutada omaette XSL-leht. Näiteks
HTML- ja WAP-väljund näevad nõnda erinevad välja, et ühist muundajat kirjutada oleks
raske. Kui aga valida lihtsalt eri resolutsioonidele arvestatud HTML-i vahel, siis võib XSLi
parameetri abil kord rohkem, kord vähem lähteandmeid sisse võtta. Samuti, kui näiteks
soovitakse näidata lehel inimeste vanuseid, salvestatud on aga sünniaastad, siis parameetrina
antud praeguse aastaarvu järgi saab vähemalt ligikaudugi tulemuse parajaks sättida.
Parameetri väärtus tuleb määrata eraldi elemendina enne mallikirjelduste algust.
Nagu näha, tuleb parameetri nimi atribuudina, väärtus aga elemendi väärtusena.
5
Hiljem atribuudi väärtust küsides tuleb avaldises selle nimele dollarimärk ette panna.
Ilma dollarita tähendaks see vastavanimelist XML-elementi.
Andmete sortimiseks tuleb tsükli sisse paigutada alamelement nimega xsl:sort ning
parameetrina määrata, millise elemendi väärtuse järgi sorteeritakse. Nagu mujal, nii ka siin
oleks võimalik parameetriks koostada avaldis, mis järjestamise peenemalt ette määraks.
Soovides väljatrüki abil tühikuga eraldatud ees- ja perekonnanime, aitab funktsioon
concat. Muul juhul tuleks sama tulemuse saavutamiseks xsl:value-of element mitmel korral
välja kutsuda.
;
Ning näide tervikuna.
ar
5
Nimed, mis sisaldavad kombinatsiooni :
;
Nimed pikkusega ja rohkem:
;
Käivitus
E:\kasutaja\jaagup\xml>java XSLMuundur inimesed.xml inimesed4a.xsl
inimesed4a.txt
ja tulemus
E:\kasutaja\jaagup\xml>more inimesed4a.txt
Nimed, mis sisaldavad kombinatsiooni ar:
Oskar Ohakas;
Mari Maasikas;
Nimed pikkusega 5 ja rohkem:
Kalle Kaalikas varuks 0;
Oskar Ohakas varuks 0;
Parameetrite väärtuste muutmiseks ei pea alati tekstiredaktoriga muutma XSLi faili
sisu. Neid saab sättida ka otse XMLi ja XSLi kokkusiduvas koodis ning ka ühendava
programmi väljakutsel. Nõnda on ka siin näha, kus pikkusele antakse väärtuseks neli.
tolkija.setParameter("pikkus", "4");
Muus osas näeb faile ühendav käivitusprogramm eelnenuga sarnane välja.
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import java.io.*;
public class XSLParameetrid{
public static void main(String argumendid[]) throws Exception{
Transformer tolkija=TransformerFactory.newInstance().
newTransformer(new StreamSource("inimesed4a.xsl"));
tolkija.setParameter("pikkus", "4");
tolkija.transform(
new StreamSource("inimesed.xml"),
new StreamResult(new FileOutputStream("inimesed4a.txt"))
);
}
}
Ka käivitamine sarnane
E:\kasutaja\jaagup\xml>java XSLParameetrid
Ning tulemusena näeb siis nelja tähe pikkusi ja pikemaid nimesid.
E:\kasutaja\jaagup\xml>more inimesed4a.txt
Nimed, mis sisaldavad kombinatsiooni ar:
Oskar Ohakas;
Mari Maasikas;
Nimed pikkusega 4 ja rohkem:
Juku Juurikas varuks 0;
Juku Kaalikas varuks 0;
Kalle Kaalikas varuks 1;
Mari Maasikas varuks 0;
Oskar Ohakas varuks 1;
Ülesandeid
XML
Sisestusharjutus
* Koosta eesnimede loetelu.
* Koosta inimeste loetelu, kus isikuandmeteks on eesnimi,
perekonnanimi ja
synniaasta.
Andmepuu
* Kirjuta XML-i abil üles sugupuu alates oma vanaisast.
* Näita puus ka abikaasad.
XSL
* Loo XSL leht, mis sõltumata sisendandmetest väljastab "Tere".
Loetelus on vähemalt viie inimese andmed: eesnimi, perekonnanimi ning
sünniaasta.
* Väljastatakse teise inimese sünniaasta
* Andmed väljastatakse tabelina nii mallide (template) abil.
* Andmed väljastatakse tabelina for-each tsükli
abil. Tulpade pealkirjad on rasvased.
* Luuakse SQL-laused inimeste andmete lisamiseks baasi.
* Väljastatakse semikoolonitega eraldatud loetelu vanuste
järjekorras.
* Parameetrina antakse ette käesoleva aasta number.
Iga inimese kohta väljastatakse nimi ja vanus.
Sugupuu
Sugupuus on vähemalt kolme põlve andmed, iga inimese kohta vähemalt
ees- ja
perekonnanimi ning sünniaasta.
* Trükitakse välja inimeste nimed ning nende laste arv.
* Väljastatakse nimed, kel on vähemalt kaks last.
* Väljastatakse nimed, kellel on sugupuus vanavanem.
* Andmepuus muudetakse sünniaasta atribuudiks.
XML ja kassid
* Loo XML-fail kus on kirjas kasside nimed ja nende sünniaastad
* Kirjuta XSL-i abil andmed välja, määrates nimed pealkirjadeks ning
iga
pealkirja alla kirjutada teksti sisse, millisel aastal vastav kass
sündis.
* Lisaks eelmisele väljasta andmed sorteerituna sünniaastate järgi.
XML ja koerad
* Loo XML-fail, kus kirjas koert nimed ja tõud.
* Väljasta iga koer eraldi real ning muuda tõug rasvaseks.
* Lisaks eelmisele muuda paiguta kõik viie tähe pikkused nimed
kaldkirja.
DOM
Nagu mitemetes keeltes, nii ka Java puhul leiduvad vahendid XMLi andmepuu
loomiseks, lugemiseks ja muutmiseks. Võrrelduna lihtsalt tekstikäskude abil töötlemisele
saab siin programmeerija enam keskenduda andmete paiknemise loogikale. Samuti hoiab
puu elementide loomine ja nende poole pöördumine ära teksti loomisel tekkida võivad
trükivead. Abikäskudega õnnestub küsida sobivaid elemente. Kasutatavad avaldised pole
küll veel nõnda paindlikud kui XSLi juurde kuuluva XPathi omad, kuid märgatavat kasu on
neistki.
Järgnevalt DOM-i tutvustus väikese näite abil. Keskseks klassiks on Document.
Selle eksemplari kasutatakse nii uute elementide loomiseks kui elemendihierarhia algusena.
Dokument võidakse luua kas tühjana tühjale kohale
Document
d=DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
või siis lugeda sisse olemasolevast failist.
// Document
d=DocumentBuilderFactory.newInstance().newDocumentBuilder().parse("linnad.xml")
;
Nagu näha, ei kasutata dokumendi loomisel mitte klassi konstruktorit, vaid selle
asemel koostatakse vabriku (DocumentBuilderFactory) eksemplar, mille abil siis dokument
kokku pannakse. Selline pikk lähenemine võimaldab mitmel pool seada parameetreid,
samuti kasutada ilma koodi muutmata mitmete tootjate abitükke.
Et dokumenti saaks elemente lisada, peab selles olema vähemasti juurelement. Failist
lugedes tuleb see kaasa, tühja dokumendi loomisel tuleb aga ka juur luua ja määrata. Ning
nagu XMLi spetsifikatsioonis öeldakse, peab igal failil või dokumendil olema üks ja ainult
üks juur. Nii nagu hiljemgi elementide puhul, nii ka siin tuleb eraldi käskudena element luua
ning siis sobivasse kohta lisada.
Element juur=d.createElement("linnad");
d.appendChild(juur);
Edasi siis dokumendile külge ka sisulised andmed, mis praegu lihtsuse mõttes
võetakse massiivist.
String[] linnanimed={"Tallinn", "Tartu", "Narva"};
Tekstiliste andmete XML-i puusse kinnitamiseks tuleb kõigepealt luua teksti puusse
kinnitatavaks tervikuks ühendav TextNode, mis siis omakorda nimega elemendi sisse
paigutada. Et siin näites on juurelemendiks "linnad", selle all elemendid nimega "linn" ning
edasi vastava elemendi sees omakorda linnanimi, näiteks "Tartu".
for(int i=0; ijava UusDokument
TallinnTartuNarva
Lihtsalt tekstiekraanile kirjutatuna võib linnade rida olla halvasti loetav. Kui aga sama
XMLi lõik salvestada faili ja avada seiluriga, siis õnnestub hulga selgemini lugeda.
Joonistusvahend
Järgnevalt veidi pikem näide, kus pildi andmete salvestamisel kasutatakse XMLi
andmepuud. Puu loomise käsud samad kui lühemagi näite puhul. Juures käsklused puust
andmete lugemiseks ning joonistuspool. Tähtsamad nupud avamise ja salvestamise jaoks.
Iga hiire vedamisega tekib joon, joone juures jäetakse meelde koordinaadid, mida hiir
läbinud. Nii nagu eelmises näites oli juurelemendiks "linnad" ning selle all hulk elemente "linn",
nii siin on juurelemendiks "koordinaadid" ning juure küljes elemendid "joon". Iga joone sees
omakorda hulk elemente nimega "punkt", milles koordinaate tähistavad "x" ja "y".
Algus nagu eelmiselgi korral. Nii alustuse kui kustutuse puhul luuakse uus tühi
dokument ning sinna sisse juurelement.
d=DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
juur=d.createElement("koordinaadid");
d.appendChild(juur);
Iga hiirevajutuse puhul luuakse uus element nimega "joon" ning jäetakse vastava
nimega muutujasse meelde. Nii vajutuse kui lohistuse puhul lisatakse joone külge punkt.
public void mousePressed(MouseEvent e) {
joon=d.createElement("joon");
juur.appendChild(joon);
lisaPunkt(e.getX(), e.getY());
}
public void mouseDragged(MouseEvent e){
lisaPunkt(e.getX(), e.getY());
}
Selle suhteliselt tervikliku tegevuse tarbeks loodi omaette alamprogramm. Isendi
piires kättesaadava muutuja joon külge lisatakse element punkt, mille juurde omakorda x ja
y oma koordinaatide tekstilise väärtusega.
void lisaPunkt(int x, int y){
Element punkt=d.createElement("punkt");
Element px=d.createElement("x");
px.appendChild(d.createTextNode(x+""));
punkt.appendChild(px);
Element py=d.createElement("y");
py.appendChild(d.createTextNode(y+""));
punkt.appendChild(py);
joon.appendChild(punkt);
}
Joonistamine näeb välja mõnevõrra keerukam. Graafikakomponentide puhul
soovitatakse kogu joonistus ette võtta paint-meetodis ning meetodit sobival ajal välja
kutsuda. Ka pole lihtsuse mõttes siin näites puhvrit vahele loodud, nii et iga ülejoonistuskäsu
peale koostatakse kogu pilt uuesti.
public void paint(Graphics g){
Alustuseks küsitakse massiivina välja kõik dokumendis paiknevad jooned. Et
elementide paiknemine on teada, siis piisab küsimisest asukoha ning mitte nime järgi.
Dokumendi d käsk getFirstChild() väljastab juurelemendi "koordinaadid", sealt käsk
getChildNodes() väljastab joonte kogumi.
NodeList jooned=d.getFirstChild().getChildNodes();
Edasises tsüklis käiakse jooned ükshaaval läbi ning palutakse nad kõik ekraanile
joonistada.
for(int i=0; ijava EesnimedeLoendaja
Leiti 5 eesnime.
Suurema analüüsi puhul võib meelespeetavaid väärtusi rohkem olla. XMLReader
hoolitseb lihtsalt selle eest, et dokumendis leidumise järjekorras saaks õiged käsklused
õigete parameetritega välja kutsutud. Kõik muu jääb programmeerija hooleks. Järgnevalt
loetakse kokku ja trükitakse välja eesnimede väärtused.
Elementide sisu
Kui elementide nimed saab kergesti kätte, siis elementide sisu kinnipüüdmiseks tuleb
veidi rohkem vaeva näha. Põhjus tõenäoliselt selles, et suuremates XML-dokumentides
võivad tekstiosad ka näiteks mitme megabaidi pikkused olla ning neid ei pruugi mõistlik ega
võimalik olla korraga mällu lugeda. Samuti kasutatakse SAXi olukordades, kus suurest
dokumendist vajatakse vaid üksikuid andmeid ning siis pole ülejäänud andmete muundamine
kergesti loetavale kujule vajalik.
Igal pool, kus faili läbimisel jõutakse elemendi sildist väljapool asuvale tekstile,
kutsutakse välja meetod characters. Meetodi väljakutsumise kordade arv võib olla ka
suurem kui üks - juhul, kui tekstilõik edastatakse kuularile mitmes osas. Nõnda siis peab
tervikliku teksti kokku lappimiseks programmeerija mõned read kirjutama, et ühe elemendi
sisese teksti tervikuna kätte saada. Samuti võib ebatavalisena paista teksti esitamise moodus:
tähemassiiv ning kaks arvu funktsiooni parameetritena. Mõte on tõenäoliselt jälle seotud
jõudlusega. Faili analüüsil loetakse sellest korraga mällu miski suurusega plokk. Edaspidi
pole seda plokki vaja mälus liigutada enne, kui uus plokk selle asemele loetakse. Ning kui
tahetakse kasutajale teada anda, et tal on võimalus tekstilõik enese valdusesse hankida, siis
teatatakse talle vaid ploki asukoht, teksti esimese tähe järjekorranumber ning tähtede arv.
Ning ainult juhul, kui kasutajal teksti parajasjagu vaja läheb, tuleb tal see lõik omale sobivas
formaadis välja küsida. Õnneks on klassil String olemas konstruktor, mis tahab just samad
kolm parameetrit: tähemassiivi, vajaliku teksti alguse ja tähtede arvu. Nõnda saab vajadusel
ühe käsuga soovitud sõne kätte.
Tingimuslause abil tuleb kontrollida, kas parasjagu soovitud teksti vaja on. Praegusel
juhul näitab muutuja kasEesnimi, et kas ollakse analüüsiga eesnime elemendi sees.
public void characters(char[] tahed, int algus, int pikkus){
if(kasEesnimi){
puhver.append(new String(tahed, algus, pikkus));
}
}
Iga kord eesnime elementi sisenedes luuakse uus tühi puhvri eksemplar. Meetodis
characters liidetakse eesnimi tükkidest kokku, juhul kui andmed peaksid osade kaupa
saabuma. Muidu pannakse puhvrisse lihtsalt üks terviklik tükk. Kui eesnime element lõpeb,
siis trükitakse puhvri sisu ekraanile ning nõnda saabki kasutaja näha eesnimede loetelu.
import javax.xml.parsers.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;
/**
* Trükitakse välja eesnimed. Tükid koondatakse puhvris kokku tervikuks.
*/
public class EesnimedeLugeja extends DefaultHandler{
boolean kasEesnimi=false;
StringBuffer puhver;
public void startElement(String nimeruum, String kohalik,
String element, Attributes at){
if(element.equals("eesnimi")){
kasEesnimi=true;
puhver=new StringBuffer();
}
}
public void endElement(String nimeruum, String kohalik,
String element){
if(element.equals("eesnimi")){
kasEesnimi=false;
System.out.println(puhver);
}
}
public void characters(char[] tahed, int algus, int pikkus){
if(kasEesnimi){
puhver.append(new String(tahed, algus, pikkus));
}
}
public static void main(String argumendid[]) throws Exception{
XMLReader lappaja=
SAXParserFactory.newInstance().newSAXParser().getXMLReader();
lappaja.setContentHandler(new EesnimedeLugeja());
lappaja.parse("inimesed.xml");
}
}
/*
E:\kasutaja\jaagup\xml>java EesnimedeLugeja
Juku
Juku
Kalle
Mari
Oskar
*/
Üheks levinud SAXi kasutamise kohaks on XML-faili osade lugemine andmebaasi.
XML-faili lapates kogutakse muutujatesse kokku sobivad väärtused. Kui terve rea jagu
koos, siis õnnestub tulemus ühe insert-lause abil andmebaasi tabeli reaks kirjutada.
| |