I Dati biblioteca: contiene piu’ libro e schede prestito libro: identificato da un codice univoco, presenta un titolo, un autore formato da nome e cognome, un editore ed alcune parole chiave. Inoltre mantiene il tipo di carta su cui e’ stampato (normale, lucida, patinata, riciclata) Prestito: prevede un utente che ha ricevuto in prestito un certo libro identificato dal suo codice Secondo il modello Relazionale I dati relativi ai Libri “R414” , “normale” , “2001: Odissea nello spazio” , “Clarke” , “Arthur Charles” , “Rizzoli” , “romanzo” , fantascienza” “Z096” , “normale” , “Io Robot” , “Asimov” , “Isaac” , “Mondadori” , “fantascienza” “A438” , “lucida” , “Promessi Sposi” , “Manzoni” , “Alessandro” , “Mondadori” , “romanzo”, “storico” I dati relativi ai Prestiti dei Libri “A438” , “Damon” , “Crudelia” , “Z096” , “Ghini” , “Vittorio” , I dati saranno mantenuti in un documento XML. Il formato XML prevede di organizzare la struttura dei dati in forma gerarchica, in forma di albero, in cui ogni nodo dell’albero (quelli in nero) e’ un elemento del documento XML Quelle che nel modello relazionale sono gli identificatori univoci dei record, e le chiavi esterne, nel modello XML possono essere realizzate mediante gli “attributi” dei nodi (in clore rosso) per i quali e’ permesso di specificare alcuni vincoli. biblioteca libro libro codice tipocarta titolo autore editore nome cognome libro parola_ chiave prestito parola_ chiave prestito prestito codicelibro utente nome cognome Struttura e componenti di un documento XML Un documento XML è composto da tre parti: • Dichiarazione XML, serve a specificare la versione del linguaggio XML usato • Dichiarazione della Struttura del Documento, che e’ opzionale, può anche essere contenuta in un file esterno, ed è esprimibile in due diversi linguaggi: o Document Type Definition (DTD), piu’ semplice da esprimere e da capire, non permette pero’ di esprimere requisiti complicati. o XML-Schema, linguaggio ottenuto da XML, parecchio complicato ma potente, perchè permette di descrivere strutture e requisiti molto complessi Inizialmente utilizzeremo solo DTD, per cominciare ad usare e navigare documenti XML, successivamente descriveremo ed utilizzeremo anche XML-Schema • Contenuto del Documento (con i tag di markup), sono i dati veri e propri del documento, integrati con i tag del linguaggio, per separare ed identificare le diverse componenti. Il contenuto del documento e’ formato da diversi componenti, che sono: Elementi - Gli elementi sono le parti di documento dotate di un senso proprio. Il titolo, l’autore, i paragrafi del documento sono tutti elementi. Un elemento è individuato da un tag iniziale, un contenuto ed un tag finale. Non confondere i tag con gli elementi! <titolo>Tre uomini in barca</titolo> Attributi - Gli attributi sono informazioni aggiuntive sull’elemento che non fanno effettivamente parte del contenuto (meta-informazioni). Essi sono posti dentro al tag iniziale dell’elemento. Tipicamente hanno la forma nome=valore <libro codice=“A438”>…</libro> Entità - Le entità sono frammenti di documento memorizzati separatamente e richiamabili all’interno del documento. Esse permettono di riutilizzare lo stesso frammento in molte posizioni garantendo sempre l’esatta corrispondenza dei dati, e permettendo una loro modifica semplificata. &FV; #PCDATA - Rappresenta il contenuto vero e proprio del documento. Esso corrisponde alle parole, gli spazi e la punteggiatura che costituiscono il testo. Viene anche detto #PCDATA (Parsed Character DATA) perché XML usa questo nome per indicare il contenuto di elementi di testo. Commenti - I documenti XML possono contenere commenti, ovvero note da un autore all’altro, da un editore all’altro, ecc. Queste note non fanno parte del contenuto del documento, e le applicazioni XML li ignorano. Sono molto comodi per passare informazioni tra un autore e l’altro, o per trattenere informazioni per se stessi, nel caso le dimenticassimo. <!--Questa parte è ignorata da XML --> text - E’ importante notare come gli elementi semplici, ovvero gli elementi composti da un tag iniziale, un tag finale, ed una stringa testuale (il contenuto dell’elemento), vengono considerati dal parser XML come dei nodi in cui esiste un figlio di tipo text, e questo figlio e’ la proprio quella stringa di testo. Quindi, la selezione della stringa testuale puo’ essere fatta mediante la sintassi seguente: child::text() Il documento XML <? xml version=”1.0” ?> <!DOCTYPE biblioteca SYSTEM "biblioteca.dtd" > <biblioteca> <libro codice=”R414” tipocarta=”normale” > <titolo>2001: Odissea nello spazio</titolo> <autore> <cognome>Clarke</cognome> <nome>Arthur Charles</nome> </autore> <editore>Rizzoli</editore> <parola_chiave>romanzo</parola_chiave> <parola_chiave>fantascienza</parola_chiave> </libro> <libro codice=”Z096” tipocarta=”normale”> <titolo>2001: Io Robot</titolo> <autore> <cognome> Asimov </cognome> <nome> Isaac </nome> </autore> <editore>Mondadori</editore> <parola_chiave>fantascienza</parola_chiave> </libro> <libro codice=”A438” tipocarta=”lucida” > <titolo> Promessi Sposi</titolo> <autore> <cognome> Alessandro </cognome> <nome> Manzoni </nome> </autore> <editore>Mondadori</editore> <parola_chiave>romanzo</parola_chiave> <parola_chiave>storico</parola_chiave> </libro> <prestito codicelibro=”A438”> <utente> <cognome> Crudelia </cognome> <nome> Damon </nome> </utente> </prestito> <prestito codicelibro=”Z096”> <utente> <cognome> Ghini </cognome> <nome> &V; </nome> </utente> </prestito> </biblioteca> --------------------------------------------------------------------------------------------------Dichiarazione XML, la parte indispensabile con la dichiarazione della versione del linguaggio XML usato <?xml version=”1.0”?> --------------------------------------------------------------------------------------------------Document Type Definition (DTD) <!DOCTYPE biblioteca [ <!ELEMENT biblioteca (libro+ , prestito*)> <!ELEMENT libro (titolo, autore+, editore, parola_chiave+)> <!ATTLIST libro codice ID #REQUIRED tipocarta CDATA “normale” > <!ELEMENT titolo (#PCDATA)> <!ELEMENT autore (cognome, nome)> <!ELEMENT editore (#PCDATA)> <!ELEMENT parola_chiave (#PCDATA)> <!ELEMENT cognome (#PCDATA)> <!ELEMENT nome (#PCDATA)> <!ELEMENT prestito (utente)> <!ATTLIST prestito codicelibro IDREF #REQUIRED> <!ELEMENT utente (cognome, nome)> <!ENTITY V “Vittorio“ )> ]> Univocità degli Identificativi ID In un documento non possono esistere due attributi di tipo ID che assumono lo stesso valore. Ovvero, definiti cosi’ gli attributi codice ed etichetta come identificatori di tipo ID <!ATTRLIST libro codice ID #REQUIRED> <!ATTRLIST barattolo etichetta ID #REQUIRED> allora due righe come queste di seguito non sono ammesse in uno stesso documento. <libro codice=”96”> ……. <barattolo etichetta=”96”> ERRATO Integrita’ Referenziale Se in un documento definisco un attributo di tipo IDREF allora questo deve assumere il valore di un attributo ID gia’ esistente nello stesso documento. <!ATTRLIST libro codice ID #REQUIRED> <!ATTRLIST prestito codicelibro IDREF #REQUIRED> Affinché codicelibro assuma valore 96 e’ necessario che uno ed uno solo attributo di tipo ID, nel documento stesso, assuma valore 96. <libro codice=”96”> ……. <prestito codicelibro=”96”> <?xml version="1.0"?> <!DOCTYPE biblioteca [ <!ELEMENT biblioteca (libro+,prestito*) > <!ELEMENT libro (titolo, autore+, editore, parola_chiave) > <!ATTLIST libro codice ID #REQUIRED tipocarta CDATA "normale" > <!ELEMENT titolo (#PCDATA) > <!ELEMENT autore (cognome,nome) > <!ELEMENT editore (#PCDATA) > <!ELEMENT parola_chiave (#PCDATA) > <!ELEMENT cognome (#PCDATA) > <!ELEMENT nome (#PCDATA) > <!ELEMENT prestito (utente) > <!ATTLIST prestito codice ID #REQUIRED > <!ELEMENT utente (cognome,nome) > ]> <biblioteca> <libro codice="R414" tipocarta="normale"> <titolo>2001: Odissea nello spazio</titolo> <autore> <cognome>Clarke</cognome> <nome>Arthur Charles</nome> </autore> <editore>Rizzoli</editore> <parola_chiave>romanzo</parola_chiave> <parola_chiave>fantascienza</parola_chiave> </libro> <libro codice="Z096" tipocarta="normale"> <titolo>Io Robot</titolo> <autore> <cognome>Asimov</cognome> <nome>Isaac</nome> </autore> <editore>Mondadori</editore> <parola_chiave>fantascienza</parola_chiave> </libro> <libro codice="A438" tipocarta="lucida"> <titolo>Promessi Sposi</titolo> <autore> <cognome>Manzoni</cognome> <nome>Alessandro</nome> </autore> <editore>Mondadori</editore> <parola_chiave>romanzo</parola_chiave> <parola_chiave>storico</parola_chiave> </libro> <prestito codicelibro="A438" > <utente> <cognome>Damon</cognome> <nome>Crudelia</nome> </utente> </prestito> <prestito codicelibro="Z096" > <utente> <cognome>Ghini</cognome> <nome>Vittorio</nome> </utente> </prestito> </biblioteca> Ricerche in documenti XML - XPath XPath Gli XPath sono una sintassi comune per esprimere locazioni all’interno di documenti XML. XPath opera sulla struttura logica del documento, non su quella sintattica, usando una sintassi non XML accettabile all’interno di URI e attributi. Un XPath è un espressione che restituisce un oggetto di uno di questi quattro tipi: • Un booleano • Una stringa • Un numero • Un insieme di nodi (nodi elemento, nodi attributi, nodi testo) Introduzione Informale ai Location Path Il tipo più importante di XPath è il Location Path. Questo può essere o assoluto o relativo. Un Location Path assoluto inizia con ‘/’. Un Location Path è composto di una sequenza di passi di locazione (Location Steps) separati da ‘/’, e letti da sinistra a destra. Ogni termine individua più precisamente un frammento della risorsa individuata in precedenza. Esempi notevoli: percorsi assoluti che partono dalla radice Es.: /child::biblioteca/child::libro/child::autore/child::nome identifica gli elementi “nome” che siano figli diretti di un elemento “autore” che sia figlio diretto di un nodo “libro“ che sia figlio diretto della radice “biblioteca” del documento XML. Es.: /child::biblioteca/descendant::nome Es.: /child::biblioteca///::nome identifica gli elementi “nome” che discendano anche non direttamente dalla radice “biblioteca” del documento XML. Attenzione, che questo vuol dire che io otterro’ sia nome come figlio di autore, sia nome come figlio di utente. Es.: Es.: /child::biblioteca/child::libro[position()=3]/child::autore/child::nome /child::biblioteca/child::libro[3]/child::autore/child::nome identifica gli elementi “nome” che siano figli diretti di un elemento “autore” che sia figlio diretto di un nodo “libro“ che sia il terzo figlio diretto della radice “biblioteca” del documento XML. Es.: /child::biblioteca/child::libro[last()]/child::autore/child::nome identifica gli elementi “nome” che siano figli diretti di un elemento “autore” che sia figlio diretto di un nodo “libro“ che sia l’ultimo figlio diretto della radice “biblioteca” del documento XML. Es.: Es.: /child::biblioteca/child::libro[Attribute::tipocarta=’lucida’]/child::autore/child::nome /child::biblioteca/child::libro[@tipocarta=’lucida’]/child::autore/child::nome identifica gli elementi “nome” che siano figli diretti di un elemento “autore” che sia figlio diretto di un nodo “libro“ che abbia come attributo tipocarta il valore “lucida“ e che sia figlio diretto della radice “biblioteca” del documento XML. Es.: /child::biblioteca/descendant::autore[cognome != ‘Asimov’] identifica tutti gli elementi “autore”, discendenti della radice “biblioteca” del documento XML, che abbiano cognome diverso da ‘Asimov‘. Es.: /child::biblioteca/descendant::autore[cognome = ‘Asimov’]/parent::libro/child::editore identifica tutti l’elemento editore del libro di Asimov. Prima trova l’elemento Asimov, poi sale di un livello e trova il libro, poi scende di livello cercando l’autore. Es.: /child::biblioteca/child::libro[last()]/child::autore/child::nome identifica gli elementi “nome” che siano figli diretti di un elemento “autore” che sia figlio diretto di un nodo “libro“ che sia l’ultimo figlio diretto della radice “biblioteca” del documento XML. Esempi notevoli: ricerca di valori testuali (non di elementi) /child::biblioteca/descendant::autore[cognome=’Asimov’]/parent::libro/child::editore/child::text() Restituisce la stringa di testo (non un elemento) che e’ il valore testuale dell’elemento editore del libro di Asimov. Il valore dell’elemento viene pensato come un figlio testuale ( usare funzione text() ) dell’elemento stesso. /child::biblioteca/descendant::autore[cognome=’Asimov’]/parent::libro/attribute::tipocarta Restituisce la stringa di testo (non un elemento) che e’ il valore testuale dell’attributo tipocarta del libro di Asimov. Il valore dell’attributo e’ un dato testuale. Esempi notevoli: percorsi assoluti che partono da un nodo identificato dal suo identificatore univoco Es.: id( ‘Z096’ ) notare gli apici semplici identifica e restituisce, se esiste, quell’unico elemento che abbia un attributo univoco (cioè quello di tipo ID) che abbia il valore indicato tra le parentesi. Nel nostro esempio restituisce l’elemento di tipo libro che ha come attributo codice il valore (la stringa testuale) ‘A438’, cioe’ il libro di Asimov IO Robot. Es.: id( ‘Z096’ )/child::autore/child::nome identifica e restituisce, se esiste, il nome dell’autore dell’unico elemento che abbia come attributo univoco il valore indicato tra le parentesi. Nel nostro esempio restituisce l’elemento di tipo nome “Isaac“. Es.: id( ‘Z096’ )/parent::* identifica e restituisce, l’elemento padre del nodo che ha come attributo univoco il valore indicato tra le parentesi. Nel nostro esempio poiché l’elemento con quel codice e’ un libro, il padre dell’elemento sara’ biblioteca, e l’espressione restituisce tutto l’elemento biblioteca. Es.: id( ‘Z096’ )/attribute::tipocarta identifica e restituisce la stringa di testo che e’ il tipo di carta del libro di Aimov Esempi notevoli: composizione di condizioni su nodi: operatori logici OR e NAD Es: /child::biblioteca/descendant::autore[cognome=’Asimov’ or nome=’Alessandro’]/parent::libro Restituisce gli elementi libro scritti o da Isaac Asimov o da Alessandro Manzoni. Es.: /child::biblioteca/descendant::autore[cognome=’Asimov’ and nome=’Isaac’]/parent::libro Restituisce gli elementi libro scritti da un autore che deve avere cognome Asimov e nome Isaac. /child::biblioteca/descendant::autore[cognome=’Asimov’ or ( nome=’Alessandro’ and cognome=’Manzoni’) ]/parent::libro Restituisce gli elementi libro scritti o un autore che ha cognome Asimov oppure da un autore che deve avere nome Alessandro e cognome Manzoni. Esempi notevoli: uso di funzioni su stringhe Es.: analoghi /child::biblioteca/child::prestito/child::utente/child::cognome[contains(child::text(),'ini')] /child::biblioteca/child::prestito/child::utente[contains(child::cognome/child::text(),'ini')] /child::biblioteca/child::prestito/child::utente[contains(child::cognome,'ini')] Esempi notevoli: annidamento delle Location Path Premessa: /child::biblioteca/child::prestito/child::utente[nome='Crudelia']/parent::presti to/attribute::codicelibro con questo trovo il valore testuale del codice del libro prestato a Crudelia, e poi, qui sotto, lo userò per trovare il libro prestato a Crudelia e quindi il titolo id( /child::biblioteca/child::prestito/child::utente[nome='Crudelia']/parent::pre stito/attribute::codicelibro )/child::titolo/child::text() ottiene il titolo del libro prestato a Crudelia. Notate che ho utilizzato l’ Xpath precedente e l’ho inserita come argomento della funzione id(). Notate anche che ho inserito come argomento della funzione id NON l’elemento titolo bensì la stringa di testo che e’ il valore dell’elemento titolo. In modo analogo, qui sotto, notare il modo differente in cui inserisco la condizione sul nodo utente, in modo da non dover scendere e poi dover risalire con parent. id( /child::biblioteca/child::prestito[ child::utente/child::nome='Crudelia' ] /attribute::codicelibro )/child::titolo/child::text() Esempi notevoli: unione dei risultati delle ricerche Es.: id( ‘Z096’ ) | id( ‘A438’ ) notare gli apici semplici Restituisce un insieme di due elementi, ciascuno dei quali ha come identificatore univoco uno dei due valori tra le parentesi. Quindi restituisce i due elementi libro di Asimov e libro di Manzoni. Esempi notevoli: selezione di un dato sottolivello Es.: /child::biblioteca/child::*/ child::*/child::text Restituisce l’insieme dei valori testuali degli elementi semplici che siano nipoti di biblioteca (cioe’ figli dei figli di biblioteca e che abbiano come figlio un dato testuale). In definitiva, restituisce l’insieme delle stringhe di testo contenute negli elementi titolo, editore, parola_chiave Esempi notevoli: interrogazione annidata, con CONFRONTO tra ELEMENTI COMPOSITI L’insieme di tutti i libri degli autori di cui io (Ghini) ho libri in prestito. Questa ricerca viene svolta in cinque passi successivi: 1) Prima cerco il codice univoco dei libri che io (ghini) ho in prestito, 2) poi cerco questi libri, 3) poi cerco gli autori di questi libri, 4) ed infine cerco tutti i libri di questi autori. /child::biblioteca/child::libro[ child::autore = id( /child::biblioteca/child::prestito[ child::utente/child::cognome='Ghini' ]/attribute::codicelibro )/child::autore ] notare che faccio un confronto non tra elementi semplici, ma tra elementi compositi (nel caso specifico, confronto gli autori, che sono formati da diverse parti) Sintassi generale delle XPath Alla luce degli esempi precedenti possiamo così sintetizzare: un XPath è un espressione che restituisce un oggetto di uno di questi quattro tipi: • Un booleano • Una stringa • Un numero • Un insieme di nodi (nodi elemento, nodi attributi, nodi testo) Il tipo più importante di XPath è il Location Path. Un Location Path è composto di una sequenza di passi di locazione (Location Steps) separati da ‘/’, e letti da sinistra a destra. Ogni termine individua più precisamente un frammento della risorsa individuata in precedenza. step step step step /child::biblioteca/descendant::autore[cognome=‘Asimov’]/parent::libro/child::editore • Si parte da una data posizione (il cosiddetto Nodo Contesto) che può essere: - Assoluta / id( valoreidentificatoreunivoco ) la radice del documento il nodo con quell’identificatore - Relativa Il nodo a cui sono arrivato con il precedente step • Ad ogni passo (step) • • • • Indico la direzione in cui cerco i nuovi nodi (si chiama asse, axis ) Considero i nodi che incontro nella direzione scelta. Seleziono questi nodi e tengo solo quelli che superano le condizioni che impongo (test di nodo) I nodi selezionati diventano la posizione di partenza del nuovo step, in cui applichero’ una nuova direzione e nuove condizioni. Direzioni (assi, AxisName) 'ancestor' 'ancestor-or-self' 'attribute' 'child' 'descendant' 'descendant-or-self' 'following' 'following-sibling' 'namespace' 'parent' 'preceding' 'preceding-sibling' 'self' tutti i nodi antenati gli attributi i nodi figli diretti i nodi discendenti (figli, nipoti, ..) il nodo padre il nodo stesso Test di Nodo, ovvero test sull’insieme dei nodi collezionati ad un dato step sul valore di un elemento testuale sul valore di un attributo Funzioni sugli insieme di nodi, ovvero funzioni predefinite con cui posso effettuare operazioni di test. number last() number position() number count( insieme_di_nodi) nodo id( identificatore_univoco) Funzioni sulle stringhe string string(object?) string concat(string, string, string*) boolean starts-with(string, string) boolean contains(string, string) string substring-before(string, string) string substring-after(string, string) string substring(string, number, number?) number string-length(string?) string normalize-space(string?) string translate(string, string, string) Funzioni sui numeri number number(object?) number sum(node-set) number floor(number) number ceiling(number) number round(number) Riferimenti Bibliografici [1] "Extensible Markup Language (XML) 1.0 Specification", available http://www.w3.org/TR/1998/REC-xml-19980210.html [2] "XML Path Language (XPath) Version 1.0, available http://www.w3.org/TR/1999/REC-xpath-19991116 [3] "XML Schema Home Page", http://www.w3.org/XML/Schema [4] "Extensible Stylesheet Language (XSL) Version 1.1", http://www.w3.org/TR/xsl/ [5] "XQuery 1.0: An XML Query Language", http://www.w3.org/TR/xquery/