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.
| |