Język XML jest nowym standardem reprezentowania danych służącym do wymiany danych między aplikacjami w tym również między bazami danych. Szczególne znaczenie ma on dla wymiany danych w Internecie. W tym wykładzie zajmiemy się rozszerzeniami do przetwarzania XML, które dodano do obiektowo-relacyjnych baz danych. W dodatkowym wykładzie 16 zajmiemy się natomiast językami zapytań dla baz danych przechowujących wszystkie dane w postaci dokumentów XML.
Zaczniemy od przypomnienia podstawowych informacji o języku XML w tym o zapytaniach formułowanych w języku XPath.
W drugiej części wykładu przedstawiliśmy informacje na temat reprezentacji dokumentów XML w bazie danych oraz na temat wyszukiwania słów kluczowych w dokumentach tekstowych (niekoniecznie w dokumentach XML).
W trzeciej części opisaliśmy implementację XML w obiektowo-relacyjnej bazie danych (Oracle 9i) za pomocą typu obiektowego XMLType.
XML jest skrótem od eXtensible Markup Language. Ratifikowany przez World Wide Web Consortium (W3C), XML stał się standardem identyfikowania i opisywania danych (dokumentów) przekazywanych w sieci WWW. Podobnie jak HTML, XML jest podzbiorem obszerniejszego i mającego dłuższą historię języka SGML (ang. Structured Generalized Markup Language).
XML umożliwia opisywanie zarówno zawartości jak i struktury dokumentu niezależnie od sposobu jego prezentacji na ekranie użytkownika. Zastosowania dokumentów XML są trzech rodzajów.
W dokumentach HTML oprócz zawartości tekstowej występują specjalne metaelementy, zwane znacznikami. Znaczniki zwykle tworzą parę: znacznik otwierający i znacznik zamykający. Między znacznikami umieszcza się tekst bądź inne znaczniki.
Przykłady:
<B>Nie zapomnij!</B>
Tekst „Nie zapomnij!” ma być wypisany pogrubioną czcionką. Zatem znaczniki <B>
i </B>
mają charakter
prezentacyjny.
<A Href="http://www.pjwstk.edu.pl/">Odwiedź naszą witrynę.</A>
Znaczniki <A>
i </A>
definiują odsyłacz (odwołanie) do innego dokumentu internetowego. Mają więc charakter metadanych.
Przykład HTML: Lista publikacji
<HTML>
<BODY>
Fikcja:
<UL>
<LI>Autor: Lech Banachowski</LI>
<LI>Tytuł: Bazy danych</LI>
<LI>Rok: 1998</LI>
</UL>
Nauka:
<UL>
<LI>Autor: Michał Lentner</LI>
<LI>Tytuł: Oracle9i</LI>
<LI>Twarda okładka</LI>
</UL>
</BODY>
</HTML>
HTML jest odpowiedni jeśli chodzi o reprezentowanie struktury dokumentu w celu uwzględnienia jej przy wyświetlaniu dokumentu w przeglądarce internetowej. Jest natomiast niewystarczający do reprezentowania struktury danych w dokumencie w innych celach niż jego wyświetlenie w przeglądarce. Na przykład, moglibyśmy chcieć wysłać powyższy dokument HTML do innej aplikacji, a ta aplikacja powinna wyświetlić informację o naszych książkach. Za pomocą znaczników HTML nie jesteśmy jednak w stanie odróżnić np. imion autorów od ich nazwisk.
Zaprezentujemy teraz elementy składowe dokumentów XML. Czytelnik zaznajomiony z budową dokumentów XML może ten fragment pominąć.
Dokumenty XML są dokumentami mającymi zagnieżdżoną strukturę. Składają się ze znaczników i zawartości. Jest sześć rodzajów znaczników:
elementy (ang. elements),
instrukcje przetwarzania (ang. processing instructions),
komentarze (ang. comments),
sekcje CDATA (ang. CDATA sections),
referencje do encji (ang. entity references),
definicje typów dokumentów DTD (ang. document type definitions).
Program odczytujący i przetwarzający dokument XML nazywa się procesorem (lub parserem) XML.
Podstawową konstrukcją w dokumencie XML jest element. Element składa się ze znacznika otwierającego, zawartości i znacznika zamykającego np.
<OSOBA>Jan Kowalski</OSOBA>
Znacznik <OSOBA>
pełni tutaj rolę
metadanych podając interpretację zawartości elementu w dokumencie XML.
Zawartość elementu może być pusta. Wtedy piszemy:
<SEPARATOR/>
Elementy mogą być zagnieżdżone np.
Element może mieć atrybuty, które dostarczają dodatkowych informacji o elemencie np. status studenta:<OSOBA>
<IMIE>Jan</IMIE>
<NAZWISKO>Kowalski</NAZWISKO>
</OSOBA
>
<OSOBA Status="student">
<IMIE>Jan</IMIE>
<NAZWISKO>Kowalski</NAZWISKO>
</OSOBA
>
W przeciwieństwie do elementów atrybuty nie mogą być zagnieżdżone, ale za to mogą, jak zobaczymy wkrótce, być wskaźnikami.
W XML wszystkie wartości atrybutów muszą być ujęte w cudzysłowy lub apostrofy.
<DIV Class="preface">
<BOOK ISBN='9876-3456-65-2X'>
Jak widać, informacje o elemencie można podawać w postaci jego atrybutu bądź zamieszczać w jego zawartości. Informacja w atrybucie ma postać danej prostego typu danych.
W języku XML istotne jest odróżnienie liter dużych od małych:
<ach>, <ACH>
oraz <Ach>
są to trzy różne znaczniki.
Instrukcje przetwarzania (PI) dostarczają specjalnych instrukcji dla aplikacji. Nie są one częścią danych znakowych dokumentu i są bez ich przetwarzania przekazywane do aplikacji. Instrukcje przetwarzania mają postać:
<?name pidata?>
Nazwa name identyfikuje instrukcję. Konkretna aplikacja reaguje tylko
na pewne instrukcje przetwarzania, a pozostałe pomija. Dane pidata
występujące po nazwie instrukcji przetwarzania są opcjonalne i mają znaczenie
tylko dla aplikacji, które je rozpoznają. Nazwy zaczynające się
słowem 'xml' są zarezerwowane dla standardu XML.
Np.
<?xml version="1.0"?>
Komentarze zaczynają się od <!--
a kończą
się -->
. Komentarze mogą zawierać dowolne napisy z wyjątkiem dwóch
myślników --
. Komentarze mogą się znajdować w dowolnym miejscu dokumentu.
Komentarze nie są częścią tekstowej zawartości dokumentu XML. Procesor XML nie
musi przekazywać ich do aplikacji.
W
dokumencie XML sekcja CDATA instruuje procesor aby nie dokonywał analizy składniowej
znaków zawartych w sekcji traktując je jako dane napisowe. W ten sposób znaki
takie jak <
, >
czy &
mogą być częścią napisu np.
<![CDATA[ *p = &q; b = (i <= 3);
]]>
Między początkiem sekcji <![CDATA[
a końcem sekcji ]]>
, wszystkie dane znakowe zostają przekazane bez
interpretacji bezpośrednio do aplikacji. Jedynym napisem, jaki nie może wystąpić
w sekcji CDATA, to ]]>
Pewne znaki zarezerwowano do tworzenia znaczników i
do innych specjalnych celów, np. znak <
identyfikuje początek znacznika. Aby
móc je używać w charakterze zawartości, zdefiniowano alternatywnš postać reprezentowania
ich. Do reprezentowania tych specjalnych znaków używa się tzw. encji.
Są one również używane przy odwołaniach do często
występujących napisów jak i do zawartości zewnętrznych plików.
Każda encja
musi mieć jednoznaczną nazwę. Użycie encji polega na odwołaniu się do jej nazwy.
Referencje do encji zaczynają się znakiem &
, a kończą się średnikiem. Na
przykład, encja lt
reprezentuje znak <
, gt
znak >
,
amp
znak &, apos
apostrof, a
quot
cudzysłów. Zatem napis
<element>
zapisujemy jako
<element>
Przedstawione encje to tzw. encje wewnętrzne, reprezentujące stałe tekstowe (napisy). Oprócz nich mamy do czynienia z tzw. encjami zewnętrznymi reprezentującymi zawartości plików. W przypadku plików tekstowych ich zawartość jest wstawiana w dokument XML. W przypadku plików binarnych są one przekazywane do aplikacji bez dokonywania żadnych zmian. Mogą wystąpić tylko jako wartość atrybutu specjalnego typu ENTITY np. atrybut Zdjęcie jest typu ENTITY. Encje zewnętrzne janek oraz dane_janka reprezentują odpowiednio zawartości pliku binarnego i tekstowego:
<OSOBA Zdjęcie="janek”>&dane_janka;</
OSOBA
>
W tym sensie w skład dokumentu XML mogą wchodzić dowolne dane multimedialne.
Przykład
Poniżej znajduje się kod HTML oraz odpowiadający mu kod XML dla danych
o pracownikach (z tabeli Emp): numer pracownika, nazwisko, stanowisko i zarobki.
Najpierw przedstawimy HTML.
<TABLE> <TR> <TD>EMPNO</TD> <TD>ENAME</TD> <TD>JOB</TD> <TD>SAL</TD> </TR> <TR> <TD>7654</TD> <TD>MARTIN</TD> <TD>SALESMAN</TD> <TD>1250</TD></TR> <TR> <TD>7788</TD> <TD>SCOTT</TD> <TD>ANALYST</TD> <TD>3000</TD></TR> </TABLE> |
W kodzie XML występują znaczniki określające dane. Struktura elementów w XML jest
zagnieżdżona. Oto odpowiedni dokument XML:
<?xml version="1.0"?> <EMPLIST> <EMP> <EMPNO>7654</EMPNO> <ENAME>MARTIN</ENAME> <JOB>SALESMAN</JOB> <SAL>1250</SAL> </EMP> <EMP> <EMPNO>7788</EMPNO> <ENAME>SCOTT</ENAME> <JOB>ANALYST</JOB> <SAL>3000</SAL> </EMP> </EMPLIST> |
Przykład XML
Rozważymy jeszcze listę publikacji jako kolejny przykładowy dokument XML.
<LISTA>
|
Wygodnie jest patrzeć na dokument XML jak na strukturę hierarchiczną, drzewiastą. Jest to postać, często używana do reprezentowania dokumentu XML w pamięci wewnętrznej przez procesor dokumentów XML.
Elementy i ich tekstowe zawartości są reprezentowane przez węzły drzewa.
Rys. 15.1 Reprezentacja drzewowa dokumentu XML
Model danych XML umożliwia powiązania między obiektami opisywanymi w dokumencie XML. Na przykład: jedna publikacja może mieć wielu autorów; jeden autor może być autorem wielu publikacji. Ta cecha pozwala definiować semistrukturalne dane w postaci dowolnego grafu nie tylko drzewa. Powiązania między obiektami są realizowane poprzez wartości atrybutów.
Typ ID dostarcza jednoznacznych identyfikatorów dla elementów.
Typy danych IDREF i IDREFS pozwalają korzystać ze wskaźników do elementów wyróżnionych w danym dokumencie. IDREF oznacza pojedynczy wskaźnik; IDREFS oznacza listę wskaźników.
Wartością atrybutu IDREF musi być nazwa występująca jako wartość atrybutu typu ID.
Wartością atrybutu IDREFS musi być lista nazw występujących jako wartości atrybutów typu ID.
Przykład
Przedstawimy dokument XML z atrybutami typów
ID i IDREFS umożliwiającymi powiązanie publikacji z autorami.
<LISTA>
<AUTOR Id_autora="LB" Lista_pub="BD1,BD2,BD3">
<IMIĘ>Lech</IMIĘ>
<NAZWISKO>Banachowski</NAZWISKO>
</AUTOR>
<AUTOR Id_autora="KS" Lista_pub="BD1,BD2,SO">
<IMIĘ>Krzysztof</IMIĘ>
<NAZWISKO>Stencel</NAZWISKO>
</AUTOR>
<PUBLIKACJA Id_publikacji="BD1" Lista_autor="LB,KS">
<TYTUŁ>Bazy danych. Projektowanie aplikacji na
serwerze</TYTUŁ>
<ROK>2001</ROK>
</PUBLIKACJA>
<PUBLIKACJA Id_publikacji="BD2" Lista_autor="LB,KS,AC,EM,KM">
<TYTUŁ>Bazy danych. Wykłady i ćwiczenia</TYTUŁ>
<FORMAT>Twardy</FORMAT>
</PUBLIKACJA>
........
</LISTA>
Przestrzeń nazw wprowadzamy do dokumentu XML poprzez określenie specjalnego prefiksu przestrzeni nazw. Potem dodajemy ten prefiks z dwukropkiem do nazw elementów i atrybutów. Przestrzenie nazw są atrybutami definiowanymi za pomocą specjalnego prefiksu o nazwie "xmlns". Oto przykład:
<doc xmlns:document="http://www.osborne.com/document"
xmlns:books="http://www.osborne.com/book">
<document:title>List of books on XML</document:title>
<books:booklist>
<books:book>
<books:title>XML Handbook</books:title>
....
</books:book>
...
</books:booklist>
</doc>
W przykładzie występują dwie przestrzenie nazw o prefiksach odpowiednio document i books. Przestrzenie nazw rozróżniają między znacznikami pochodzącymi z dwóch różnych definicji umożliwiając użycie tej samej nazwy title dla dwóch różnych elementów. W ten sposób możliwe jest odróżnienie znaczników pochodzących z różnych źródeł i zastosowanie do nich odmiennych reguł przetwarzania.
Zazwyczaj potrzebne jest wydzielenie klasy poprawnych dokumentów XML, które są zrozumiałe dla danej aplikacji. Realizuje się to przez podanie definicji poprawnego dokumentu XML czyli zbioru reguł definiujących elementy, atrybuty i encje w dokumencie XML.
Dwa najbardziej znane formalizmy definiowania poprawnych dokumentów XML to DTD (prostszy) i XML Schema (silniejszy).
Oto przykładowa definicja DTD - określająca dokument XML o korzeniu LISTA i węzłach wewnętrznych (elementach) PUBLIKACJA, AUTOR, TYTUŁ, ROK, FORMAT, IMIĘ, NAZWISKO. W przypadku elementu PUBLIKACJA jest wymagany atrybut rodzaj przyjmujący dwie wartości: Nauka i Fikcja.
<!DOCTYPE LISTA [
<!ELEMENT LISTA (PUBLIKACJA)*>
<!ELEMENT PUBLIKACJA (AUTOR, TYTUŁ, ROK?, FORMAT?)>
<!ELEMENT AUTOR (IMIĘ, NAZWISKO)>
<!ELEMENT IMIĘ (#PCDATA)>
<!ELEMENT NAZWISKO (#PCDATA)>
<!ELEMENT TYTUŁ (#PCDATA)>
<!ELEMENT ROK (#PCDATA)>
<!ELEMENT FORMAT(#PCDATA)>
<!ATTLIST PUBLIKACJA Rodzaj (Nauka|Fikcja) #REQUIRED>
]>
gdzie:
<!DOCTYPE
definiuje element będący korzeniem
dokumentu,
<!ELEMENT
definiuje strukturę elementu,
<!ATTLIST
definiuje listę
atrybutów danego elementu,
#PCDATA
oznacza typ danych napisów znakowych (ang.
Parseable Character Data),
#REQUIRED
oznacza atrybut wymagany.
Tworzenie ustandaryzowanych definicji DTD lub XML Schema dla konkretnych dziedzin dokumentów umożliwia wymianę danych między heterogenicznymi źródłami danych.
Przykład
Mathematical Markup Language (MathML) jest specjalistycznym językiem umożliwiającym tekstowe definiowanie wzorów matematycznych.
W HTML napisalibyśmy: <IMG SRC="xysq.gif" ALT="(x+y)^2">
gdzie w pliku xysq.gif
umieścilibyśmy obrazek naszego wyrażenia
matematycznego "x plus y
do kwadratu".
To samo w MathML wyglądałoby:
<apply>
<power/>
<apply> <plus/> <ci>x</ci> <ci>y</ci> </apply>
<cn>2</cn>
</apply>
XQuery jest to deklaratywny język zapytań dla dokumentów XML będący standardem przygotowywanym przez organizację W3C. Tym językiem zajmiemy się bardziej szczegółowo w dodatkowym wykładzie 16.
Niezależnie opracowano wersję języka SQL obejmującą dokumenty XML o nazwie SQL/XML. Wersja ta ma być zawarta w nowym Standardzie SQL:2000n.
Język XQuery obejmuje zapytania dotyczące danych w dokumentach XML; przy integracji danych pochodzących z różnych źródeł umożliwia transformacje danych XML. Obejmuje wyrażenia XPath wyznaczające elementy i wartości w dokumencie XML. W tym wykładzie ograniczymy się do zaprezentowania i użycia wyrażeń XPath. Bardziej formalny opis XPath znajduje się w wykładzie 16.
XPath jest standardem W3C służącym do lokalizacji specyficznych elementów w dokumentach XML. Wynikiem zastosowania wyrażenia XPath do dokumentu XML jest zbiór elementów (węzłów) - w szczególności zbiór pusty lub jednoelementowy ale także może to być wartość typu boolean, number lub string.
XPath używa modelu drzewa dla dokumentu XML.
Struktura drzewa jest uporządkowana: z góry w dół i od lewej
strony do prawej. Na przykład, można mówić o drugim następniku PUBLIKACJA
elementu LISTA
.
Przykłady wyrażeń XPath
Zasadniczo składnia XPath jest podobna do adresowania plików w
systemie plików. Jeśli ścieżka zaczyna się od ukośnika /
, to reprezentuje bezwzględną
(tj. zaczynającą się w korzeniu dokumentu)
ścieżkę do wymaganego elementu. Na przykład,
/LISTA/PUBLIKACJA
wyznacza wszystkie elementy PUBLIKACJA
, które są następnikami głównego elementu
LISTA
. Jeśli ścieżka zaczyna się od //
wówczas wszystkie elementy
w drzewie spełniające dalsze warunki są wyznaczane np.
//AUTOR/NAZWISKO
wyznacza wszystkie elementy NAZWISKO
, które są następnikami dowolnego elementu
AUTOR
osiągalnego z głównego elementu. Z kolei
//AUTOR/NAZWISKO[1]
wyznacza pierwszy element w zbiorze wyników a
//AUTOR/NAZWISKO[last()]
ostatni element w zbiorze wyników. Natomiast
//AUTOR/NAZWISKO/text()
wyznacza wszystkie nazwiska (w
postaci tekstowej jako napisy) elementów NAZWISKO
, które są następnikami dowolnego elementu
AUTOR
osiągalnego z głównego elementu.
//AUTOR/*
wybiera wszystkie elementy zlokalizowane przez poprzedzającą ścieżkę. Atrybuty są specyfikowane za pomocą prefiksu @ np.
//@
Rodzaj
wyznacza wszystkie elementy z atrybutem Rodzaj
. W nawiasach [ ] są formułowane predykaty.
Można używać wartości atrybutów jako kryterium wyboru
elementu. Np.
//PUBLIKACJA[@Rodzaj='fikcja']
wyznacza wszystkie elementy PUBLIKACJA
, które mają atrybut Rodzaj
równy
'fikcja'
. W
predykatach można używać spójników logicznych jak OR, AND i NOT np.
/LISTA/PUBLIKACJA[ROK=2001 OR ROK=2002]/AUTOR/NAZWISKO
wyznacza wszystkie elementy
NAZWISKO
autorów książek opublikowanych albo w roku 2001 albo w roku 2002.
Dokumenty tekstowe (w tym XML) magą być reprezentowane w obiektowo-relacyjnej bazie danych na dwa sposoby:
1. zwykle jako duże obiekty CLOB - ewentualnie, z dodanym indeksowaniem ich zawartości. Aby dokonać przetworzenia dokumentu sprowadza się go do pamięci wewnętrznej i stosuje się odpowiednie metody jak na przykład przetwarzanie za pomocą drzewa. Istniejące indeksy pozwalają ograniczyć zbiór sprowadzanych do pamięci dokumentów.
2. dokumenty XML o ustalonym schemacie poprzez zbiór tabel relacyjnych lub obiektowo-relacyjnych. Operacje przetwarzania zbioru dokumentów łumaczy się na operacje na tabelach bazy danych.
Listy książek zapisywane w przykładzie powyżej jako dokumenty XML można reprezentować w bazie danych w płaskich tabelach relacyjnych (według zasady, że elementy przechodzą na tabele):
LISTA(Listid:Integer)
PUBLIKACJA(Pubid:Integer, Listid:Integer, Tytuł:String, Rok:String,
Rodzaj:String, Format:String)
AUTOR(Autorid:Integer, Pubid:Integer, Imię:string, Nazwisko:string)
I na odwrót, zawartość zwykłej tabeli relacyjnej może być w naturalny sposób reprezentowana jako dokument XML np. przykładowa tabela Emp:
<ROWSET Table="Emp">
<ROW>
<EMPNO>2345</EMPNO>
<ENAME>SCOTT</ENAME>
...
</ROW>
<ROW> ....
</ROW>
....
</ROWSET>
Dla ułatwienia w Oracle wprowadzono nowy, specjalny obiektowy typ danych XMLType,
którego wartości reprezentują dokumenty XML. XMLType osłania programistę
bazy danych przed szczegółami implementacyjnymi. Programista nie musi zajmować się tym,
czy dokument XML jest
zapisany jako obiekt CLOB czy jako zbiór powiązanych wierszy w tabelach
obiektowo-relacyjnych. O XMLType pomówimy za chwilę po zaznajomieniu się najpierw z tematem
przechowywania dowolnych dokumentów tekstowych (niekoniecznie XML).Tekstowa baza danych jest to zbiór dokumentów tekstowych. W bazie danych dokumenty tekstowe są zwykle zapisywane jako obiekty LOB (np. CLOB lub BFILE) ewentualnie jako adresy stron internetowych (gdy dokument ma postać strony WWW). Dodatkowo dobudowuje się struktury indeksowe wspomagające wyszukiwanie dokumentów.
Ważną klasę zapytań w tekstowej bazie danych stanowią wyszukiwania po słowach kluczowych.
Zapytania boolowskie: Składniki zapytania są powiązane spójnikami AND, OR i NOT. Wynikiem zapytania jest lista dokumentów, które spełniają wyrażenie boolowskie, np.
Database AND (Microsoft OR Oracle)
Zapytania rankingowe: Wynikiem zapytania jest lista dokumentów, które spełniają wyrażenie boolowskie, uporządkowane według stopnia istotności danego dokumentu dla zapytania.Zawiera informacje: termin j występuje k razy w dokumencie i.
Id | Database | Oracle | Microsoft | SQL | Table | Query |
1 | 2 | 2 | 0 | 1 | 5 | 8 |
2 | 1 | 0 | 1 | 1 | 4 | 9 |
3 | 0 | 0 | 0 | 23 | 56 | 67 |
4 | 1 | 1 | 1 | 0 | 0 | 0 |
5 | 0 | 1 | 1 | 1 | 0 | 0 |
Zapytanie o dokumenty zawierające podane słowo kluczowe np. Database zwraca dokumenty uporządkowane według liczby wystąpień danego słowa kluczowego (najprostsza miara istotności). Wyliczenie wyniku zapytania boolowskiego np. Database AND Oracle AND Microsoft sprowadza się do zastosowania operatora koniunkcji na trzech wektorach - w wyniku otrzymujemy dokument 4 z wagą 1.
Dla każdego terminu zapisujemy listę odwróconą identyfikatorów dokumentów, w których występuje dany termin. Na przykład dla dwóch dokumentów:
Id_dok | Dokument |
1 | Oracle Database |
2 | Microsoft Database |
struktura danych list odwróconych wygląda następująco:
Słowo | Lista odwrócona |
Oracle | 1 |
Database | 1, 2 |
Microsoft | 2 |
Wyznaczenie wyniku zapytania boolowskiego sprowadza się do operacji przecięcia i sumy list odwróconych.
Przykład: Database AND
Oracle
to przecięcie dwóch list odwróconych,
Database
OR Oracle
to
suma dwóch list odwróconych.
W praktyce listy odwrócone (np. w wyszukiwarkach internetowych) są bardzo długie. Słowa kluczowe są zwykle zorganizowane w strukturę danych nazywaną leksykonem (np. w postaci drzewa) przechowywaną w pamięci wewnętrznej.
W Oracle dokument XML może być reprezentowany jako obiekt wbudowanego typu obiektowego XMLType. Za pomocą metod typu XMLType można tworzyć, wydobywać i indeksować dane XML przechowywane w bazie danych. Typ XMLType tak jak każdy typ obiektowy może być używany jako typ danych kolumn lub jako typ tabeli obiektowej.
Załóżmy,
że chcielibyśmy przechowywać w bazie danych książkę adresową z umożliwieniem
zapisu obok danych typowych również nietypowych danych kontaktowych. Dodatkowo,
chcielibyśmy móc łatwo przekazywać dane kontaktowe w postaci tekstowej przez
Internet. Oto nasze rozwiązanie korzystające z kolumny typu XMLType.
CREATE TABLE Kontakty(
Nazwisko
VARCHAR2(50),
Karta XMLTYPE
,
Data_utworzenia DATE);
Dla pełności obrazu zauważmy, że alternatywnie można wszystkie dane
umieścić wewnątrz dokumentu XML i zamiast z tabeli relacyjnej
Kontakty korzystać z tabeli obiektowej typu XMLType.
CREATE TABLE Obj_Kontakty OF XMLType;
Egzemplarz typu XMLType tworzy się z wartości VARCHAR2 lub CLOB przy użyciu konstruktora
XMLType
:
INSERT INTO Kontakty VALUES ('KOWALSKI',
XMLType('<KARTA>
<EMAIL>Jan.Kowalski@praca.pl</EMAIL>
<TEL_PRACA>33-456</TEL_PRACA>
<TEL_DOM>28-991</TEL_DOM>
<TEL_KOM>600-345</TEL_KOM>
<ADRES>
<ULICA>Wygodna 9m1</ULICA>
<MIASTO>Warszawa</MIASTO>
<KOD>02-782</KOD>
</ADRES>
</KARTA>'),
Sysdate);
INSERT INTO Kontakty VALUES ('NOWAK',
XMLType('<KARTA>
<EMAIL>Anna.Nowak@praca.pl</EMAIL>
<WWW>http://www.praca.pl/prac/annaw.html</WWW>
<TEL_PRACA>33-456</TEL_PRACA>
<TEL_DOM>65-998</TEL_DOM>
<ADRES>
<HOTEL>Moniuszko</HOTEL>
<ULICA>Moniuszki 19 pok.205</ULICA>
<MIASTO>Warszawa</MIASTO>
<KOD>00-782</KOD>
</ADRES>
</KARTA>'),
Sysdate);
Przy wydobywaniu danych z obiektu typu XMLType korzystamy z
metod konwersji (obowiązuje zasada, że część obiektu XMLType jest też obiektem
XMLType):
|
Załóżmy, że interesują nas wszystkie adresy elektroniczne z tabeli Kontakty. Użyjemy metody Extract oraz jej argumentu będącego wyrażeniem XPath. Metoda ta wyznacza wszystkie elementy dokumentu XML opisane przez podaną ścieżkę.
SELECT w.Karta.Extract('/KARTA/EMAIL/text()').GetStringVal()
"EMail"
FROM Kontakty w;
W wyniku otrzymujemy kolumnę wartości typu VARCHAR2:
EMail
---------------------
Jan.Kowalski@praca.pl
Anna.Nowak@praca.pl
Gdybyśmy nie zastosowali funkcji text()
na końcu wyrażenia ścieżkowego,
tzn. gdybyśmy napisali:
SELECT w.Karta.Extract('/KARTA/EMAIL').GetStringVal()
"EMail"
FROM Kontakty w;
otrzymalibyśmy następującą kolumnę wartości typu VARCHAR2:
EMail
------------------------------------
<EMAIL>Jan.Kowalski@praca.pl</EMAIL>
<EMAIL>Anna.Nowak@praca.pl</EMAIL>
W szczególności
SELECT w.Nazwisko, w.Karta.Extract('/KARTA').GetStringval() AS "KARTA"
FROM Kontakty w;
wypisuje pełne teksty dokumentów XML traktując je jako wartości VARCHAR2,
podobnie jak:
SELECT w.Nazwisko, w.Karta.GetStringval() AS "KARTA"
FROM Kontakty w;
Gdy chcemy wziąć cały dokument XML i przesłać go jako dokument tekstowy, piszemy:
SELECT w.Karta.GetClobval() as KartaKow
FROM Kontakty w
WHERE w.Nazwisko = 'KOWALSKI';
Aby sprawdzić czy w dokumencie XML występuje element <WWW>
stosujemy metodę ExistsNode:
SELECT w.Nazwisko, w.Karta.ExistsNode('/KARTA/WWW') "Ma
stronę WWW"
FROM Kontakty w
WHERE w.Karta IS NOT NULL;
Wynik:
NAZWISKO Ma stronę WWW ----------- --------------- KOWALSKI 0 NOWAK 1
Zauważmy, że gdybyśmy opuścili warunek w.Karta IS NOT NULL
, w wyniku znalazłyby się
nazwiska wszystkich osób. Dla tych, które nie mają przyporządkowanej
karty, otrzymalibyśmy NULL w kolumnie Karta, co sygnalizowałoby niemożliwość
zastosowania metody ExistsNode do nieokreślonego obiektu (NULL).
Gdy chcemy wziąć adresy osób, których adres elektroniczny to
"Jan.Kowalski@praca.pl"
napiszemy:
SELECT w.Nazwisko, w.Karta.Extract('/KARTA/ADRES').GetStringval()
AS "Adres"
FROM Kontakty w
WHERE w.Karta.ExistsNode('/KARTA[EMAIL="Jan.Kowalski@praca.pl"]') = 1;
Następujące zapytanie jest podobne, ale nie liczy dokładnie tego samego co poprzednio. Dlaczego?
SELECT w.Nazwisko, w.Karta.Extract('/KARTA[EMAIL="Jan.Kowalski@praca.pl"]/ADRES').GetStringval()
AS "Adres"
FROM Kontakty w;
Jedna metoda polega na zastąpieniu jednego dokumentu innym:
UPDATE Kontakty w
SET w.Karta =
XMLType('<KARTA>
<EMAIL>Jan.Kowalski@praca.pl</EMAIL>
<EMAIL>JanKow@wp.pl</EMAIL>
<TEL_PRACA>33-456</TEL_PRACA>
<TEL_DOM>28-991</TEL_DOM>
<TEL_KOM>600-345</TEL_KOM>
<ADRES>
<ULICA>Wygodna 9m1</ULICA>
<MIASTO>Warszawa</MIASTO>
<KOD>02-782</KOD>
</ADRES>
</KARTA>')
WHERE w.Nazwisko='KOWALSKI';
Druga metoda polega na zastosowaniu funkcji UpdateXML
albo w odniesieniu do stałej wartości:
UPDATE Kontakty w
SET w.Karta = UpdateXML(w.Karta,
'/KARTA[EMAIL="Jan.Kowalski@praca.pl"]/TEL_DOM/text()',
'9999-10')
WHERE w.Nazwisko='KOWALSKI';
albo w odniesieniu do całego elementu:
UPDATE Kontakty w
SET w.Karta = UpdateXML(w.Karta,'/KARTA[EMAIL="Jan.Kowalski@praca.pl"]/ADRES',
XMLType('<ADRES>
<ULICA>Aksamitna 90m10</ULICA>
<MIASTO>Warszawa</MIASTO>
<KOD>12-782</KOD>
</ADRES>'))
WHERE w.Nazwisko='KOWALSKI';
W szczególności można tą metodą usuwać fragmenty dokumentów
XML. Na przykład przy zmianie polityki biznesowej firmy klient nie
musi podawać numeru swojego dowodu osobistego.
W naszym przykładzie:
UPDATE Kontakty w
SET w.Karta = UpdateXML(w.Karta,'/KARTA[EMAIL="Jan.Kowalski@praca.pl"]/ADRES/KOD',
NULL)
WHERE w.Nazwisko='KOWALSKI';
usunie kod z adresu Kowalskiego a dokładniej zastąpi element KOD przez
pusty element <KOD/>. Aby usunąć cały dokument piszemy:
UPDATE Kontakty w
SET w.Karta = NULL
WHERE w.Nazwisko='KOWALSKI';
Aby usunąć wszystkie wiersze, w których Karta nie zawiera elementu ADRES, piszemy:
DELETE FROM Kontakty w
WHERE
w.Karta.ExistsNode('/KARTA/ADRES') = 0;
W celu przyśpieszenia wykonywania zapytania
SELECT * FROM Kontakty w WHERE
w.Karta.Extract('/KARTA/ADRES/MIASTO/text()').GetStringVal()= 'Warszawa';
indeksuje się zawartości elementu MIASTO w dokumentach XML kolumny Karta
CREATE INDEX Miasto_index ON Kontakty w
(w.Karta.Extract('/KARTA/ADRES/MIASTO/text()').GetStringVal());
Zapytanie SQL użyje tego indeksu funkcyjnego, zamiast czytać dokumenty XML wiersz po wierszu i obliczać wartości wyrażeń
XPath.Ponadto w Oracle są dostępne konstrukcje, których nie omawiamy na wykładzie:
Więcej informacji można znaleźć w dokumentacji Oracle w szczególności w: Oracle9i XML API Reference - XDK and Oracle XML DB.
W czasie tego wykładu przedstawiono problematykę związana z językiem XML ze szczególnym uwzględnieniem rozszerzeń obiektowo-relacyjnych baz danych o udogodnienia do przetwarzania dokumentów XML.
Przedstawiono dwie podstawowe metody przechowywania dokumentów XML w obiektowo-relacyjnej bazie danych:
Pokazano proste konstrukcje serwera bazy danych Oracle wspomagające definiowanie, przechowywanie i przetwarzanie dokumentów XML.
Z jednej strony dokumenty XML można reprezentować w relacyjnej i w obiektowo-relacyjnej bazie danych, ale również na odwrót dane relacyjne i obiektowo-relacyjne dają się w sposób naturalny reprezentować jako dane XML. Zachodzi więc pytanie. Skoro do komunikacji używamy danych w postaci XML to może, zamiast za każdym razem dokonywać konwersji, po prostu korzystać wyłącznie z baz danych XML, które są ogólniejsze niż bazy relacyjne i obiektowo-relacyjne?
XML - język dokumentów oparty na znacznikach, którego celem jest ułatwienie komunikacji i przekazywania danych w sieci między aplikacjami, bazami danych i ludźmi.
poprawnie zbudowany dokument XML - dokument XML, którego elementy są poprawnie zagnieżdżone.poprawny dokument XML - poprawnie zbudowany dokument XML, który ma definicję typu (np. DTD lub XML Schema) oraz jest zbudowany zgodnie z regułami tej definicji.
procesor XML - moduł oprogramowania używany przez aplikacje w celu odczytania dokumentu XML oraz przetwarzania jego zawartości i struktury.
DTD - język oparty na XML służący do definiowania składni poprawnych dokumentów XML.
XML Schema - język oparty na XML służący do definiowania składni poprawnych dokumentów XML.
XPath - język wyrażeń scieżkowych umożliwiający wydobywanie z dokumentu XML jego części.
XSL - język arkuszy stylów umożliwiający przekształcanie dokumentu XML na przykład w dokument HTML.
XMLType - typ obiektowy umożliwiający reprezentowanie, przechowywanie i przekształcanie dokumentów XML w obiektowo-relacyjnej bazie danych Oracle osłaniający programistę bazy danych przed szczegółami implementacyjnymi.
1. Wykonaj przykłady z wykładu dotyczące XMLType.
2. Utwórz bazę danych przyjmowania zamówień (Klienci, Faktury, Pozycje, Towary). Może to być baza relacyjna albo obiektowo-relacyjna. Napisz aplikację przyjmowania zamówień i wystawiania faktur, za pomocą XML.
Klient składa zamówienie (na jeden towar) przysyłając dokument XML:
Aplikacja ma sprawdzić zamówienie, zapisać w bazie danych i wysłać fakturę w postaci dokumentu XML:
<Zamawiam>
<Klient>
<Imie>Jan</Imie>
<Nazwisko>Kowalski</Nazwisko>
<Adres>Cicha 5m1, 08099 Warszawa</Adres>
</Klient>
<Pozycja>
<Towar>Cukier</Towar>
<Ilość>4</Ilość>
<Miara>kg</Miara>
</Pozycja>
</Zamawiam>
<Faktura>
<Klient>
<Imie>Jan</Imie>
<Nazwisko>Kowalski</Nazwisko>
<Adres>Cicha 5m1, 08099 Warszawa</Adres>
</Klient>
<Zakup>
<Towar>Cukier</Towar>
<Ilość>4</Ilość>
<Miara>kg</Miara>
<Cena_jedn>2</Cena_jedn>
<Cena>8</Cena>
</Zakup>
</Faktura>
3. Zaproponuj sposób zapisywania zamówień jako dokumentów XML w kolumnie tabeli Klienci.