XSLT+FO:n tarjoamat mahdollisuudet XMLdatan käsittelyyn eivät aina ole riittäviä: Tietojen käsittely on vuorovaikutteista Tietojen käsittely on kaksisuuntaista, ei vain datan esittämistä Esitysvälineiden kyvyt ovat riittämättömiä tuottamaan haluttua esitystapaa esim. kuvia, yms XML rakenteen käsittelymahdollisuuksia: DOM-puun käsittely edellyttää koko xml-aineiston lataamista keskusmuistiin DOM-puuksi tietojen hyväksikäytön voi aloittaa vasta kun puu on luotu ohjelmakirjastoja puun käsittelyyn Sarjallinen käsittely tapahtumaperustaisesti xml-aineisto tietovirtana, reagointi materiaalin mukaan tietoa voidaan käyttää hyväksi ennen kuin aineisto on kokonaisuudessaan ladattu - kaikkea ei välttämättä tarvitse ladata 1 2 W3C:llä API-suositus Document Object Model (DOM) Level 3 Core Specification,Version 1.0, W3C Recommendation 07 April 2004 (http://www.w3.org/tr/dom-level-3-core/) Eri ohjelmointikielillä eri abstraktiotasolla olevia kirjastototeutuksia 3 Text CDATASection CharacterData Comment Document Node Element Attr DocumentType Notation * Entity * EntityReference Processing Instruction W3C:n DOM-mallin DOM-puun rajapintaluokat * = eivät näy XPath -mallissa 4 Puun juuri on Document solmu Seuraavalla tasolla yksi enintään yksi Elementja DocumentType-solmu ja mahdollisesti PIsekä Comment-solmuja Element-solmun lapsina Element, PI, Comment, Text,CDATASection ja EntityReference Attr-solmun lapsina Text ja EntityReference Huom: Attr-solmut eivät ole Element solmujen lapsia eikä Element ole Attr:n isäsolmu (ero XPath-malliin) Muita rajapintaluokkia: NodeList järjestetty kokoelma Node-olioita item(i) palauttaa i:nnen alkion, alkaen indeksistä 0 length =listan pituus NamedNodeMap mahdollistaa järjestämättömän solmujoukon, esim. attribuutit, käsittelyn solmun nimen perusteella getnameditem(name) Eläviä kokoelmia, muutos rakenteeseen vaikuttaa välittömästi myös kokoelman sisältöön 5 6 1
Node tietosisältöä: nodename nodevalue (arvo määrätty Attr ja eri tyyppisillä merkkitieto elementeillä, muilla null) parentnode childnodes (NodeList) firstchild lastchild previoussibling nextsibling attributes (NamedNodeMap) ownerdocument Toimintoja insertbefore (newchild, refchild) lisää tiettyyn kohtaan, ensin paikannettava refchild replacechild (newchild, oldchild) removechild (oldchild) appendchild (newchild) lisää poikueen loppuun haschildnodes clonenode(deep) tekee kopion solmusta, attribuuttitiedot kopioidaan, ei isätietoja (jos deep= false, ei kopioida alirakenteita, jos true, niin alirakenteineen) 7 8 Document sisältöä doctype implementation documentelement Document toimintoja createelement(tagname) luo tyhjän elementtisolmun, vain nodename=tagname createattribute(attrname) luo tyhjän attribuuttisolmun, kuten createelement createtextnode(data) luo tekstisolmun, jonka sisältönä on data getelementbyid(elementid) palauttaa elementin, jonka ID-tyyppisen attribuutin arvo on sama kuin parametri getelementsbytagname(tagname) palauttaa solmulistan (esijärjestyksessä) solmuista, joiden taginimi vastaa parametria 9 10 Element sisältöä: tagname Element toimintoja: getattribute(name) palauttaa attribuutin arvon merkkijonona, jos attribuutti löytyy nimellä setattribute(name, value) liittää elementtiin uuden attribuuttiarvon tai muuttaa olemassa olevaa, luo tarvittaessa attribuuttisolmun. Jos attribuuttiarvo sisältää viittauksia nimettyihin kohteisiin, sitä ei voi asettaa tällä toiminnolla, vaan on luotava erikseen attribuuttisolmu getattributenode(name) palauttaa attribuuttinimeä vastaavan Attr solmun setattributenode(newattr) lisää elementin atribuuttien joukoon annetun solmun removeattributenode(oldattr) poistaa attribuuttisolmun getelementsbytagname(tagname) tuottaa solmulistan elementin jälkeläisten joukosta löytyvistä tagname-tyyppisistä solmuista hasattribute(name) onko elementillä kysytty attribuutti 11 12 2
CharacterData toimintoja substring(offset, count) appenddata(string) - lisää loppuun insertdata(offset,string) - lisää kohtaan deletedata(offset,count) - poistaa pätkän kohdasta replacedata(offset,count,string) -korvaa alueen sisällön Puun läpikäynti tyypillisesti: Edetään puussa GetElementsByTagName toiminnon, tai firstchild, tai childnodes rakenteiden avulla. Rakenteita käydään läpi silmukassa tai iteraattorilla Solmukohtaisesti päätetään miten jatketaan 13 14 Esimerkki JavaScrip:llä, tulostaa tagit x=xmldoc.documentelement.childnodes; for (i=0;i<x.length;i++) { if (x[i].nodetype==1) { //Process only element nodes (type 1) document.write(x[i].nodename); document.write("<br />"); 15 Tekstisolmujen käsittelyä rakenteessa <title>tekstiä</title> //the x variable will hold a NodeList var x=getelementsbytagname('title'); for (i=0;i<x.length;i++) { document.write(x[i].childnodes[0].nodevalue); document.write("<br />"); title solmut niiden sisältönä oleva tekstisolmu arvo 16 atribuuttien käsittelyä: xmldoc=loadxmldoc("books.xml"); var x=xmldoc.getelementsbytagname("book"); for(i=0;i<x.length;i++) { //the attlist variable will hold a NamedNodeMap var attlist=x.item(i).attributes; var att=attlist.getnameditem("category"); document.write(att.value + "<br />"); Onnistuu myös yksinkertaisemin: x.item(i).getattribute("gategory") DOM-puun luominen ja muuttaminen Luodaan tyhjiä solmuja Määritetään solmuille sisältö Muodostetaan solmuista alipuu Kytketään alipuu DOM-rakenteeseen 17 18 3
//check if last child node is an element node function get_lastchild(n) { var x=n.lastchild; while (x.nodetype!=1) { x=x.previoussibling; return x; xmldoc=loadxmldoc("books.xml"); var x=xmldoc.documentelement; var newnode=xmldoc.createelement("book"); var newtitle=xmldoc.createelement("title"); var newtext=xmldoc.createtextnode("a Notebook"); newtitle.appendchild(newtext); newnode.appendchild(newtitle); x.insertbefore(newnode,get_lastchild(x)); Tyhjiä elementtejä kytketään alipuuksi Ohjelmakirjastoihin voi perusrakenteiden lisäksi sisältyä toimittajien laajennoksia, esimerkiksi haku XPath-lausekkeiden avulla. Näiden toteutukset voivat poiketa merkittävästi. Esim. selainten JavaScript:ssä IE: document.selectnodes(xpath) palauttaa nodelist:n Firefox: document.evaluate(xpath, contextnode, namespaceresolver, resulttype, result) palauttaa oletusarvoisesti iteraattorin nodelist:iin Liitetään puuhun 19 20 Edelliset esimerkit ovat olleet JavaScriptillä. Oliorakenteiset rajapinnat hyödyntävät perintää ja ohjelmointikielen rakenteita esim. kokoelmaluokkia ja nostavat tyypillisesti hieman abstraktiotasoa Tarjolla on myös suoraviivaisia W3C-DOM toteutuksia Java toteutuksia esim: dom4j, jdom Java JDOM esimerkki static void doublesugar(document d) throws DataConversionException { Namespace rcp = Namespace.getNamespace("http://www.brics.dk/ixwt/recipes"); Filter f = new ElementFilter("ingredient",rcp); java.util.iterator i = d.getdescendants(f); while (i.hasnext()) { Element e = (Element)i.next(); if (e.getattributevalue("name").equals("sugar")) { double amount = e.getattribute("amount").getdoublevalue(); e.setattribute("amount",new Double(2*amount).toString()); 21 22 DOM-puun rakentaminen edellyttää XML-aineiston jäsentämistä (parsing). Edellä olleissa JavaScript esimerkeissä DOM-rakenne luotiin alun perin Document -olion load-metodilla (ei määritelty suosituksessa). Tämä metodi suorittaa sisäisesti jäsennyksen ja puun rakennuksen Useissa ohjelmointiympäristöissä puun rakentaja voidaan määritellä myös eksplisiittisesti ja se on vaihdettavissa Rakentajan keskeisenä osana on jäsentäjä 23 Esimerkki jäsentäjän kytkemiseksi DOM:n konstruointiin public class ChangeDescription { oletusarvoisen rakentajan public static void main(string[] args) { asemasta voitaisiin määritellä mitä käytetään try { SAXBuilder b = new SAXBuilder(); Document d = b.build(new File("recipes.xml")); Namespace rcp = Namespace.getNamespace("http://www.brics.dk/ixwt/recipe s"); d.getrootelement().getchild("description",rcp).settext("cool recipes!"); XMLOutputter outputter = new XMLOutputter(); outputter.output(d,system.out); catch (Exception e) { e.printstacktrace(); 24 4
(SAX) (SAX) Tapahtumaperustaisesta jäsennyksestä käytetään nimitystä SAX (Simple API for XML) Periaate: XML-aineistoa käsitellään tietovirtana, jota jäsentäjä lukee ja tarkkailee sekä ilmoittaa sovellukselle havainnoistaan vastaan tulevien dokumentin osien suhteen Ilmoitukset annetaan aktivoimalla tarkoitusta varten määritelty tapahtumankäsittelijä Ilmoitusten kohteita: dokumentti alkaa tavataan alkutagi tavataan lopputagi tavataan nimiavaruusmäärittely tavataan tyhjää tilaa tavataan merkkitietojakso dokumentti päättyy 25 26 (SAX) (SAX) Käsittelijöille on valmiiksi määritelty rajapinta. Sovelluskohtaisesti määritellään rajapinnan toteutus. Jäsentäjä ilmoittaa tapahtumasta kutsumalla rajapinnan toteutusta (call-back) Toteutus on kerrottava jäsentäjälle ennen jäsennyksen aloitusta. public class Trace extends DefaultHandler { int indent = 0; void printindent() { for (int i=0; i<indent; i++) System.out.print("-"); public void startdocument() { System.out.println("start document"); public void enddocument() { System.out.println("end document"); 27 28 (SAX) (SAX) public void startelement(string uri, String localname, String qname, Attributes atts) { System.out.println("start element: " + qname); indent++; paikallinen nimi public void endelement(string uri, String localname, String qname) { indent--; System.out.println("end element: " + qname); public void ignorablewhitespace(char[] ch, int start, int length) { System.out.println("whitespace, length " + length); public void processinginstruction(string target, String data) { System.out.println("processing instruction: " + target); public void characters(char[] ch, int start, int length){ System.out.println("character data, length " + length); nimiavaruus attribuutit arvoineen 29 30 5
(SAX) (SAX) public static void main(string[] args) { try { Trace tracer = new Trace(); XMLReader reader = XMLReaderFactory.createXMLReader(); reader.setcontenthandler(tracer); reader.parse(args[0]); catch (Exception e) { e.printstacktrace(); startelement käsittelijä valmistelee tietorakenteet ottamaan vastaan elementin tietoja tallentaa tai käsittelee attribuuttiarvot endelement käsittelijä tallentaa kootun tekstisisällön ja mahdollisesti muunkin sisällön IgnorableWhitespace ja characters käsittelijät kokoavat tekstidataa 31 32 (SAX) (SAX) Käytettäessä SAX-jäsennystä on sovelluksen ratkaistava, miten jäsennetty tieto tallennetaan muistiin - vai tallennetaanko lainkaan Sovellus voi rakentaa DOM-puun tai käyttää jotain muuta tehokkaampaa rakennetta - taulukoita, kokoelmia DOM käyttää runsaasti muistitilaa Koko rakennetta ei välttämättä tarvita Sovelluksen on yleensä pidettävä kirja jäsennyksen etenemisestä jonkinlaisen jäsennyspinon avulla SAX:iin liittyen on mahdollista käyttää suotimia pilkkomaan käsittelyä 33 34 (XMLpull) Tapahtumapohjaisen push-tekniikan (tapahtumia pakkosyötetään) vaihtoehdoksi on tarjolla myös perinteisempi sovellusohjelman kontrolloima jäsennystekniikka (XMLPull) ja sitä tukevia ohjelmakirjastoja Yksinkertainen, nopea Esimerkki: http://www.xmlpull.org/v1/download/unpacked/src/jav a/samples/myxmlpullapp.java 35 6