Język XML jest 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. Podstawową jednostką organizacji danych staje się dokument. Dokumentem w szczególnym przypadku może być zawartość strony WWW. W tym wykładzie zajmiemy się rozszerzeniami do przetwarzania dokumentów XML, które dodano do obiektowo-relacyjnych baz danych.
W pierwszej części wykładu przedstawimy 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 drugiej części opiszemy implementację XML w obiektowo-relacyjnej bazie danych Oracle 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.
Przykład XML
Rozważymy listę publikacji jako 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. 6.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>
Dokumenty tekstowe (w tym XML) mogą 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 obiektowych. Operacje przetwarzania zbioru dokumentów tł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(Autorstwoid: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 posługiwania się dokumentami XML 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).Dla pełności obrazu reprezentacji dokumentów XML w bazie danych wspomnijmy jeszcze o przechowywaniu w bazie danych tylko samego adresu URL strony WWW zawierającej dokument.
Tekstowa baza danych jest to zbiór dokumentów tekstowych. W bazie danych dokumenty tekstowe są zwykle zapisywane jako:
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 (kolumnach) - 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: Wyznaczenie wyniku zapytania Database AND
Oracle
sprowadza się do przecięcia dwóch list odwróconych.
Wyznaczenie wyniku zapytania
Database
OR Oracle
sprowadza się do
sumy 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.
Zastosowanie funkcji haszującej
Niech wartością funkcji haszującej h(k) dla słowa kluczowego k będzie wektor bitowy. Niech dokument D zawiera słowa kluczowe k1,…,kn. Sygnaturą dokumentu H(D) nazywamy wartość h(k1) OR … OR h(kn). Jeśli zapytanie Z dotyczy koniunkcji słów kluczowych z1,…, zi liczymy sygnaturę zapytania: H(Z)=h(z1) OR … OR h(zi).
Wyszukiwanie przeprowadzamy najpierw na sygnaturach. Mianowicie, szukamy wszystkich dokumentów D takich, że H(Z) AND H(D) = H(Z) (czyli H(D) zawiera H(Z)) (ograniczając się do sygnatur dokumentów) i tylko dla nich sprawdzamy czy D należy do wyników zapytania Z tj. czy wszystkie słowa kluczowe zapytania Z zawierają się w zbiorze słów kluczowych dokumentu D.
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 duży dokument tekstowy typu CLOB, 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. Odwołując się do naszego przykładu możemy chcieć usunąć element zawierający
kod adresu Kowalskiego. Następująca instrukcja: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.
Następująca instrukcja tworzy indeks dla wartości elementu MIASTO: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ązaną 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 programistyczne PL/SQL wspomagające definiowanie, przechowywanie i przetwarzanie dokumentów XML.
Reasumując, do obsługi dokumentów XML w bazie danych wystarczają wprowadzone wcześniej pojęcia jak typy obiektowe, duże obiekty CLOB oraz oczywiście język PL/SQL.
Zatem 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.
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.