xmldb - Oracle Italia by Massimo Ruocchio

FO C U S
Le soluzioni di Oracle
La principale innovazione presente nella
release 2 di Oracle9i è il database XML
chiamato XDB. Analizziamo le principali
caratteristiche di questo importante strumento
Oracle 9.2
XML Database
[email protected]
di Massimo Ruocchio
È laureato in matematica ed è certificato Oracle
Application Developer. Si occupa di analisi, progettazione e sviluppo di applicazioni software
I
n un articolo pubblicato nel numero di Gennaio 2002
di Computer Programming [3], è stato introdotto il
tema dei database XML analizzando, a titolo d’esempio,
tre prodotti di tipo diverso. Tra i prodotti presentati
Oracle8i, che non usciva benissimo dal confronto con strumenti “specializzati” nella gestione di documenti XML.
Con la versione 9.2 del database, Oracle si propone di porre
rimedio a questa situazione fornendo XDB.
XDB non è un prodotto a sé; è costituito da una serie di
funzionalità, incluse nell’istallazione base di Oracle9i, per la
gestione dei documenti XML. I due elementi principali di
XDB sono il datatype XMLType, già presente nella release
precedente ma decisamente migliorato nell’ultima, ed il
repository XML. Nei prossimi paragrafi descriveremo questi
due strumenti.
XMLType
Un documento XML può essere archiviato in un database
relazionale in due modi:
Monolitico, in un campo di tipo CLOB
Segmentato, dato-per-dato in tabelle relazionali (archiviazione strutturata)
Fino all’ultima release di Oracle9i bisognava decidere
quale tipo di archiviazione utilizzare e poi progettare sia
il database sia l’applicazione in maniera coerente con la
scelta effettuata.
Il datatype XMLType consente di gestire i documenti XML
presenti nel database a prescindere dalla tecnica di archiviazione scelta. In più, XMLType fornisce una serie di metodi
per il supporto dei principali standard XML: XML Schema,
Xpath, Indici gerarchici, ecc.
Il datatype XMLType può essere utilizzato sia per le colonne
delle tabelle sia come parametro di procedure e funzioni.
Quando è estratto dal database mediante una select restituisce
un frammento XML ben formato. Internamente al database,
invece, è conservato con una rappresentazione ad albero, tipo
DOM per intenderci.
Per creare una tabella che contenga dati di tipo XMLType si
hanno due scelte:
OraXmlDb
Creare una tabella basata solo sul tipo XMLType (una
sorta di array di XMLType)
Creare una normale tabella relazionale in cui una colonna
sia del tipo XMLType
In entrambi i casi bisogna specificare il tipo di archiviazione che s’intende utilizzare e, opzionalmente, lo schema
XML che i documenti archiviati devono rispettare.
Ecco la prima grande innovazione: il supporto di XML
Schema. Per maggiori informazioni su XML schema si può
consultare [4].
Uno schema, prima di essere utilizzato, deve essere registrato nel database mediante il package dbms_xmlschema.
Una volta registrato, lo schema è memorizzato nel repository XML, di cui parleremo più avanti, a fronte di un URL.
Questo URL deve essere utilizzato nell’istruzione CREATE
TABLE per assegnare lo schema al campo XMLType. Nel
momento della registrazione dello schema, il DBMS definisce automaticamente le tabelle, i datatype e gli oggetti
necessari per conservare i dati dei documenti che faranno
riferimento a quello schema. Per gestire l’associazione tra
gli elementi dello schema ed i tipi creati in fase di registrazione, allo schema vengono aggiunti alcuni attributi,
ad esempio oraxdb:SQLType, oraxdb:SQLName e oraxdb:
SQLSchema. Se si intendono utilizzare tipi e tabelle definiti
dall’utente basta modificare, dopo averli creati, questi attributi dello schema.
Vediamo le due sintassi possibili per creare una tabella con
una colonna di tipo XMLType:
CREATE TABLE [schema.] table_name OF XMLTYPE
[XMLTYPE XMLType_storage]
[XMLSCHEMA “XMLSchema URL”];
LISTATO 1 Una funzione che legge dal file system
create or replace function
getdocument(dir varchar2, filename varchar2)
return clob authid current_user is
xbfile bfile;
xclob clob;
begin
xbfile := bfilename(dir, filename);
dbms_lob.open(xbfile);
dbms_lob.createtemporary(xclob, TRUE, dbms_lob.session);
dbms_lob.loadfromfile(xclob, xbfile,
dbms_lob.getlength(xbfile));
dbms_lob.close(xbfile);
return xclob;
end;
/
35
CP 119
FO C U S
oppure
FIGURA 1 Creazione di una risorsa mediante Oracle Enterprise Manager
CREATE TABLE [schema.] table_name
(column_name XMLTYPE [NOT NULL])
[XMLTYPE COLUMN “column_name” XMLType_storage]
[XMLSCHEMA “XMLSchema URL”];
In sostanza l’oggetto creato non cambia; nel primo caso
Oracle attribuisce un nome di sistema alla colonna XMLType.
Alla seconda istruzione possono essere aggiunte altre colonne
a piacere.
Torniamo a parlare del tipo d’archiviazione, indicato, come
si è visto, mediante la clausola XMLType_storage. Se si assegna
uno schema non c’è bisogno di indicare il tipo d’archiviazione.
I dati vengono automaticamente spacchettati e suddivisi nelle
tabelle create dal DBMS al momento della registrazione dello
schema. Se si desidera archiviare il documento per intero in
un campo CLOB basta specificare la clausola STORE AS
CLOB dove nella sintassi appare XMLTYPE_storage. Se non
si assegna uno schema, i dati sono archiviati in un campo di
tipo CLOB.
Poiché il campo XMLType è gestito internamente con una
rappresentazione ad albero proprietaria di Oracle, in fase di
inserimento o modifica dei dati bisogna convertire il documento XML che si intende inserire in un oggetto che abbia
quella struttura. Ciò può essere fatto mediante il metodo
costruttore del tipo XMLType. La sintassi per l’inserimento è
semplicemente:
insert into nome_tabella
values (xmltype(documento_xml,URL_dello_schema));
dove documento_xml può essere una stringa, una variabile
PL/SQL oppure un campo di database contenente il documento. E se si intende inserire un documento presente nel
file system? Bisogna costruirsi una funzione che, da Oracle,
legge il file e ne scarica il contenuto in una variabile CLOB
o VARCHAR2.
Nel Listato1 è riportata una funzione siffatta idonea per
leggere un file contenuto nello stesso file system in cui si
trova il database. La funzione è riportata dal forum della
Oracle dedicato a XDB [7]. Per inserire dati in XDB è possibile anche utilizzare SQL*Loader.
XDB è dedicato alla
gestione dei documenti XML
La modifica dei dati richiede l’utilizzo della funzione UPDATEXML.
Questa funzione prende in input tre valori: il documento
XML (in formato XMLType) da modificare, un percorso
XPath che indica il valore da sostituire, il nuovo valore in
formato alfanumerico. La sintassi è la seguente:
update nome_tabella
set nome_campo = UPDATEXML( documento_xml,
xpath_da_sostituire,
nuovo_valore);
Bisogna notare che l’istruzione UPDATE sostituisce
sempre tutto il contenuto del campo XMLType: non è pos-
CP 119
36
sibile modificare un solo dato del documento (a meno di
modificare direttamente la tabella relazionale che contiene
il singolo dato).
Abbiamo già introdotto Xpath. Xpath è un linguaggio
standard del W3C con cui è possibile indicare la posizione di
frammenti (o singoli nodi) all’interno di un documento XML;
per far ciò si utilizzano dei percorsi tipo quelli adoperati nei file
system. Xpath può essere utilizzato anche come linguaggio di
query, perché dà la possibilità di indicare anche delle condizioni di estrazione oltre alla posizione dell’oggetto da estrarre.
Ed è proprio come linguaggio di query che Xpath è utilizzato
in XDB, congiuntamente a SQL, per estrarre dati da campi di
tipo XMLType.
XDB supporta Xpath tramite alcune nuove funzioni, ad
esempio extractValue, updatexml, xmltype.extract, existsNode. La differenza tra xmltype.extract ed extractValue è
che la prima ritorna un frammento XML ben formato mentre
la seconda ritorna sempre un singolo valore. La funzione existsNode restituisce 1 se in una variabile XMLType assegnata
esiste un certo percorso Xpath.
XML Repository
Il Repository di Oracle XML DB è una collezione di oggetti
di database organizzati in forma gerarchica.
Si può vedere il Repository come un file system, interno al
database, in cui è possibile creare directory e conservare file
di ogni genere. Tutti gli oggetti contenuti nel repository sono
chiamati risorse.
L’accesso alle risorse può essere realizzato mediante gli
strumenti solitamente utilizzati per accedere ai più diffusi file
system: FTP, HTTP, WebDAV. In particolare, la compatibilità
con WebDAV consente di navigare il Repository da Internet
Explorer e di aprire e modificare i documenti in esso contenuti
con tutti gli editor che supportano questo standard (ad esempio Microsoft Word o XML Spy di Altova).
Le risorse si dividono in due tipi: contenitori e file. In ogni
caso una risorsa può essere creata mediante l’interfaccia grafica di Oracle Enterprise Manager (OEM) – un esempio è
riportato in Figura 1 –, oppure utilizzando da PL/SQL le funzioni CREATEFOLDER e CREATERESOURCE del package DBMS_XDB.
L’interfaccia grafica è sicuramente più comoda e veloce. Per
avere informazioni sulle risorse presenti nel Repository possono essere interrogate le viste RESOURCE_VIEW e PATH_VIEW.
Per agevolare la consultazione di queste viste, Oracle mette a
disposizione le funzioni:
UNDER_PATH che ritorna 1 quando una certa risorsa si trova
EQUALS_PATH che torna 1 quando la risorsa si trova esatta-
PATH che restituisce il percorso di una risorsa
DEPTH che restituisce il numero di livelli gerarchici presenti
tra il path indicato nella UNDER_PATH e la risorsa estratta.
tra i “discendenti” di un percorso specificato
mente al path specificato
Le view PATH_VIEW e RESOURCE_VIEW sono modificabili;
mediante esse, quindi, è possibile anche aggiornare direttamente le informazioni sulle risorse contenute nel repository.
Il Repository può essere utilizzato anche per conservare le
diverse versioni di una risorsa. Infatti, quando una risorsa
è modificata, il vecchio contenuto può essere conservato,
creando una nuova versione della risorsa. La gestione delle
risorse è effettuata mediante il package DBMS_XDB_VERSION ed
è opzionale. Per abilitarla bisogna eseguire lo script PL/SQL
che segue:
declare
resid DBMS_XDB_VERSION.RESID_TYPE;
begin
resid := DBMS_XDB_VERSION.MakeVersioned(Path_della_
risorsa);
end;
/
Non per tutte le risorse possono essere gestite le versioni.
Fanno eccezione: Contenitori (le cartelle), i file ACL (di cui
parleremo dopo) ed i documenti XML archiviati in maniera
strutturata. L’ultima limitazione è molto grave e riduce fortemente l’utilità dello strumento.
Come si è già detto, si può accedere al Repository anche
mediante HTTP/WebDAV. In Figura 2 è mostrata una
videata di Internet Explorer in cui è visualizzato il contenuto
del Repository sotto la cartella di rete denominata “ruocchiolapt”, che è il nome del server Oracle. Per aggiungere il Repository alle risorse di rete basta accedervi una volta, ad esempio
digitando http://nome_computer:8080 nella barra degli indirizzi e dando invio. La porta 8080 è quella di default.
Tutti gli accessi al Repository, anche mediante FTP,
HTTP e WebDAV, sono protetti da un meccanismo di
sicurezza basato su ACL (Access Control List). Per una
data risorsa, una ACL è una lista in cui vengono elencati i
privilegi che i vari utenti/ruoli definiti nel database hanno
sulla risorsa stessa.
Le ACL possono a loro volta essere conservate nel Repository per essere utilizzate da più risorse. L’ACL è controllata ad ogni accesso alla risorsa. Anche le ACL possono
essere gestite graficamente mediante OEM oppure via
PL/SQL utilizzando il packge DBMS_XDB.
Qualche esempio
Ok, dopo tante chiacchiere vediamo qualche esempio
concreto. Tutti i file menzionati in questo paragrafo sono
disponibili sul sito FTP di Infomedia (ftp://ftp.infomedia.it/
pub/ComputerProgramming/Listati/). Per prima cosa è stato
definito uno schema XML (file anag.xsd e Listato 2). A
fronte dello schema sono stati creati sei documenti XML
contenenti anagrafiche di persone fisiche o giuridiche (file
anagN.xml).
Tutte le istruzioni SQL indicate in questo paragrafo sono
contenute nel file test.sql; nel Listato 3 è visualizzato uno
spool con tutti i risultati delle istruzioni eseguite. Il primo passo
da compiere per archiviare i dati nel database è la registrazione dello schema. Quest’attività è stata compiuta mediante
OEM (Figura 3). Allo schema è stato assegnato l’URL ‘http:
//ruocchio-lapt:8080/max/schemi/anag.xsd’. L’URL non indica
necessariamente la collocazione fisica dello schema, è solo un
nome logico con cui lo schema sarà referenziato nel database.
LISTATO 2 Lo schema XML Anag.xsd
<?xml version=”1.0” encoding=”UTF-8”?>
<xs:schema xmlns:xs=”http://www.w3.org/2001/XMLSchema”>
<xs:element name=”anagrafica”>
<xs:complexType>
<xs:sequence>
<xs:element ref=”denominazione”/>
<xs:element ref=”indirizzo”/>
</xs:sequence>
<xs:attribute name=”flag_fis_giu” use=”required”>
<xs:simpleType>
<xs:restriction base=”xs:NMTOKEN”>
<xs:enumeration value=”F”/>
<xs:enumeration value=”G”/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
<xs:element name=”cap” type=”xs:int”/>
<xs:element name=”civico” type=”xs:string”/>
<xs:element name=”cognome” type=”xs:string”/>
<xs:element name=”comune” type=”xs:string”/>
<xs:element name=”denominazione”>
<xs:complexType>
<xs:sequence>
<xs:element ref=”titolo” minOccurs=”0”/>
<xs:element ref=”nome” minOccurs=”0”/>
<xs:element ref=”cognome” minOccurs=”0”/>
<xs:element ref=”ragsoc” minOccurs=”0”/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name=”indirizzo”>
<xs:complexType>
<xs:sequence>
<xs:element ref=”via”/>
<xs:element ref=”civico”/>
<xs:element ref=”cap”/>
<xs:element ref=”comune”/>
<xs:element ref=”provincia”/>
<xs:element ref=”telefono”/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name=”nome” type=”xs:string”/>
<xs:element name=”provincia” type=”xs:string”/>
<xs:element name=”ragsoc” type=”xs:string”/>
<xs:element name=”telefono” type=”xs:string”/>
<xs:element name=”titolo”>
<xs:simpleType>
<xs:restriction base=”xs:string”>
<xs:enumeration value=”Dott.”/>
<xs:enumeration value=”Sig.”/>
<xs:enumeration value=”Cav.”/>
<xs:enumeration value=”Avv.”/>
<xs:enumeration value=”Ing.”/>
<xs:enumeration value=”Gr. Uff.”/>
<xs:enumeration value=”Comm.”/>
<xs:enumeration value=”On.”/>
<xs:enumeration value=”Sen.”/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name=”via” type=”xs:string”/>
</xs:schema>
37
CP 119
FO C U S
Una volta registrato lo schema, XDB crea autonomamente
i datatype e le tabelle da utilizzare per caricare gli elementi
dei documenti XML che lo referenziano. Nel file allegato
AnagORA.xsd c’è lo schema XML con le modifiche apportate
da XDB per realizzare l’archiviazione strutturata. Per vedere
ciò che è stato creato, eseguiamo le query:
select type_name, typecode from user_types;
insert into anagrafiche
select 6, xmltype(getdocument(‘CARTELLA’,’anag6.xml’),
‘http://ruocchio-lapt:8080/max/schemi/anag.xsd’)
from dual;
Veniamo alle query (i risultati sono in Listato 3).
Per prima cosa ci interessa ottenere un elenco dei soggetti
inseriti in tabella con i relativi numeri di telefono.
Bisogna distinguere tra persone fisiche e giuridiche:
select table_name from user_xml_tables;
Passiamo alla creazione della tabella deputata a contenere
le nostre anagrafiche. Se intendiamo archiviare solo i documenti XML ci basta un array di XMLType, possiamo utilizzare
l’istruzione:
CREATE TABLE ANAGRAFICHE OF SYS.XMLTYPE
XMLSCHEMA “http://ruocchio-lapt:8080/max/schemi/anag.xsd”
ELEMENT “anagrafica”;
select decode(extractvalue(anagrafica,’./anagrafica/
@flag_fis_giu’),
‘F’, extractvalue(anagrafica,’./anagrafica/
denominazione/cognome’),
‘G’, extractvalue(anagrafica,’./anagrafica/
denominazione/ragsoc’)) Denominazione,
extractvalue(anagrafica,’./anagrafica/
indirizzo/telefono’) Telefono
from anagrafiche;
Noi vogliamo che nella tabella ANAGRAFICHE ci sia anche
un progressivo numerico e, dunque, utilizziamo l’istruzione:
Il datatype XMLType consente di
CREATE TABLE ANAGRAFICHE
(PROGR NUMBER NOT NULL,
ANAGRAFICA XMLTYPE NOT NULL)
XMLTYPE COLUMN “ANAGRAFICA”
XMLSCHEMA “http://ruocchio-lapt:8080/max/schemi/anag.xsd”
ELEMENT “anagrafica”;
gestire i documenti XML presenti
nel database a prescindere dalla
tecnica di archiviazione scelta
Per caricare i documenti utilizziamo due tecniche. Cinque
dei sei file sono stati conservati in un campo CLOB della
tabella TEMP_CLOB. Per caricarli in ANAGRAFICHE utilizziamo
l’istruzione:
insert into anagrafiche
select rownum, xmltype(dati,
’http://ruocchio-lapt:8080/max/schemi/anag.xsd’)
from temp_clob;
Il sesto documento si trova nel file system.
Per caricarlo vogliamo utilizzare la funzione getDocument (Listato 1), che abbiamo preventivamente creato nel
database. Siccome la funzione accetta in input un identificativo di directory, possiamo crearne una con l’istruzione:
create directory CARTELLA ‘c:\massimo\articoli\oraxmldb’;
Ora possiamo caricare il documento nella tabella con l’istruzione:
FIGURA 2 Navigazione del Repository mediante Internet
Explorer
La funzione extractvalue restituisce valori singoli mentre
la funzione extract restituisce frammenti XML. Invece del
telefono, visualizziamo l’intero indirizzo:
select decode(extractvalue(anagrafica,’/anagrafica/
@flag_fis_giu’),
‘F’, extractvalue(anagrafica,’/anagrafica/
denominazione/cognome’),
‘G’, extractvalue(anagrafica,’/anagrafica/
denominazione/ragsoc’)) Denominazione,
xmltype.extract(anagrafica,’/anagrafica/indirizzo’)
Indirizzo
from anagrafiche;
Passiamo alla modifica dei dati. Il primo concetto da afferrare è il seguente: un campo XMLType viene sempre modificato completamente. Anche se si deve modificare un solo
attributo in un documento di mille linee, viene sostituito
l’intero documento. Per effettuare la modifica dei dati è stata
introdotta la funzione UPDATEXML. Un esempio è il seguente:
update anagrafiche
set anagrafica = UPDATEXML(anagrafica,
‘/anagrafica/indirizzo/civico/text()’, ‘333’)
where extractvalue(anagrafica,’/anagrafica/
indirizzo/civico’)=’133’;
Sfruttando le potenzialità di Xpath, in particolare la possibilità di indicare una condizione d’estrazione tra parentesi
quadre, si può anche scrivere:
update anagrafiche
set anagrafica = UPDATEXML(anagrafica,
‘/anagrafica/indirizzo/civico[text()=”133”]/
text()’, ‘333’);
CP 119
38
LISTATO 3 I risultati delle istruzioni indicate nell’articolo
SQL*Plus: Release 9.2.0.1.0 - Production
on Mar Ago 27 11:14:43 2002
Copyright (c) 1982, 2002, Oracle Corporation.
All rights reserved.
Connesso a:
Personal Oracle9i Release 9.2.0.1.0 - Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.1.0 - Production
SQL> select type_name, typecode from user_types;
TYPE_NAME
---------------------------anagrafica196_T
denominazione193_T
indirizzo188_T
TYPECODE
---------------------------OBJECT
OBJECT
OBJECT
SQL> select table_name from user_xml_tables;
TABLE_NAME
-----------------------------anagrafica197_TAB
denominazione195_TAB
cognome194_TAB
indirizzo192_TAB
comune191_TAB
cap190_TAB
civico189_TAB
nome187_TAB
provincia186_TAB
ragsoc185_TAB
telefono184_TAB
titolo183_TAB
via182_TAB
SQL>
2
3
4
5
6
CREATE TABLE ANAGRAFICHE
(PROGR NUMBER NOT NULL,
ANAGRAFICA XMLTYPE NOT NULL)
XMLTYPE COLUMN “ANAGRAFICA”
XMLSCHEMA “http://ruocchio-lapt:8080/max/
schemi/anag.xsd”
ELEMENT “anagrafica”;
SQL> select decode(extractvalue(anagrafica,’./
anagrafica/@flag_fis_giu’),
2
‘F’, extractvalue(anagrafica,’./anagrafica/
denominazione/cognome’),
3
‘G’, extractvalue(anagrafica,’./anagrafica/
denominazione/ragsoc’)) Denominazione,
4
extractvalue(anagrafica,’./anagrafica/
indirizzo/telefono’) Telefono
5 from anagrafiche;
DENOMINAZIONE
-----------------------------Landi
Bernardi
Pizza e Fichi S.p.A.
Banda del Torchio S.r.l.
Banda Bassotti S.a.s.
Dei Paperoni
SQL> col Indirizzo for a50
SQL> select decode(extractvalue(anagrafica,’./anagrafica/
@flag_fis_giu’),
2
‘F’, extractvalue(anagrafica,’./anagrafica/
denominazione/cognome’),
3
‘G’, extractvalue(anagrafica,’./anagrafica/
denominazione/ragsoc’)) Denominazione,
4
xmltype.extract(anagrafica,’./anagrafica/
indirizzo’) Indirizzo
5 from anagrafiche;
DENOMINAZIONE
INDIRIZZO
------------------------ ------------------------------Landi
<indirizzo>
<via>delle rose</via>
<civico>92</civico>
<cap>82343</cap>
<comune>Corzano</comune>
<provincia>TC</provincia>
<telefono>0934434343</telefono>
</indirizzo>
Bernardi
<indirizzo>
<via>Vittorio Emanelele II</via>
<civico>37</civico>
<cap>132</cap>
<comune>Roma</comune>
<provincia>RM</provincia>
<telefono>0655667788</telefono>
</indirizzo>
Pizza e Fichi S.p.A.
<indirizzo>
<via>della libertà</via>
<civico>194B</civico>
<cap>30153</cap>
<comune>Frittole</comune>
<provincia>FT</provincia>
<telefono>042565758798</telefono>
</indirizzo>
Creata tabella.
SQL> desc anagrafiche
Nome
Nullo?
---------------- --------PROGR
NOT NULL
ANAGRAFICA
NOT NULL
Tipe
---------------------------NUMBER
SYS.XMLTYPE(XMLSchema
“httpp://ruocchio-lapt:8080/max/
schemi/anag.xsd” Element
“anagrafica”) STORAGE
Object-relational TYPE
“anagrafica196_T”
SQL> insert into anagrafiche
2 select rownum, xmltype(dati,’http://ruocchio-lapt:
8080/max/schemi/anag.xsd’)
3
from temp_clob;
Create 5 righe.
SQL> insert into anagrafiche
2 select 6, xmltype(getdocument(‘CARTELLA’,’anag6.xml’),
3
‘http://ruocchio-lapt:8080/max/schemi/anag.xsd’)
4
from dual;
Creata 1 riga.
SQL> col Denominazione for a30
SQL> col Telefono for a14
TELEFONO
-------------0934434343
0655667788
042565758798
09889898787
022323232322
024234343566
Banda del Torchio S.r.l. <indirizzo>
<via>dei banditi</via>
<civico>13</civico>
<cap>98212</cap>
<comune>Santa Ortensia</comune>
<provincia>XV</provincia>
<telefono>09889898787</telefono>
</indirizzo>
Banda Bassotti S.a.s.
<indirizzo>
<via>dei paperi</via>
<civico>77</civico>
<cap>54554</cap>
<comune>Paperopoli</comune>
<provincia>PP</provincia>
(segue a pagina seguente)
39
CP 119
FO C U S
segue LISTATO 3 I risultati delle istruzioni indicate nell’articolo
<telefono>022323232322</telefono>
</indirizzo>
Dei Paperoni
<indirizzo>
<via>del deposito di monete</via>
<civico>133</civico>
<cap>55445</cap>
<comune>Paperopoli</comune>
<provincia>PP</provincia>
<telefono>024234343566</telefono>
</indirizzo>
SQL> update anagrafiche
2
set anagrafica = UPDATEXML(anagrafica,
3
‘/anagrafica/indirizzo/civico
[text()=”133”]/text()’,
4 ‘333’);
Aggiornate 6 righe.
SQL> select decode(extractvalue(anagrafica,’/anagrafica/
@flag_fis_giu’),
2
‘F’, extractvalue(anagrafica,’/anagrafica/
denominazione/cognome’),
3
‘G’, extractvalue(anagrafica,’/anagrafica/
denominazione/ragsoc’)) Denominazione,
4
xmltype.extract(anagrafica,’/anagrafica/
indirizzo’) Indirizzo
5 from anagrafiche
6 where progr=6;
DENOMINAZIONE
INDIRIZZO
--------------------- -----------------------------------Dei Paperoni
<indirizzo>
<via>del deposito di monete</via>
<civico>333</civico>
<cap>55445</cap>
<comune>Paperopoli</comune>
<provincia>PP</provincia>
<telefono>024234343566</telefono>
</indirizzo>
SQL> roll;
Completato rollback.
SQL> update anagrafiche
2
set anagrafica = UPDATEXML(anagrafica,
3
‘/anagrafica/indirizzo/civico/text()’,
4
‘333’)
5 where extractvalue(anagrafica,’/anagrafica/
indirizzo/civico’)=’133’;
SQL> update anagrafiche
2
set anagrafica = UPDATEXML(anagrafica,
3
‘/anagrafica/@flag_fis_giu’,’S’)
4 where extractvalue(anagrafica,’/anagrafica/
denominazione/nome’)=’Paperone’;
update anagrafiche
*
ERRORE alla riga 1:
ORA-31038: Valore enumeration S non valido
SQL> select decode(extractvalue(anagrafica,’/anagrafica/
@flag_fis_giu’),
2
‘F’, extractvalue(anagrafica,’/anagrafica/
denominazione/cognome’),
3
‘G’, extractvalue(anagrafica,’/anagrafica/
denominazione/ragsoc’)) Denominazione,
4
xmltype.extract(anagrafica,’/anagrafica/
indirizzo’) Indirizzo
5 from anagrafiche
6 where progr=6;
DENOMINAZIONE
INDIRIZZO
--------------------- -----------------------------------Dei Paperoni
<indirizzo>
<via>del deposito di monete</via>
<civico>333</civico>
<cap>55445</cap>
<comune>Paperopoli</comune>
<provincia>PP</provincia>
<telefono>024234343566</telefono>
</indirizzo>
SQL> select path(0) percorso, depth(0) livello
2
from resource_view
3
where under_path(res,3,’/max’,0) = 1;
PERCORSO
LIVELLO
------------------------------------ ---------/anagrafiche/anag5.xml
2
/squadre/italia.xml
2
/anagrafiche/anag6.xml
2
/ord.xml
1
/anagrafiche
1
/anagrafiche/anag3.xml
2
/anagrafiche/anag1.xml
2
/anagrafiche/anag2.xml
2
/anagrafiche/anag4.xml
2
/schemi
1
/schemi/team.xsd
2
/squadre
1
Aggiornata 1 riga.
La prima versione modifica solo la riga che ha civico 133,
mentre la seconda effettua l’update di tutte le righe della
tabella, lasciando invariato il contenuto di quelle che hanno
il civico diverso da 133. Il risultato finale è identico, ma se
la tabella ha molte righe la seconda istruzione è sicuramente
da scartare. Per completare il discorso sulla modifica dei dati,
vediamo cosa accade se cerchiamo di porre a ‘S’ il flag pers_
fis_giu che, da schema, può valere solo ‘F’ o ‘G’:
update anagrafiche
set anagrafica = UPDATEXML(anagrafica, ‘/anagrafica/
@flag_fis_giu’,’S’)
where extractvalue(anagrafica,’/anagrafica/
denominazione/nome’)=’Paperone’;
update anagrafiche
*
ERRORE alla riga 1:
ORA-31038: Valore enumeration S non valido
CP 119
40
Ci è stato correttamente segnalato che il valore ‘S’ non è tra
quelli ammessi.
Concludiamo questo paragrafo con un esempio di lettura delle informazioni sulle risorse contenute nel Repository.
Dopo aver caricato i documenti XML nel Repository
mediante OEM (Figura 1), eseguiamo la query:
select path(0) percorso, depth(0) livello
from resource_view
where under_path(res,3,’/max’,0) = 1;
Per ogni risorsa (campo RES della vista RESOURCE_VIEW)
presente nel Repository tra i discendenti della cartella
‘max’, chiediamo il percorso ed il livello di profondità.
Le funzioni PATH e DEPTH danno risultati relativi alla cartella che si è indicata nella funzione UNDER_PATH.
Il livello ed il percorso vanno intesi a partire dalla cartella ‘max’, non sono valori assoluti nel Repository.
FIGURA 3 Registrazione di uno schema mediante Oracle
Enterprise Manager
ricerche effettuate mediante la funzione existsNode. La sintassi è analoga alla precedente con la differenza che indextype
deve valere ctxsys.ctxxpath invece di ctxsys.content.
Un indice “function-based” è legato all’utilizzo di una particolare funzione su un particolare frammento di documento
XML. Se, ad esempio, si intende velocizzare l’istruzione:
Select extractvalue(anagrafica,
‘/anagrafica/indirizzo/comune’)
From anagrafiche;
è possibile creare l’indice “function-based” che segue:
CREATE INDEX COMUNE_I
ON ANAGRAFICHE (extractvalue(anagrafica,
‘/anagrafica/indirizzo/comune’));
L’intero 0 è il legame tra la UNDER_PATH e le funzioni PATH e
DEPTH che ad essa fanno riferimento. Avremmo potuto utilizzare qualunque altro numero intero.
Il problema delle performance
In un database relazionale, in genere, la forma gerarchica
dei dati XML causa problemi molto seri alle prestazioni
delle query. Per limitare questi problemi, Oracle ha introdotto nuovi tipi di indici e migliorato quelli che già esistevano. In questo paragrafo faremo una panoramica sui tipi
di indice che velocizzano l’accesso ai dati XMLType ed al
Repository. Sulle colonne XMLType possono essere costruiti
quattro tipi di indice:
“B*Tree” e “bitmap” (che non sono stati modificati in
questa versione)
“Oracle Text” (il vecchio InterMedia, che è stato migliorato)
“function-based” (che è stato creato apposta per i dati
XMLType).
Analizziamo più in dettaglio gli ultimi due tipi. Gli indici di
tipo “Oracle Text” funzionano sulle colonne di tipo VARCHAR
e CLOB. In Oracle9i sono stati migliorati per gestire anche i
campi di tipo XMLType. Ad esempio, sulla tabella definita da:
CREATE TABLE documenti_xml (
Doc_id number(10),
Documento XMLType);
è possibile creare l’indice:
CREATE INDEX documenti_xml_i ON
documenti_xml (Documento) indextype is ctxsys.context;
Ovviamente il campo “Documento” ha un’archiviazione
di tipo CLOB: dunque ha senso utilizzare un indice di tipo
“Oracle text”. L’indice documenti_xml_i mette a disposizione
gli strumenti dei classici indici di tipo “Oracle Text”, in più le
nuove funzioni INPATH ed HASPATH sono state aggiunte proprio
per i campi XMLType. La funzione INPATH controlla se una
data parola appare nel documento XML ad un percorso specificato, la funzione HASPATH controlla se un dato percorso esiste
nel documento.
Tra gli indici di tipo “Oracle Text” è stata aggiunta una nuova
categoria, chiamata CTXXPATH, che ha lo scopo di migliorare le
che fa esplicito riferimento alla funzione da eseguire. In
sostanza la sintassi è quella solita, con la variante di indicare
la funzione al posto delle colonne da indicizzare. Con questi
indici possono essere velocizzate anche le funzioni extract()
ed existsNode().
Per quanto riguarda il Repository, non c’è bisogno di creare
esplicitamente indici per velocizzare la navigazione. Un indice
gerarchico del Repository, infatti, viene sempre aggiornato ed
utilizzato automaticamente. Quello che l’utente può fare è
ricostruire l’indice gerarchico mediante la funzione DBMS_XDB.
REBUILTHIERARCHICALINDEX.
Conclusioni
XML è uno standard che sta avendo grande successo e
diffusione. Il mercato dei database XML è ancora molto
aperto e quindi in continua evoluzione [3]. Fino alla prima
release di Oracle9i, Oracle era sensibilmente indietro rispetto
ai prodotti specializzati nella gestione di documenti XML, i
cosiddetti ‘database XML nativi’. Con XDB Oracle si propone
di ribaltare questa situazione ed assumere la leadership nel
settore. Si dice addirittura che XDB è, a tutti gli effetti, un
database XML nativo. Prima di dare giudizi definitivi bisogna
aspettare un po’ per vedere i risultati dei test significativi del
prodotto nonché le reazioni del mercato. Per ora ci limitiamo
a sottolineare i grandi passi avanti fatti con questa nuova
release. Il miglior pregio ed il peggior difetto: la completa
trasparenza, per lo sviluppatore, nella gestione dei diversi tipi
di archiviazione dei dati (CLOB o strutturato) e la carenza di
flessibilità in caso di modifiche degli schemi in corso d’opera.
Chiudo con un interrogativo: quanti dei vostri clienti sono
disposti a migrare ad Oracle 9.2 per utilizzare XDB?
BIBLIOGRAFIA
[1] Oracle - “Oracle 9.2 XML Database Developer’s Guide Oracle XML DB”, Oracle Corp., 2002
[2] Oracle - “Oracle XML DB Technical White Paper”, Oracle
Corp., 2002
[3] M. Ruocchio - “Archiviare dati XML nel Database”, Computer
Programming 109, 2002
[4] M. Ruocchio - “XML Schema ai mondiali di calcio”, Computer
Programming 109, 2002
RIFERIMENTI
[5] http://www.oracle.com
[6] http://technet.oracle.com
[7] http://www.oracle.com/forums/forum.jsp?id=1015144
41
CP 119