POLSKO-JAPOŃSKA WYŻSZA SZKOŁA TECHNIK KOMPUTEROWYCH PRACA MAGISTERSKA Nr ................ Język zapytań dla XML oparty na podejściu stosowym Studenci Rafał Hryniów Tomasz Pieciukiewicz Nr albumu 829 871 prof. dr hab. Kazimierz Subieta Bazy Danych i Inżynieria Oprogramowania Inżynierii Oprogramowania 20.05.2001 15.06.2002 Promotor Specjalność Katedra Data zatwierdzenia tematu Data zakończenia pracy Podpis promotora pracy Podpis kierownika katedry .................................... ......................................... Język zapytań dla XML oparty na podejściu stosowym Streszczenie Niniejsza praca przedstawia zaimplementowany przez autorów język zapytań do XML oparty na podejściu stosowym. Obszary, których dotyczy praca to: języki zapytań, XML i narzędzia wspomagające tworzenie repozytoriów dokumentów. We wstępie autorzy przedstawiają cel powstania niniejszej pracy oraz motywacje stojące za jego wyborem. Opisują też podział pracy pomiędzy autorów. W rozdziale dotyczącym stanu sztuki autorzy przedstawiają standardy i technologie dotyczące poszczególnych obszarów, których dotyczy praca, jak również wskazują niedostatki istniejących rozwiązań i kroki, jakie należy podjąć w celu ich wyeliminowania. W rozdziale dotyczącym narzędzi i teorii znajdują się informacje dotyczące narzędzi użytych podczas tworzenia implementacji języka zapytań, jak również zwięzły opis teorii, na której opiera się główny element niniejszej pracy. Rozdział omawiający rezultaty pracy opisuje składnię i semantykę stworzonego języka oraz API udostępniane użytkownikowi. Kolejny rozdział zawiera szczegółowy opis implementacji i zastosowanych rozwiązań technicznych, użyte struktury danych, jak również zastosowane algorytmy. W ostatnim rozdziale można znaleźć informacje na temat trudności napotkanych podczas realizacji pracy. Autorzy wskazują również potencjalne obszary zastosowań stworzonego języka zapytań, jak również możliwości jego dalszego rozwoju. Strona 2 Język zapytań dla XML oparty na podejściu stosowym Spis Treści I. WSTĘP ......................................................................................................................................................... 5 II. STAN SZTUKI ............................................................................................................................................ 7 1. REPOZYTORIA............................................................................................................................................ 7 1.1. Zastosowanie repozytoriów ............................................................................................................. 7 1.2. Informacje o dokumentach przechowywanych w repozytoriach ..................................................... 7 1.3. Podstawowe założenia repozytoriów ............................................................................................... 8 1.4. Uchwyty ........................................................................................................................................... 9 1.5. Struktura Repozytorium................................................................................................................... 9 1.6. Repository Access Protocol ........................................................................................................... 10 1.7. Inne podejścia ............................................................................................................................... 10 1.8. Dostrzeżone braki.......................................................................................................................... 10 1.9. Proponowane rozwiązanie ............................................................................................................ 11 2. XML (EXTENSIBLE MARKUP LANGUAGE) .............................................................................................. 11 2.1. Geneza XML .................................................................................................................................. 12 2.2. Własności XML ............................................................................................................................. 12 2.3. Znaczenie XML.............................................................................................................................. 13 2.4. XML – Zastosowanie ..................................................................................................................... 14 2.5. Technologie i standardy powiązane z XML................................................................................... 16 3. JĘZYKI ZAPYTAŃ ..................................................................................................................................... 22 3.1. Języki zapytań w systemach relacyjnych ....................................................................................... 22 3.2. Języki zapytań w systemach obiektowych ...................................................................................... 23 3.3. Języki zapytań dla XML................................................................................................................. 24 3.4. Próba oceny przydatności istniejących rozwiązań ........................................................................ 31 3.5. Proponowane rozwiązanie ............................................................................................................ 32 III. NARZĘDZIA I TEORIE ZASTOSOWANE PODCZAS REALIZACJI PRACY ......................... 34 JĘZYK JAVA ............................................................................................................................................. 34 4.1. Co to jest Java ............................................................................................................................... 34 4.2. Java a inne języki programowania ................................................................................................ 35 4.3. Java a XML ................................................................................................................................... 36 4.4. Dlaczego właśnie Java? ................................................................................................................ 36 5. PARSER XERCES I STANDARD DOM ...................................................................................................... 37 5.1. Standard DOM .............................................................................................................................. 37 5.2. Parser XERCES ............................................................................................................................ 38 6. NARZĘDZIA WSPOMAGAJĄCE TWORZENIE PARSERÓW ............................................................................. 38 6.1. JFLEX ........................................................................................................................................... 38 6.2. CUP ............................................................................................................................................... 39 7. TEORIA STOSOWYCH JĘZYKÓW ZAPYTAŃ ................................................................................................ 39 7.1. Podejście stosowe .......................................................................................................................... 39 7.2. Podejście stosowe a języki zapytań ............................................................................................... 42 7.3. Podejście stosowe na tle innych teorii........................................................................................... 43 7.4. Podejście stosowe a XML .............................................................................................................. 44 4. IV. OMÓWIENIE REZULTATÓW PRACY .......................................................................................... 45 OMÓWIENIE JĘZYKA ZAPYTAŃ DLA XML STANOWIĄCEGO ZASADNICZY REZULTAT PRACY ................... 45 8.1. Składania języka ............................................................................................................................ 45 8.2. Stos rezultatów .............................................................................................................................. 47 8.3. Semantyka języka zapytań dla XML .............................................................................................. 47 8.4. Linki i sposób ich użycia ............................................................................................................... 56 9. OMÓWIENIE API UDOSTĘPNIANEGO PRZEZ SYSTEM ................................................................................ 58 9.1. Klasa edu.t2r.magisterka.QueryExecutor ..................................................................................... 58 9.2. Klasa edu.t2r.magisterka.ReferenceManager ............................................................................... 59 9.3. Klasy klasa edu.t2r.magisterka.parser i edu.t2r.magisterka.Lexer ............................................... 60 9.4. Klasa edu.t2r.magisterka.LinkManager ........................................................................................ 60 9.5. Metody służące do operacji na węzłach XML ............................................................................... 61 8. V. OMÓWIENIE IMPLEMENTACJI......................................................................................................... 62 Strona 3 Język zapytań dla XML oparty na podejściu stosowym 10. 10.1. 10.2. 10.3. 10.4. 11. 11.1. 11.2. 11.3. 11.4. 11.5. 11.6. 11.7. 12. 12.1. 12.2. 12.3. 12.4. 13. 13.1. 13.2. 14. 14.1. 14.2. 14.3. 15. 15.1. 15.2. 15.3. VI. ROZWIĄZANIA IMPLEMENTACYJNE – STRUKTURY DANYCH ................................................................ 62 Skład obiektów .............................................................................................................................. 62 Stos środowisk i rezultatów ........................................................................................................... 62 Bindery .......................................................................................................................................... 63 Zarządzanie referencjami .............................................................................................................. 63 ROZWIĄZANIA IMPLEMENTACYJNE – IMPLEMENTACJA OPERATORÓW ALGEBRAICZNYCH .................. 65 Operatory arytmetyczne ................................................................................................................ 65 Operatory działające na łańcuchach tekstowych .......................................................................... 66 Operatory logiczne ........................................................................................................................ 67 Operatory porównań ..................................................................................................................... 69 Operatory działające na kolekcjach .............................................................................................. 71 Operatory zmiany nazwy ............................................................................................................... 72 Złączenia ....................................................................................................................................... 74 ROZWIĄZANIA IMPLEMENTACYJNE – IMPLEMENTACJA OPERATORÓW NIE-ALGEBRAICZNYCH ........... 75 Operatory selekcji ......................................................................................................................... 75 Kwantyfikatory .............................................................................................................................. 76 Złączenia ....................................................................................................................................... 77 Inne operatory ............................................................................................................................... 78 ROZWIĄZANIA IMPLEMENTACYJNE – OPERACJE ELLIPSE I $ ................................................................ 79 Implementacja operacji ................................................................................................................. 79 O czym należy pamiętać przy rozszerzaniu funkcjonalności języka o operacje aktualizacji ......... 80 ROZWIĄZANIA IMPLEMENTACYJNE – IMPLEMENTACJA LINKÓW ......................................................... 80 Zebranie informacji o węzłach z identyfikatorami ........................................................................ 80 Obsługa linków w trakcie wykonywania zapytań .......................................................................... 80 O czym należy pamiętać przy rozszerzaniu funkcjonalności języka o operacje aktualizacji ......... 80 ROZWIĄZANIA IMPLEMENTACYJNE – INTERPRETACJA ZAPYTAŃ......................................................... 81 Konstrukcja skanera ...................................................................................................................... 81 Konstrukcja parsera ...................................................................................................................... 82 Konstrukcja drzewa rozbioru gramatycznego ............................................................................... 85 ZAKOŃCZENIE .................................................................................................................................. 88 16. 16.1. 16.2. 17. 17.1. 17.2. 18. 18.1. 18.2. 19. TRUDNOŚCI PRZY REALIZACJI PRACY.................................................................................................. 88 Wpływ DOM na sposób realizacji pracy ....................................................................................... 88 Inne napotkane trudności .............................................................................................................. 88 WADY I ZALETY PRZYJĘTEGO ROZWIĄZANIA ...................................................................................... 89 Zalety przyjętego rozwiązania ....................................................................................................... 89 Wady przyjętego rozwiązania ........................................................................................................ 89 POTENCJALNE ZASTOSOWANIA PRACY ............................................................................................... 89 Możliwości wykorzystania rezultatu pracy w konstrukcji repozytorium dokumentów .................. 89 Możliwości wykorzystania pracy w konstrukcji aplikacji .............................................................. 90 MOŻLIWOŚCI ROZWOJU PRACY ........................................................................................................... 90 Strona 4 Język zapytań dla XML oparty na podejściu stosowym I. Wstęp W dotychczasowym toku studiów magistranci dostrzegli brak dobrych rozwiązań dotyczących dwóch istotnych zdaniem autorów zagadnień: Brak opartego na mocnych podstawach teoretycznych i łatwo rozszerzalnego języka zapytań dla XML Brak języka zapytań umożliwiającego łatwe wyszukiwanie żądanych informacji w repozytoriach dokumentów. Znane jest wiele języków zapytań do XML jednak ich podstawy teoretyczne oraz wygoda użytkowania pozostawiają wiele do życzenia. W przypadku repozytoriów języki zapytań języki wydają się być jedyną dziedziną pominięta przez autorów prac związanych z tą dziedziną. Podstawową motywacją autorów było ukazanie siły podejścia stosowego dla języków zapytań poprzez implementację prototypowego języka zapytań dla XML. Autorzy często odczuwają potrzebę korzystania z niewielkich repozytoriów dokumentów, nie są jednak usatysfakcjonowani obecnie istniejącymi rozwiązaniami w zakresie wyszukiwania informacji w repozytoriach. Celem pracy jest stworzenie generycznego narzędzia, które da podstawy dla dalszych prac nad tworzeniem systemów repozytoriów, wyszukiwarek, systemów zarządzania wersjami, itp. W tym celu autorzy zamierzają stworzyć język zapytań dla dokumentów XML, który zdecydowanie usprawni proces tworzenia takich systemów. Proponowanym rozwiązaniem jest język zapytań dla XML zbudowany w oparciu o podejście stosowe dla języków zapytań opracowane przez Kazimierza Subietę ([3]). W toku prac zastosowano następujące narzędzia: Java – jako język programowania użyty do implementacji prototypu języka zapytań dla XML Xerces – parser dokumentów XML, zgodny ze standardem DOM 2.0 JFlex – generator skanerów użyty przy konstrukcji parsera dla stworzonego języka zapytań. CUP – generator parserów LALR(1) użyty przy konstrukcji parsera dla stworzonego języka zapytań. Rezultatem pracy jest język zapytań stworzony w oparciu o podejście stosowe, umożliwiający wykonywanie zapytań na wielu dokumentach XML jednocześnie. Udowodniono, że podejście stosowe dobrze nadaje się do języka zapytań dla dokumentów XML. Ponadto stworzono generyczne narzędzie umożliwiające tworzenie systemów, w których potrzebny jest język zapytań, a duży serwer bazodanowy jest z pewnych przyczyn nieodpowiedni. Jako, że praca ta była tworzona w zespole dwuosobowym, konieczne był podział pracy między obu członków zespołu. Podział pracy był następujący: Rafał Hryniów: o Implementacja zarządzania referencjami o Implementacja stosu środowisk i binderów o Implementacja operatorów nie-algebraicznych o Implementacja operacji shallow ($) Strona 5 Język zapytań dla XML oparty na podejściu stosowym o Stan sztuki, opis narzędzi i teorii – Java, oraz XML wraz z językami zapytań dla XML, podejście stosowe Tomasz Pieciukiewicz: o Stworzenie parsera, łącznie z konstrukcją drzewa rozbioru zapytania o Implementacja linków. o Adaptacja drzewa DOM do potrzeb pracy o Implementacja operatorów algebraicznych o Implementacja operacji ellipse o Stan sztuki, opis narzędzi i teorii – repozytoria dokumentów, języki zapytań (bez języków zapytań dla XML), ewaluacja przydatności poszczególnych rozwiązań w zakresie języków zapytań do potrzeb niniejszej pracy, JFLex, CUP, DOM Każdy z członków zespołu odpowiedzialny był za napisanie części pracy magisterskiej odpowiadającej jego zadaniom implementacyjnym. Pozostała część pracy została napisana wspólnie. Strona 6 Język zapytań dla XML oparty na podejściu stosowym II. Stan sztuki Niniejszy rozdział stanowi próbę przedstawienia czytelnikowi istniejących rozwiązań w zakresie repozytoriów dokumentów, XML wraz z technologiami pochodnymi oraz języków zapytań, jak również wskazania najważniejszych według autorów braków w istniejących już rozwiązaniach. Autorzy zdają sobie sprawę, że opis ten nie może być kompletny, gdyż wszystkie trzy wspomniane dziedziny są bardzo rozbudowane, jak również szybko ewoluują i próba ich pełnego opisu skazana jest na niepowodzenie. 1. Repozytoria Repozytoria są szczególnym przypadkiem systemów gromadzenia danych. W przeciwieństwie do najpopularniejszych – systemów zarządzania bazami danych - repozytoria służą do przechowywania i wyszukiwania różnego rodzaju dokumentów elektronicznych (zamiast starannie obrobionych danych o określonej strukturze). Dokumenty przechowywane w repozytoriach mogą być różnego typu – od czystych dokumentów tekstowych, przez dokumenty w językach takich jak HTML lub XML, kody źródłowe programów, po pliki binarne takie jak zdjęcia lub programy wykonywalne. Repozytoria muszą dostarczać sposobów wyszukiwania tego typu danych, przechowywania informacji o ich wzajemnych powiązaniach, różnych wersjach tego samego dokumentu itd. Informacje zawarte w tej części pracy oparte są na standardzie opracowanym w Corporation for National Research Initiatives (CNRI), opisanym w [8], stosowanym z większymi lub mniejszymi zmianami w większości powstających obecnie cyfrowych bibliotek. 1.1. Zastosowanie repozytoriów Repozytoria stosowane są w kilku obszarach: W bibliotekach cyfrowych takich jak na przykład CSTR (Computer Science Technical Reports) w celu przechowywania, wyszukiwania i udostępniania dokumentów znajdujących się w tych bibliotekach. W systemach zarządzania wersjami lub konfiguracją (takich jak CVS, ClearCase lub internetowy SourceForge), w celu przechowywania wszystkich objętych kontrolą składników oprogramowania. Wyszukiwarki internetowe, takie jak np. Altavista lub Google, również można uznać za swego rodzaju repozytoria (zwłaszcza, że przechowują one kopie znajdujących się w ich katalogach dokumentów). 1.2. Informacje o dokumentach przechowywanych w repozytoriach Zgodnie z [8], informacje o dokumentach przechowywanych w repozytoriach powinny zawierać następujące dane: Związki z innymi dokumentami. Dokument może być częścią innego dokumentu (na przykład zdjęcie może być częścią artykułu prasowego). Dokument może też składać się z innych dokumentów (na przykład książka z rozdziałów), lub też należeć do jakiejś sekwencji (na przykład jeden z serii tygodniowych raportów z postępów prac). Repozytorium musi zapewniać możliwość przechowywania informacji o związkach każdego z dokumentów z innymi i naturze tych związków. Strona 7 Język zapytań dla XML oparty na podejściu stosowym Format, w jakim przechowywany jest dany dokument. Ten sam dokument może być przechowywany w różnych formatach, czasem różniących się przenoszoną informacją (na przykład zdjęcie nie skompresowane i poddane kompresji stratnej), czasem zawierające tą samą informację i umożliwiające przeprowadzenie konwersji (na przykład zdjęcie nie skompresowane i poddane kompresji bezstratnej). Repozytorium powinno zapewniać możliwość przechowywania informacji o formatach, w jakich dostępny jest dany dokument i umożliwiać pobranie dokumentu w żądanym formacie (jeśli taki jest dostępny). Wersja dokumentu. Dokumenty mogą być zmieniane – w każdej z wersji mogą różnić się pojedynczym bitem, lub całą zawartością. Repozytorium powinno umożliwiać przechowywanie dokumentów z rozróżnieniem wersji, w jakiej są przechowywane, oraz pobieranie żądanej wersji. Ponadto w repozytoriach należałoby przechowywać następujące informacje, pozwalające na łatwe wyszukiwanie dokumentów: Informacje identyfikujące autorów danego dokumentu, instytucje zaangażowane w jego powstanie, datę i miejsce publikacji, ewentualnie dane wydawcy itd. Informacje mówiące o zawartości dokumentu, takie jak słowa kluczowe, nazwiska osób, nazwy miejsc itd., których dotyczy dokument, ewentualnie kategorie tematyczne. Inne (zgodne z zapotrzebowaniem) dane dotyczące dokumentu. 1.3. Podstawowe założenia repozytoriów Podczas projektowania architektura informacji w repozytoriach należy brać pod uwagę następujące założenia ([8]): Należy dać użytkownikowi jak największą elastyczność. Ponieważ użytkownicy przeszukują materiały na wiele różnych sposobów, organizacja informacji nie może być oparta na oczekiwaniach dotyczących podejścia użytkownika do materiałów, jego poziomu doświadczenia, lub kolejności dostępu do pozycji. Kolekcje muszą być proste w zarządzaniu. W bibliotekach cyfrowych (jak we wszystkich bibliotekach), niewielki zespół specjalistów zarządza bardzo dużymi zbiorami. Architektura musi pozwalać temu zespołowi skupić się na istotnych zadaniach, uwalniając ich od rutynowych zajęć. (Dotyczy to też wykorzystania repozytoriów w zastosowaniach innych niż biblioteki cyfrowe, w celu redukcji kosztów administracyjnych). Architektura musi odzwierciedlać ekonomiczne, społeczne i prawne ramy infrastruktury informatycznej. W szczególności należy pamiętać, iż informacja jest wartościowa, podlega rozmaitym uregulowaniom prawnym i jest transmitowana przez (zazwyczaj) niezabezpieczone sieci, przekraczające granice państwowe. Ponadto, system powinien spełniać następujące warunki dotyczące sposobu przechowywania i opisywania dokumentów ([8]): Wszystkie dane (dokumenty) mają przypisany typ danych Każdy dokument ma przypisany do niego typ danych. Typ określa, w jakim formacie jest dany dokument (na przykład format ASCII lub JPEG), w jaki sposób powinien być przetwarzany (na przykład, jeśli jest programem napisanym w C), lub jaką ma organizację (na przykład tekst opisany znacznikami SGML). Metadane są kodowane explicite Używane metadane są kodowane explicite. Żadna informacja semantyczna zawarta np. w części nazwy nie może być pominięta w metadanych (w przeciwieństwie do np. systemów plików w systemach operacyjnych, gdzie informacja semantyczna jest często zawarta w nazwie pliku – np. „.txt” wskazuje na plik tekstowy). Strona 8 Język zapytań dla XML oparty na podejściu stosowym Uchwyty są przypisane pojedynczym obiektom będącym własnością intelektualną Jeśli informacja może być użyta samodzielnie, przyznawany jej jest własny uchwyt i tworzony jest z niej osobny obiekt. Dzięki posiadaniu przez nią własnego uchwytu, można uzyskać do niej bezpośredni dostęp. Pozwala to na dużą elastyczność. (Przykładowo, tekst może zawierać ilustracje. Przy tym podejściu każda z ilustracji będzie osobnym obiektem z własnym uchwytem). Metaobiekty są używane do agregowania obiektów W bibliotece elektronicznej pełne metadane dotyczące pojedynczej pozycji informacji, jak również jej kopie, mogą istnieć w wielu miejscach w repozytorium, jak również w zewnętrznych systemach. Dla każdego obiektu w związku z tym należy tworzyć metaobiekt, zawierający dane dotyczące obiektu oraz łącza do wszystkich wersji obiektu w repozytorium. Uchwyty są używane do identyfikacji obiektów zawartych w metaobiektach Metaobiekt zawiera listę. Pozycje w liście identyfikowane są przy pomocy uchwytów. Przykład użycia metaobiektu: W repozytorium znajdują się 3 wersje tej samej fotografii: wersja o wysokiej, średniej i niskiej rozdzielczości. Każda z wersji jest opisana przy pomocy własnego zestawu metadanych. Uchwyty do wszystkich trzech wersji fotografii znajdują się w metaobiekcie. Metadane tego metaobiektu zawierają informacje wspólne dla wszystkich trzech wersji fotografii. Jeśli w jakimś innym dokumencie znajdzie się odniesienie do tego metaobiektu, użytkownik próbujący pobrać fotografię będzie miał wybór między wszystkimi dostępnymi wersjami. 1.4. Uchwyty Uchwyt jest unikalnym identyfikatorem obiektu, pozwalającym na jego identyfikację. Zasoby identyfikowane przez uchwyt mogą być zmieniane, przenoszone w inne miejsca, przechowywane w wielu miejscach repozytorium lub w inny sposób zmieniać się w czasie, lecz uchwyt do obiektu pozostanie niezmienny. System jest w stanie powiązać uchwyt z konkretnym zasobem – obiektem. Wszelkie powiązania między obiektami realizowane są właśnie przy pomocy uchwytów. Uchwyty zbudowane są z dwóch części – kodu instytucji nadającej nazwy (naming authority) i kodu zasobu. Przykładem uchwytu może być np. loc.pp/4a32371, gdzie loc.pp odnosi się do instytucji nadającej nazwy, zaś 4a32371 do konkretnego zasobu. 1.5. Struktura Repozytorium Repozytorium oparte na standardzie opracowanym w CRNI jest systemem wielowarstwowym. Do komunikacji między repozytoriami, oraz między repozytorium a aplikacją kliencką wykorzystywany jest protokół RAP (Repository Access Protocol) oparty na standardzie CORBA (protokół ten to po prostu definicja interfejsu CORBA, realizującego 9 podstawowych operacji na repozytorium). Repozytorium składa się z trzech warstw: Interfejs repozytorium (Repository shell) udostępniający interfejs do repozytorium. Implementuje protokół RAP, zapewnia konwersję między wewnętrzną i zewnętrzną reprezentacją obiektów oraz zarządza prawami i uprawnieniami. Warstwa zarządzania obiektami (Object management Layer) zapewnia interfejs między usługami trwałego składu i usługami interfejsu repozytorium. Zapewnia mapowanie uchwytów na rzeczywiste obiekty. Trwały skład (Persistent store) służy do przechowywania informacji zawartej w repozytorium. Implementacja trwałego składu jest ukryta przed światem zewnętrznym, dzięki czemu możliwe jest użycie we wdrażanym systemie dowolnego z dostępnych systemów trwałego składu. Obiekty w składzie nie są przechowywane w postaci pojedynczego bloku danych. Każdy obiekt mapowany jest na pewną strukturę: Strona 9 Język zapytań dla XML oparty na podejściu stosowym Element jest najbardziej podstawową ze struktur składu. Każdy element składa się z unikalnego (w ramach danego składu) identyfikatora, atrybutów opisujących dany element (takich jak typ lub rola) oraz bloku danych (dowolnej sekwencji bajtów). Pakiet jest kolekcją elementów oraz innych pakietów, posiadającą własne ID. Obiekt jest pakietem lub elementem uzupełnionym o opisujące go metadane, przeznaczonym do udostępnienia. ID obiektu to jego uchwyt. Przykładowo, książka (obiekt w repozytorium) może składać się z rozdziałów (pakietów), zaś każdy z rozdziałów zawierać elementy w postaci tekstu rozdziału i odpowiednich ilustracji.(Uwaga – rozdziały, tekst i ilustracje, jeśli przypisane zostaną im odpowiednie metadane również bez przeszkód mogą zostać udostępnione jako obiekty). 1.6. Repository Access Protocol Repository Access Protocol używany jest we wszystkich interakcjach pomiędzy światem zewnętrznym a repozytorium. Systemy opisywane w [8] implementują następujące metody składające się na interfejs RAP: VerifyHandle pozwala sprawdzić, czy uchwyt został zarejestrowany w systemie uchwytów, AccessRepoMeta pozwala na dostęp do metadanych repozytorium, Verify_DO pozwala sprawdzić, czy repozytorium przechowuje obiekt z danym uchwytem, AccessMeta pozwala na dostęp do metadanych konkretnego obiektu, Access_DO pozwala na dostęp do obiektu, Deposit_DO pozwala na wprowadzenie obiektu do repozytorium, Delete_DO pozwala na usunięcie obiektu z repozytorium, MutateMeta pozwala na edycję metadanych obiektu, Mutate_DO pozwala na edycję obiektu, Te 9 operacji pozwala na wykonywanie podstawowych działań na repozytorium. Oprogramowanie klienckie opracowane w ramach programu początkowo wykorzystywało RAP, później jednak zdecydowano się na odejście od idei grubego klienta na rzecz dostępu do repozytorium przez WWW za pośrednictwem skryptów CGI, które z kolei kontaktowały się z repozytorium za pomocą RAP. 1.7. Inne podejścia Prezentowane podejście jest najbardziej zaawansowanym ze wszystkich znanych autorom rozwiązań. Najczęściej spotykane systemy - używane wyłącznie w rozwoju oprogramowania, takie jak CVS są bardzo ograniczone pod względem możliwości – małą elastyczność, jeśli chodzi o definiowanie metadanych, sposób przechowywania zasobów (zazwyczaj jedynie przy pomocy systemu plików) itd. Niestety, bardzo trudno jest uzyskać dane na temat struktury repozytoriów w systemach komercyjnych, jednak określanie przez producenta możliwości dowolnego nazywania wersji obiektu w repozytorium (nie zaś tylko przy pomocy numeru wersji) jako osiągnięcia (Visual SourceSafe ([9]) świadczy o tym, że pod względem elastyczności tych systemów jest niewiele lepiej, niż w przypadku systemów darmowych. Niektóre systemy komercyjne, takie jak np. Continuus oferują możliwość wykonywania zapytań (w tym tworzenia raportów) na metadanych, przechowywanych w relacyjnej bazie danych. Niestety, znaczny koszt komercyjnych systemów typu Configuration Management uniemożliwia autorom osobiste zapoznanie się z zastosowanymi w nich rozwiązaniami. 1.8. Dostrzeżone braki Prezentowane rozwiązanie wydaje się być dość rozsądne i atrakcyjne, należy jednak zwrócić uwagę na bardzo istotne niedomaganie. Rozbudowane metadane związane z obiektami i możliwość Strona 10 Język zapytań dla XML oparty na podejściu stosowym tworzenia powiązań (zarówno typu „część-całość” jak i „związany z”) między nimi są raczej obciążeniem dla poszukujących informacji, nie zaś ułatwieniem, w sytuacji, gdy brak efektywnego narzędzia służącego do nawigowania wśród danych – takiego jak język zapytań. Prezentowany standard nie zakłada niczego na temat takiego języka, w znanych autorom materiałach brak jakiejkolwiek wzmianki o konieczności jego istnienia. Niektóre systemy komercyjne używają języka zapytań (zazwyczaj SQL), jednak są one silnie ukierunkowane na jeden obszar zastosowań. 1.9. Proponowane rozwiązanie 1.9.1 Cechy idealnego rozwiązania Idealne repozytorium powinno być na tyle generyczne, aby możliwe było wykorzystanie go w dowolnym zastosowaniu - nie powinno być z góry nastawione na wykorzystanie w systemie kontroli konfiguracji, bibliotece elektronicznej czy portalu internetowym. Jego konstrukcja powinna umożliwiać szybkie i łatwe przystosowanie go do użycia w dowolnym systemie wymagającym użycia repozytorium. Uważamy, że do osiągnięcia tego celu należy użyć następujących środków: Struktura metadanych dla repozytorium powinna być jak najbardziej elastyczna, co umożliwi dopasowanie metadanych do potrzeb, System powinien być wyposażony w język zapytań, umożliwiający szybkie i łatwe operowanie na metadanych. Możliwości tego języka powinny być dopasowane do przyjętego modelu metadanych, Powinien zostać skonstruowany w architekturze wielowarstwowej. System składu, system zarządzania obiektami, interfejs repozytorium i interfejs użytkownika powinny być oddzielone od siebie tak, aby możliwa była łatwa podmiana lub modyfikacja dowolnego z komponentów systemu. 1.9.2 Nasza propozycja Architektura opracowana w CNRI odpowiada dwóm z trzech wymienionych założeń – nie posiada jedynie języka zapytań. Proponujemy rozwiązanie zbliżone do tej właśnie architektury. Nasza propozycja realizacji poszczególnych założeń wygląda następująco: Dane i metadane można przechowywać w postaci plików XML o strukturze definiowanej przez użytkownika. Pozwoli to na łatwą modyfikację struktury danych pod kątem konkretnych zastosowań. Należy zaimplementować język zapytań umożliwiający wykonywanie zapytań na danych przechowywanych w postaci plików XML. Da to podstawę do późniejszej budowy repozytoriów używających dowolnych technologii, zaopatrzonych w silne narzędzie to wyszukiwania potrzebnych dokumentów. W dalszej części tego rozdziału przypatrujemy się bliżej rozwiązaniom w zakresie XML i języków zapytań mogącym mieć zastosowanie w takiej pracy. 2. XML (eXtensible Markup Language) Materiały wykorzystane w tym rozdziale pochodzą w głównej mierze ze stron W3C ([15]), książek ([25], [26]) oraz szeroko pojętych zasobów internetowych Błyskawiczny rozwój internetu, a zwłaszcza WWW przyczynił się do ukazania niedostatków HTML - głównego języka używanego w Internecie. Ponieważ HTML stworzony został jako język do prezentacji danych, nie jest on dostatecznie elastyczny oraz nie udostępnia wsparcia wymaganego dla rozwoju aplikacji internetowych. Mianowicie pojawiła się konieczność tworzenie dużych systemów rozproszonych pobierających danych z systemów heterogenicznych, baz danych, aplikacji. Aplikacje muszą porozumiewać się nie tylko z innymi elementami aplikacji, ale także z innymi systemami biznesowymi – często opartymi o inne technologie. Co więcej klientem aplikacji to nie tylko przeglądarki ale także telefony komórkowe (WAP), „organizery” obsługujące zupełnie inne znaczniki. Strona 11 Język zapytań dla XML oparty na podejściu stosowym W związku z tym podstawowym zadaniem współczesnej aplikacji jest organizacja i przetwarzanie danych. XML powstał jako narzędzie zdecydowanie mocniejsze niż HTML, mające stanowić panaceum na problemy trapiące twórców aplikacji rozproszonych. Główną różnicą między HTML i XML jest to, że HTML jest to typowy język znacznikowy, zawierający predefiniowane znaczniki, a XML jest meta-językiem pozwalającym na definiowanie własnych znaczników a także własnej struktury dokumentów. 2.1. Geneza XML Prekursorem XML był SGML (Standard Generalized Markup Language), który powstał w wyniku naturalnych potrzeb przechowywania danych niezależnie od oprogramowania lub jego producentów. Na podstawie SGML powstało setki ukierunkowanych języków znacznikowych zdefiniowanych przy pomocy SGML (aplikacjj SGML). Aplikacje te są używane w przemyśle (J2008), wojsku (Mil-M-38784), w Sieci (HTML), a także innych zastosowaniach (DocBook, TEI). Niestety SGML jest językiem zbyt skomplikowanym i kosztownym, aby używać go w Sieci na dużą skalę. Skomplikowanie SGML powoduje, że do wykorzystanie go niezbędne są duże ilości szkoleń, czasu, narzędzi. Głównym celem XML, który powstał jako podzbiór SGML było umożliwienie przesyłania, przetwarzania, udostępniania danych zakodowanych w SGML poprzez Sieć w możliwie jak najprostszy sposób. Popularność XML przyczyniła się do stworzenie wielu „kilkuliterowych” technologii, rozszerzających możliwości XML (np. XSL, XSLT, XHTML, XSD, XPath, XPointer, XLink) – kilka naszym zdaniem najistotniejszych zostanie opisana w dalszej części rozdziału. W chwili obecnej XML oraz technologie z nim związane rozwijane są przez W3C. 2.2. Własności XML Główna cecha XML wywodzącą się bezpośrednio z SGML jest możliwość definiowania dowolnych znaczników oraz reguł gramatycznych, oraz możliwość późniejszej walidacji dokumentów. Walidacja możliwa jest poprzez użycie w XML standardu DTD (Document Type Definition) będącego częścią SGML, pozwalającego na walidację dokumentów zgodnie ze zdefiniowanym schematem. Obecnie tworzony jest standard XML Schema, lepiej dopasowany do specyfiki XML, mający zastąpić DTD. Dodatkowo dziesięć głównych założeń (według W3C [15]) poczynionych przez twórców spowodowało znaczne uproszczenie XML a także lepsze dopasowanie do wymogów Sieci. Najważniejsze założenie to: XML może być używany w istniejących protokołach sieciowych i przy użyciu tych samych mechanizmów. XML ma obsługiwać szeroki zakres zastosowań. Z tego założenia wynika prostota oraz elastyczność XML. XML ma być kompatybilny z SGML. Łatwość tworzenia parserów XML. Prosta struktura XML pozwala w prosty sposób tworzyć wydajne parsery XML. Minimalizacja opcjonalnych cech XML. Założenie to umożliwia szybsze nauczenia się XML, a także uproszczenie narzędzi do XML. Dokumenty XML powinny być zrozumiałe także dla człowieka oraz bez nadmiernego lukru syntaktycznego (można się spierać czy założenie to udało się spełnić w XML) Projekt XML należy stworzyć szybko. Strona 12 Język zapytań dla XML oparty na podejściu stosowym Projekt XML ma być formalny i spójny. Jako podstawę specyfikacji XML użyto rozszerzonego formatu Backus-Naura (EBNF – Extended Backus-Naura Format) dobrze znanego wśród programistów1. Łatwość tworzenia dokumentów XML Zwięzłość znaczników nie ma praktycznie znaczenia. Oprócz powyższych założeń zawiera wiele dodatkowych cech ułatwiających używanie go w Sieci: Modularność – możliwość łączenia wielu fragmentów kodu XML lub pojedynczych DTD w spójną całość Internacjonalizacja – oparcie działania XML o Unicode pozwala zapomnieć o problemach ze znakami diakrytycznymi. XML wymaga także, aby całe oprogramowanie obsługujące XML także obsługiwało Unicode. Ukierunkowanie na dane – standard XML został stworzony do opisu i obsługi danych. Zapewnia walidację struktury dokumentów, oraz ścisła kontrolę danych (XML Schema). Niestety XML umożliwia tylko opisanie semantyki danych. Przy braku ontologii dla danych problematyczne wydaje się automatyczne przetwarzanie danych przez komputer. W tym momencie programiści tworzący aplikacje używające XML do wysyłania i odbierania danych muszą znać ontologię danych w celu zrozumienia danych (wiedza ta niestety nie pochodzi z XML). Możliwość tworzenia łączy między elementami XML (wewnątrz dokumentu oraz do zewnętrznych źródeł danych) pozwala odzwierciedlić relację oraz zależności między encjami. Służą do tego technologie XLink oraz XPointer. Technologie zostaną opisane w dalszej części rozdziału. XML pozwala pracować z dokumentami na dwa sposoby – formalnie i nieformalnie. Dla małych projektów lub prototypowania, można tworzyć dokumenty poprawnie zbudowane. Dla większych projektów lepsze jest stworzenie dokumentów walidowanych. Poprawnie zbudowany dokument XML spełnia następujące reguły: Tylko jeden element główny Każdy niepusty element ma odpowiadające mu znaczniki początku i końca Wszystkie elementy są poprawnie zagnieżdżone, bez zazębiania Wymogi dotyczące znaków (np. znaki specjalne) oraz nazewnictwa. Dokument walidowalny to dokument poprawnie zbudowany, który także: Zawiera lub odwołuje się do schematu lub DTD. Spełnia wymogi danego schematu lub DTD Koncepcja XML oparta jest na dokumentach złożonych z encji. Każda encja może zawierać jeden lub więcej logicznych elementów. Każdy z tych elementów może posiadać atrybuty (właściwości) opisujące dany element. XML udostępnia składnię dla opisu związków między encjami, elementami i atrybutami, które składają się na dokument XML, która z kolei jest używana przez parser do rozpoznawania komponentów, z których składa się dokument. 2.3. Znaczenie XML Istnieje wiele powodów zainteresowanie XML. Jednym z najważniejszych jest niezależność danych przechowywanych w XML od środowiska, w jakim te dane mają zostać przetwarzane. Łatwość tworzenia dokumentów oraz teoretyczna możliwość zrozumienia struktury i zawartości dokumentu (rozsądne tylko dla niewielkich dokumentów) pozwala twierdzić, że XML może zastąpić w niedługim czasie HTML. Przykładem takiego trendu jest technologia XHTML, w której dokumenty 1 Bardziej popularna jest jednak notacja BNF. Strona 13 Język zapytań dla XML oparty na podejściu stosowym HTML są opisywane zgodnie z wymogami XML. Ponadto XML wraz z DTD (lub XML Schema) pozwala stworzyć standard wymiany informacji niezależny od rozwiązanie programowego oraz platformy sprzętowej. Spowodowane jest to tym, iż prostota budowy dokumentów umożliwia łatwą budowę wydajnych narzędzi. Na dzień dzisiejszy powstały parsery XML dla wszystkich popularnych języków. 2.4. XML – Zastosowanie Chociaż pierwotnym założeniem twórców XML było stworzenie języka mogącego zastąpić, w coraz większym stopniu niewystarczający, HTML. XML jako otwarty język, wraz ze wsparciem CSS, miał dostarczyć narzędzie dopasowane do wszystkich potrzeb, będące zarazem alternatywą dla HTML. Cel ten miał być osiągnięty głównie poprzez oddzielenie zawartości (danych) od prezentacji (wyświetlania). Z perspektywy dnia dzisiejszego widać, że ten cel nie został osiągnięty. XML jest używany do tworzenia stron, aczkolwiek zdecydowana większość stron tworzona jest nadal w HTML. Powodem takiego stanu rzeczy, mimo niewątpliwych zalet XML nad HTML, może być wymiernie wyższy wymagany nakład pracy na zaprojektowanie i stworzenie strony internetowej. Oprócz tego w przypadku prostych stron, tworzonych przez pojedynczych użytkowników, część właściwości XML jest niepotrzebna. Kolejnym powodem może być to, że ludzie znający HTML nie mają ochoty uczyć się XML wraz z powiązanymi technologiami (DTD, XSLT). W związku z powyższymi problemami, XML jest używany głównie przez firmy (bądź ludzi), dla których istotne jest rozdzielenie prezentacji do danych. Zasadniczą zaletą takiego podejścia jest to, iż zawartość jest niezależna od aplikacji i może być dowolnie formatowana, prezentacja zaś zależna jest od rodzaju klienta (np. przeglądarką, telefonem z obsługą Internetu itd.) oraz z funkcjami udostępnianymi przez klienta (HTML 4.0, język WML). Zawartość jest przechowywana w XML a prezentacja dla poszczególnych klientów tworzona jest za pomocą XSL i XSLT. Jedną z najpotężniejszych funkcji oferowanych przez XML w zakresie prezentacji jest możliwość tworzenia wielu arkuszy stylów odpowiadających dokumentowi XML. Możliwość ta zdecydowanie zwiększa elastyczność prezentacji – nie tylko można korzystać z jednego dokumentu XML dla wielu prezentacji, lecz struktura publikacji dokonująca transformacji może określić, od jakiego klienta przyszło żądanie dokumentu i automatycznie wybrać właściwy arkusz stylów. Kolejną zaletą jest przejrzystość i łatwość zarządzania systemem a co z tym związane niski koszt eksploatacji systemu. Niestety jak już wspomniano XML nie wyparł i prawdopodobnie nie wyprze HTML w związku z wyższymi nakładami na stworzenie oraz zdecydowanie większym wymaganym nakładem prac na opanowanie technologii. Jednakże bardzo silną alternatywą dla HTML może być XHTML język znacznikowy, stworzony z połączenie HTML i XML (Patrz [XHTML]). Drugim bardzo istotnym zastosowaniem XML jest wymiana danych między aplikacjami systemami. Jest to możliwe, ponieważ dane XML są niezależne od typu klienta, a także nie są wykorzystywane bezpośrednio przez klienta. Kolejną cechą XML przydatna do tego typu zastosowań jest opisywanie dokumentu XML przez samego siebie (co prawda tylko semantyki, ale lepsze to niż nic). Użycie XSL do dokumentu XML pozwala na bardzo łatwą konwersję dokumentu XML do innego dokumentu XML o zupełnie odmiennej strukturze a następnie po przetworzeniu wynikowego dokumentu XML (przez aplikację) znów dzięki XSL na powrót do oryginalnej struktury XML ze zmodyfikowanymi danymi. Kolejnym użyciem XML w komunikacji jest standard XML-RPC. Technologia ta opisuje komunikację między elementami aplikacji. RPC to skrót od Remote Procedure Calls (zdalne wywołania procedur). RPC to jedna z najstarszych technologii umożliwiających wywoływanie procedur przez sieć i także poprzez sieć otrzymywanie odpowiedzi.. Technologia XML-RPC stała się bardzo użytecznym sposobem odwoływanie się do zdalnych usług. XML umożliwiło rozwiać jeden z poważniejszych problemów RPC, związanym z próbą kodowanie złożonych obiektów wyłącznie tekstowo. Dzięki użyciu XML możliwe jest reprezentowanie „dowolnych” typów danych za pomocą dokumentów XML. XML-RPC odwzorowuje parametry obiektu po stronie klienta na elementy XML Strona 14 Język zapytań dla XML oparty na podejściu stosowym a następnie dekoduje te elementy na odpowiedni obiekt na serwerze. Komunikacja w drugą stronę wygląda analogicznie. Kolejnym niezwykle istotnym zastosowaniem XML zastosowanie typu B2B (business-tobusiness). W tym przypadku XML może stanowić standard wymiany informacji między aplikacjami, oraz zamkniętymi systemami. Pozwala on na łatwe przekazywanie danych a także zbieranie i wprowadzanie do systemu informacji do/od partnerów handlowych (sprzedawców, kontrahentów). XML z założenia pozwala na przetwarzanie danych przez komputer, lecz również wyświetlenie informacji np. w przeglądarce, co może eliminować koszt tworzenia aplikacji prezentujących informacje, co umożliwia wykorzystanie danych przez partnerów o niższych możliwościach technicznych (trzeba jednakże wziąć pod uwagę ludzkie ograniczenia dotyczące percepcji). Ostatnim elementem jest publikacja aktualnych informacji o firmie np. finansowych za pośrednictwem XSL oraz XSLT. XML jest także coraz częściej używany do tworzenia plików konfiguracyjnych. Jest to wymogiem dla aplikacji tworzonych zgodnie ze specyfikacją EJB (Enterprise Java Beans) tzw. deskryptory wdrożeniowe (definicja sposobu działania i inne parametry dla EJB) muszą być tworzone w XML. Ponieważ wszyscy producenci wykorzystują te same deskryptory – zwiększa się przenośność kodu EJB. Także duża część nowo tworzonych plików konfiguracyjnych dla aplikacji jest tworzona w XML (np. Apache Tomcat). XML może być też stosowany do przechowywania informacji. Jest to doskonałe rozwiązanie dla przechowywania niewielkiej ilości hierarchicznych danych. Powyżej pewnej ilości przechowywanych danych olbrzymim problemem może być wydajność takiego rozwiązania, zdecydowanie ustępująca wyspecjalizowanym systemom baz danych. Jednakże nawet w przypadku dużej ilości danych XML może być użyty do przenoszenia danych między bazami danych. Większość komercyjnych baz danych umożliwia konwersję do i z XML, dzięki czemu standard XML może w niedalekiej przyszłości stać się standardem wymiany informacji między konkurencyjnymi systemami baz danych. Użycie XML w repozytoriach danych (głównie dokumentów) jest powiązane z poprzednim punktem. Ponieważ nie wszystkie repozytoria wymagają dużej wydajności w dostępie do danych, lub z założenia nie przechowują ogromnej ilości danych, XML może być z powodzeniem używany jako składnica danych dla takich repozytoriów. Doskonałym przykładem takiego typu repozytorium jest repozytorium dokumentów. W pliku XML przechowujemy tylko atrybuty dokumentów, powiązania oraz linki do dokumentów, które przechowywane są niezależnie na dysku. Oczywiście w przypadku chęci indeksowania dokumentów np. po słowach kluczowych lub przechowywania dużej ilości dokumentów, lepszym rozwiązaniem jest składowanie danych w bazie danych, aczkolwiek także i w tym przypadku wygodne może być działanie na XML dla początkowych faz istnienia repozytorium, z powodu łatwej zmiany struktury XML (jak wiadomo, struktura bazy danych może się znacznie zmienić w trakcie tworzenia systemu, głównie z powodu zmian w wymaganiach użytkownika, lub błędów w analizie) oraz łatwej migracji do kolejnych wersji pliku XML. Drugim ciekawym typem repozytorium, dla którego XML jest wystarczającą składnicą danych jest repozytorium projektowe (wersje, informacje o wersjach itp.). XML zazwyczaj jest wystarczająco silną platformą do tego rodzaju repozytoriów, ponieważ, niezbyt często repozytoria te posiadają ilość dokumentów, dla której przetwarzanie plików tekstowych jest uciążliwe, oraz zazwyczaj nie stawiają ostrych wymogów na wydajność repozytorium. Ostatnim zastosowaniem XML, o którym chcielibyśmy wspomnieć jest użycie XML do tworzenia nowych języków znacznikowych. W rozdziale tym wymieniliśmy dwa takie języki (XHTML i WML). XHTML – połączenie HTML i XML, WML – język znacznikowy stworzony do wyświetlania informacji w telefonach komórkowych. Także nowy format graficzny, SVG (Scalable Vector Graphics), służący do opisu dwu-wymiarowej grafiki wektorowej w XML, oraz wiele innych (np. XUL, VML, MathML). Strona 15 Język zapytań dla XML oparty na podejściu stosowym 2.5. Technologie i standardy powiązane z XML Równolegle z standardem XML rozwijany jest szereg technologii oraz standardów bardzo ściśle powiązanych z XML, dzięki którym XML zyskuje na elastyczności, możliwościach a co z tego wynika potencjalnych zastosowaniach. Oprócz tego istnieją standardy związane z SGML, które są używane przez XML (patrz DTD). W związku z tym, iż XML jest obecnie niezmiernie popularny na świecie, ilość technologii z nim powiązanych jest bardzo dużo. Poczynając od definicji przestrzeni nazw przez technologie umożliwiające walidację dokumentów, aż do technologii służących do tworzenia relacji między elementami XML. Osobną sprawą są języki stworzone za pomocą XML (np. XHTML i WAP). Ponieważ nie ma najmniejszego sensu opisywać wszystkich technologii powiązanych z XML skoncentrujemy się tylko naszym zdaniem na najważniejszych technologiach starając się opisać ich założenia, wady oraz zalety a także określić zastosowanie dla tych technologii. 2.5.1 DTD (Document Type Definition) Definicja typu dokumentu nie została wyróżniona w odrębnej specyfikacji, lecz stanowi część specyfikacji XML. Używanie DTD w XML jest bezpośrednim następstwem bycia XML podzbiorem SGML. Jednak, mimo, że XML DTD wywodzi się z SGML DTD to struktura DTD dla XML została znacznie uproszczona, w związku z tym nie jest możliwe przeniesienie DTD stworzonego dla dokumentu SGML do XML bez wykonania konwersji. DTD może narzucić szereg ograniczeń na dokument XML. W DTD zdefiniowana jest poprawna struktura dokumentu XML wraz z listą poprawnych elementów. Poprzez DTD definiujemy gramatykę dokumentu XML. DTD może być zdefiniowany wewnątrz dokumentu XML lub też trzymany w oddzielnym pliku. DTD umożliwia zdefiniowanie następujących ograniczeń: Deklarację dopuszczalnych elementów Deklarację atrybutów dla elementów Deklarację struktury elementów wraz z określeniem wymagalności elementu. Poprzez ograniczenie budowy dokumentu XML uzyskuje się bardzo wymierne korzyści. Aplikacja przetwarzające dokument XML może przeszukać dane, ponieważ wie jak zagnieżdżane są elementy w dokumencie XML. Co więcej poprzez stworzenie DTD tworzymy pewnego rodzaju standard dla dokumentów, w związku ułatwiona jest wymiana danych (ponieważ znamy strukturę dokumentu). Poprzez umożliwienie definiowania elementów opcjonalnych można w zależności od potrzeb, stworzyć bardzo restrykcyjny lub bardzo elastyczny DTD. Wady DTD: DTD posiada własną składnię, zupełnie inną niż składania XML. Konieczność nauki przez ludzi zupełnie innej składni. Konieczność tworzenia odrębnych narzędzi lub odrębnego kodu do parsowania DTD. Brak kontroli zawartości danych umieszczonych między znacznikami (co uniemożliwia kontrolę przekazywanych danych) Trudności w obsłudze konfliktów przestrzeni nazw. W związku z wyżej wymienionymi wadami powstał już XML Schema będący następcą XML DTD. Chociaż XML DTD nie jest jeszcze martwym standardem, istnieje szansa, że stanie się to w niedługiej przyszłości, gdy pojawi się więcej narzędzi do XML Schema. 2.5.2 XML Schema XML Schema jest technologią zaproponowaną przez Microsoft a obecnie tworzoną przez twórców XML oraz członków W3C. XML Schema jest z założenia zamiennikiem DTD, o znacznie zwiększonych możliwościach, usuwający zarazem wady XML DTD. Tak samo jak DTD XML Schema jest standardem służącym do ograniczania (zawężania) dopuszczalnej struktury dokumentów XML. XML Schema można nazwać abstrakcyjnym modelem danych składającym się komponentów np. definicja typu, deklaracja elementu. Komponenty te służą następnie do walidacji poprawnie Strona 16 Język zapytań dla XML oparty na podejściu stosowym zbudowanego dokumentu. XML Schema zbudowany został w oparciu o standard XML 1.0 (Second Edition) oraz standard przestrzeni nazw (XML-Namespaces). Główne cechy XML Schema: Definiuje elementy dopuszczalne w dokumencie Definiuje atrybuty dopuszczalne w dokumencie Definiuje typy danych dla elementów i atrybutów Definiuje domyślne wartości dla elementów i atrybutów Definiuje zagnieżdżanie i liczność zagnieżdżonych elementów Główne zalety XML Schema nad XML DTD Składnia XML Schema identyczna ze składnią XML Wspiera typy danych wraz z tworzeniem nowych typów na podstawie istniejących. Wspiera przestrzeń nazw. Umożliwia zdefiniowanie zbiorów. Definicja równoważności elementów – można przypisać jeden typ wielu elementom. Możliwość używania wyrażeń regularnych przy sprawdzaniu poprawności Bardzo ciekawym i istotnym elementem jest wprowadzenie reguły zamienialności (substitutability) elementów – możemy zdeklarować, element, który może być zamieniony przez inne elementy. Warunkiem koniecznym jest tutaj zgodność typów elementów. Elementy podmieniające muszą mieć typ identyczny z typem elementu podstawianego lub wyprowadzony z tego typu). Można przyjąć, że w praktyce najważniejszym elementem będącym w XML Schema, którego brakowało w DTD jest możliwość definiowania i kontroli typów (pod względem dopuszczalnej zawartości). Mocne narzędzie, jakim jest XML Schema dla dokumentów XML rozszerza możliwe zastosowania XML. XML Schema umożliwia znacznie mocniejszą kontrolę przekazywanymi danymi. Kontrola taka jest praktycznie niezbędna w zastosowaniach bazodanowych oraz biznesowych. Ponieważ większość takich systemów działo według zasady GIGO (Garbage In – Garbage Out), jednym sposobem uniknięcia części śmieci jest kontrola przekazywanych danych. Teoretycznie kontrolę danych można przeprowadzić w aplikacji przetwarzającej XML, aczkolwiek to podejście ma kilka wad – przede wszystkim aplikacji przetwarzających dany typ dokumentu XML może być wiele, w związku z tym, występuje konieczność wielokrotnego pisania podobnego kodu. XML Schema mimo niewątpliwych zalet posiada też pewne wady. Częste zmiany do specyfikacji Stosunkowo duże skomplikowanie specyfikacji (13 typów komponentów w 3 kategoriach, specyfikacja ma kilkaset stron) Dziwna definicja XML Schema – zdefiniowany w XML Schema. Mimo swoich wad, częściowo związanych z wiekiem specyfikacji i brakiem wersji końcowej, XML Schema jest bardzo mocnym narzędziem do walidacji dokumentów XML. Oprócz zwiększenia możliwości w porównaniu z DTD, pozbyto się wad związanych z odmienną składnią, które utrudniały życie zarówno użytkownikom jak i twórcom parserów walidujących. 2.5.3 Przestrzeń nazw w XML (XML Namespaces) Przestrzeń nazw jest to rozwiązanie problemu niejednoznaczności (np. do jakiego elementu odnosi się dany atrybut) oraz kolizji nazw. Zgodnie z definicją W3C przestrzeń nazw XML jest to kolekcja nazw, identyfikowanych poprzez URI (Uniform Resource Identifier), które są używane w dokumencie XML jako nazwy atrybutów i elementów. W3C stwierdza także, że różnica pomiędzy przestrzenią nazw XML a tradycyjną przestrzenią nazw polega na tym, że wersja XML posiada wewnętrzną strukturę i nie jest w matematycznym znaczeniu zbiorem. Strona 17 Język zapytań dla XML oparty na podejściu stosowym Identyczność referencji URI uzyskuje się poprzez porównanie znak po znaku. Referencje URL niespełniające warunku identyczności mogą być równoważne pod względem funkcjonalności (np. referencje różniące się tylko i wyłącznie wielkością znaków). Nazwy w przestrzeni nazw XML składają się z dwóch części rozdzielonych dwukropkiem. Pierwsza część to prefiks, a druga to nazwa lokalna. Na podstawie prefiksu wybierana jest odpowiednia przestrzeń nazw. Ponieważ referencja URI może zawierać znaki niedozwolone dla nazw dopuszczalnych w XML, prefiks z nazwy używany jest jako zamiennik dla właściwej referencji. Zakres użycia danej przestrzeni nazw, ograniczony jest do elementu, w którym został zadeklarowany, a także wszystkich elementów zawartych w danym elemencie. Zakres użycia przestrzeni nazw XML w dokumentach XML jest obecnie raczej niewielki. Istnieje kilka powodów dla takiego stanu rzeczy. 1. W większości przypadków nie ma konfliktów nazw – dotyczy to zwłaszcza dokumentów XML używanych w jednej organizacji. 2. Definicja przestrzeni nazw stworzona przez W3C jest delikatnie rzecz ujmując nieprecyzyjna i mało szczegółowa. 3. Brak wygodnego łączenia DTD i przestrzeni nazw XML – problem ten ma zlikwidować XML Schema Głównym problemem z przestrzenią nazw jest to, że W3C zadeklarowało tylko i wyłącznie nowy system nazewniczy i praktycznie nic więcej. Oto kilka praktycznych i teoretycznych problemów związanych z przestrzenią nazw XML: Teoretycznie nie można określić czy dana nazwa z przestrzeni nazw odnosi się do atrybutu, czy też do elementu.(w praktyce problem ten rozwiązuje aplikacja przetwarzająca XML). Brak sposobu łączenia dokumentów z różnymi DTD. Brak walidacji przestrzeni nazw w dokumentach jej używających. Brak możliwości określenia zależności między schematem a przestrzenią nazw. Brak definicji struktury przestrzeni nazw (chociaż w definicji przestrzeni nazw XML napisane jest, że posiada wewnętrzną strukturę, zapomniano ją określić). Nazwa przestrzeni określona jako URI może prowadzić donikąd. Chociaż występuje wyraźna potrzeba dokładanego określenia przestrzeni nazw dla XML, W3C definiuje praktycznie tylko jednoznaczne identyfikatory i niewiele więcej. Brak jakichkolwiek informacji o budowie przestrzeni nazw, zastąpione ogólnikowymi stwierdzeniami i bardzo szczegółowymi przykładami pokazującymi użycie przestrzeni nazw. Zdecydowanie bardziej precyzyjna definicja tego problemu byłaby bardzo na miejscu, szczególnie, jeśli weźmiemy pod uwagę ilość specyfikacji odnoszących się w jakiś sposób do przestrzeni nazw XML (np. XLink, XPointer). 2.5.4 XPath XPath (XML Path Language) jest produktem współpracy grup zajmujących się rozwojem XSL oraz XPointer. W trakcie rozwoju specyfikacji XSL i XPointer okazało się, że obie technologie potrzebują sposobu na wskazanie zbioru specyficznych elementów w dokumencie XML. Ponieważ tworzenie dwóch praktycznie identycznych języków byłoby tylko i wyłącznie stratą czasu, stworzona została specyfikacja XPath. Jednak, ponieważ istniały pewne różnice w wymaganiach XPath definiuje tylko podstawową (bazową) funkcjonalność, do której zarówno XSL jak i XPointer dodają specyficzne dla siebie wymagania. Specyfikacja XPath określa, w jaki sposób zlokalizować określony element dokumentu XML. Aby to umożliwić definiuje pojęcie węzla (node). Węzłem może być dowolny element, atrybut a nawet dane tekstowe. XPath modeluje dokument XML jako drzewo tak zdefiniowanych węzłów. Specyfikacja ta w pełni wspiera przestrzeń nazw XML, w związku z tym nazwa węzła składa się z części lokalnej oraz URI z przestrzenią nazw (może być pusty). Strona 18 Język zapytań dla XML oparty na podejściu stosowym Podstawową konstrukcją syntaktyczną XPath jest wyrażenie. Wyrażanie może operować zarówno na adresach względnych jak i bezwzględnych. Wyrażenie może zwracać następujące typy danych: Zbiór węzłów Wyrażenie boolowskie (prawda lub fałsz). Liczba Ciąg znaków Obliczanie wyrażenia zachodzi względem kontekstu. Kontekst składa się między innymi z węzła (względem którego jest wyliczane wyrażanie), pozycji i wielkość kontekstu. Bardzo istotnym typem wyrażanie jest wyrażanie lokalizujące (LocationPath). Rezultatem takiego wyrażanie jest zbiór węzłów wybranych względem kontekstu spełniających warunki danego wyrażania. Specyfikacja XPath definiuje zestaw funkcji operujących na węzłach, znakach oraz liczbach, które mogą być używane w wyrażeniach. Funkcje te pozwalając na budowanie całkiem skomplikowanych wyrażeń. W XPath zdefiniowano składnię dopasowania wzorca (np. znajdź element którego elementem macierzystym jest X i elementem siostrzanym Y). XPath wprowadza także definicję unikalnego identyfikatora. Określa się, że tylko elementy w dokumentach posiadających DTD mogą, ale nie muszą posiadać identyfikator. Podsumowując XPath jest w miarę spójnym i intuicyjnym sposobem adresowania zawartości dokumentów XML. Jedynym mankamentem tej specyfikacji jest to, że nie pozwala odróżnić od siebie elementów tego samego typu (siostrzanych o takiej samej nazwie), ani ich uporządkować. Aczkolwiek nie było to założeniem tej specyfikacji. Jednoznaczną identyfikację elementów zajmuje się XPointer bazujący częściowo na XPath. 2.5.5 XPointer Specyfikacja XPointer (XML Pointer Language) definiuje język, który ma być używany jako podstawa do identyfikowania jakiejkolwiek referencji URI, która wskazuje na zasób będący typu XML. XPointer zbudowany jest na bazie XPath. Oprócz specyfikacji XPath duży wpływ na tworzenie specyfikacji miały standardy HTML oraz HyTime (standard ISO umożliwiający reprezentację statycznych i dynamicznych informacji przetwarzanych i wymienianych przez aplikację multimedialne i hipertekstowe). XPointer wspiera adresowanie wewnętrznych struktur dokumentów XML. Pozwala na przeglądanie hierarchicznej struktury dokumentu XML, a także umożliwia wybór części danego dokumentu na podstawie wielu właściwości, jak typ elementu, wartość atrybutu, zawartość danych tekstowych, a także pozycji względnej danego elementu. W szczególności (według specyfikacji) XPointer dostarcza referencję do elementów, oraz innych części dokumentu XML, nawet w przypadku nie posiadanie przez elementy identyfikatora. XPointer jak już wspomniano przy opisie specyfikacji XPath, definiuje rozszerzenia do tej specyfikacji. Rozszerzenia te umożliwiają: Użycie XPath jako części referencji URI określającej dany zasób. Adresowanie punktów (pozycji w dokumencie XML) i zakresów (wszystkie dane między dwoma punktami), jak również całych węzłów. Lokalizację informacji poprzez dopasowywanie ciągów znaków. Struktury adresowane, przez XPointer mogą być używane w tworzeniu łączy, a także do zastosowań specyficznych dla konkretnej aplikacji. Specyfikacja nie ogranicza, co aplikacja może robić danymi identyfikatorami przez XPointer. W szczególności implementacja przejścia do zasobu identyfikowanego przez XPointer nie jest określona w specyfikacji. Definiowaniem łączy wiążących różne zasoby, włączając dokumenty XML i ich części, zajmuje się specyfikacja XLink). Strona 19 Język zapytań dla XML oparty na podejściu stosowym Pewną wadą specyfikacji XPointer jest brak adresowania wewnętrznych struktur DTD oraz deklaracji XML – specyfikacja określa, że te tematy są poza obszarem danej specyfikacji. Prawdopodobnie związane jest to z tym, iż DTD posiada zupełnie inną strukturę (całkowicie niezgodną, z XML), a deklaracja XML, chociaż jest częściowo zgodna z syntaktyką XML(znaczniki i atrybuty), burzy hierarchię dokumentu XML (musi być traktowana inaczej niż elementy XML). Bardzo ciekawą informacją w specyfikacji XPointer, jest możliwość odniesienia się do dowolnego elementu nawet, jeżeli nie posiada on jednoznacznego identyfikatora. W dalszej części specyfikacji można przeczytać, że w tym przypadku, element jest określany względnie np. węzła posiadającego ID. Jest to bardzo ciekawe podejście, ponieważ, naszym zdaniem nie umożliwia precyzyjnego określenia dokumentu (a taki jest sens specyfikacji XPointer), w przypadku możliwości wykonywania zmian na dokumencie (np. wstawmy element siostrzany przed elementem określanym względnie – wtedy identyfikator odnosić się będzie do nowo wstawionego elementu, a nie do już istniejącego). Specyfikacja wspomina, że powinno się używać identyfikatorów elementów i W3C do tego zachęca, ale nie wymaga. Praktycznie jedynym sensownym rozwiązaniem tego problemu jest wymuszenie istnienia unikalnych identyfikatorów dla każdego elementu mogącego być adresowanym przez XPointer, a co z tego wynika, mogącym być odnośnikiem jakiegoś łącza. W tym momencie można korzystać z specyfikacji XPointer, wymuszając np. w ramach projektu stosowanie identyfikatorów. Podsumowując, specyfikacja ta jest krokiem w dobrym kierunku, aczkolwiek błędy, które się w niej znalazły, wykluczają wiele zastosowań. Widać wyraźnie, że twórcy tego standardu nie mają za wiele do czynienia z bazami danych i nie zdają sobie sprawy z konsekwencji tego, co piszą. Miejmy nadzieję, że standard XPointer poprawi te błędy, wymuszając stosowanie identyfikatorów (a co za tym idzie, XML Schema lub DTD, dzięki którym można sprawdzić czy jest atrybut o nazwie ID) dla dokumentów, które chcą korzystać z specyfikacji XPointer. Bardzo istotnym dodatkowym problemem związanym z specyfikacją XPointer jest to, że jest ona wciąż w trakcie tworzenia i w związku z tym nie jest zaimplementowana w najważniejszych przeglądarkach, przeglądarkach także innych programach. 2.5.6 XLink (XML Linking Language) Specyfikacja XLink definiuje język umożliwiający wstawianie elementów do dokumentów XML w celu zdefiniowania łączy między zasobami. Używa syntaktyki XML w celu stworzenia struktur, które opisują proste łącza jak w HTML, jak również bardziej złożone. Łącze w terminologii XLink to połączenie dwóch lub większej ilości obiektów danych lub ich fragmentów. Łącza XML oparte są na elementach łączących. Z kolei elementy łączące zawierają lokalizatory (dane dotyczące lokalizacji) wskazujące konkretne zasoby. Lokalizatory są to URI, identyfikator fragmentu, bądź połączenie obu tych możliwości. Lokalizatorami dla dokumentów XML mogą być wskaźniki typu XPointer. XLink definiuje dwa typy łącz – łącza proste i złożone. Łącza proste są bardzo zbliżone do mechanizmu łącz znanego z standardu HTML. Są to łącza jednokierunkowe, gdzie występuje tylko jeden lokalizator. Łącza złożone jest to bardzo ciekawa propozycja, umożliwiająca znaczne rozszerzenie zastosowań XML. Jednym z ciekawszych rzeczy jest fakt, że łącza nie muszą znajdować się w pliku XML, w którym się zaczynają lub, na który wskazują. Jest to jednakże tylko udogodnienie, oprócz tego łącza złożone umożliwiają: Łączenie dowolnej liczby zasobów, umożliwia to tworzenie relacji jeden-do-wielu a co za tym idzie także obsługę relacji wiele-do-wielu, zamiast zwykłej relacji jeden-do-jednego znanej z łącz prostych i HTML. Łączenie zasobów, które same nie mogą zawierać łączy (np.pliki graficzne, binarne itp.) Dynamiczne filtrowanie, dodawania i modyfikację łączy. Realizację połączeń na wiele sposobów w zależności od potrzeb. Strona 20 Język zapytań dla XML oparty na podejściu stosowym Łącza złożone w rzeczywistości bezpośrednio na nic nie wskazują, ani nic nie łączą. Element łącza złożonego zawiera lokalizatory oraz wewnętrzną identyfikację, które łącznie tworzą właściwe łącze. Oprócz tego XLink pozwala opisywać łącza i ich zasoby poprzez zdefiniowanie pewnych atrybutów. Przykładowym atrybutem jest atrybut „role” oznaczający rolę, jaką stanowi dane łącze dla aplikacji. Jak już wspomniano łącza nie muszą znajdować się w dokumentach których dotyczą. Możliwe jest to poprzez zdefiniowanie grupy łącz. Elementy grupy łącz, nic nie wskazuje, umożliwia natomiast określenie elementów, w których poszczególne dokumenty zawierają zasoby. Dodatkowymi cechami XLink jest możliwość określenia zachowania się łączy. Można określić, kiedy łącze będzie aktywne, kiedy nastąpi skok, lecz także, co ma się dziać w momencie skoku. Specyfikacja XLink znacznie rozszerza możliwości XML. Zastosowanie XLink umożliwi modelowania bardziej rzeczywistych zależności między dokumentami XML, a także pozwoli na usunięcie redundancji danych. Teoretycznie pozwoli także na tworzenie baz danych opartych w całości na dokumentach XML (pozostaje kwestia wydajności takiego systemu). Zaletą takiej bazy danych byłoby naturalne rozproszenie zasobów. Trzeba jednak stwierdzić, że bez precyzyjnej możliwości określenia elementów, do których odnosi się łącze XLink (poprzez bardziej precyzyjne zdefiniowanie XPointer), mogą wystąpić problemy w wielu zastosowaniach (np. bazy danych). Niestety tak samo jak XPointer, specyfikacja XLink jest wciąż w trakcie tworzenia, przez co nie jest ona jeszcze praktycznie implementowana (Mozilla posiada częściową implementację poprzedniej wersji XLink – XML Link). W związku z tym, problematyczne jest ustosunkowanie się do rzeczywistych możliwości i potencjalnych zastosowań technologii XLink oraz technologii z nią powiązanych. 2.5.7 Rozszerzalny język arkuszy stylów (XSL - eXtensible Style sheet Language) XSL jest to język stylów dla dokumentów XML. Ponieważ XML nie posiada niezmiennych i ściśle określonych znaczników (jak HTML), oraz informacje zawarte w dokumencie XML, mogą nie być w formie, w jakiej chcemy je prezentować, a także znaczniki XML zazwyczaj nie niosą informacji o formatowaniu, stworzono XSL udostępniający informacje jak prezentować i przetwarzać dokumenty XML. XSL składa się z trzech części: Transformacji XSL (XSLT) – język dla dokonywania transformacji na dokumentach XML XPath – języka używanego przez XSLT do wskazania lub pobrania części dokumentu XML. XSL Formatting Objects – zestaw słów kluczowych XML, dla specyfikowania formatowania. Rozdzielenie treści od warstwy prezentacji pozwala prezentować te same informacje na wiele różnych sposobów. Oto kilka przykładowych zalet: Ta sama treść może mieć różny wygląd w zależności od kontekstu. Wiele formatów docelowych, w zależności od medium przenoszącego informacje (papier, wersja elektroniczna), rozmiaru, urządzeń docelowych (stacja robocza, palmtop, telefon komórkowy). Wygląd dostosowany do preferencji użytkownika (wygląd, kolor, itp.). Używanie standardowych arkuszy stylów np. w firmie pozwala na uzyskanie jednorodnego wyglądu dokumentów. Istnieją dwa podstawowe zastosowania rozszerzalnych arkuszy stylów. Transformacja jednego dokumentu XML w inny dokument XML – ta bardzo istotna cecha pozwala na usprawnienie wymiany informacji między aplikacjami. Przy czym struktury tych dokumentów mogą być diametralnie różne. Tworzenie opisu dotyczącego prezentacji przekształconych informacji (np. jakie właściwości powiązać z każdą częścią przetwarzanego dokumentu. Podczas transformacji jednego dokumentu XML w inny dane są następujące transformacje: Strona 21 Język zapytań dla XML oparty na podejściu stosowym Generowanie stałych fragmentów tekstu (np. etykiety). Przenoszenie tekstu (np. zamiana kolejności imienia i nazwiska). Duplikacja tekstu (np. Tworzenie spisu treści). Sortowanie Bardziej złożone transformacje „tworzące” nowe informacje na podstawie istniejących danych. Istnieją także następujące formatowanie informacji: Specyfikowanie ogólnego układu strony Przyporządkowywanie przetworzonej treści do odpowiednich „kontenerów zawartości” np. listy, paragrafy. Specyfikowanie właściwości formatowania (odstępy, margines, font, itp.). Podsumowując XSL jest specyfikacja niezbędna do szerszego wykorzystania XML w praktyce. Możliwość transformacji dokumentów, wraz z możliwością dodawania opisów dotyczących formatowania, tworzą z XSL bardzo potężne narzędzie zarówno dla twórców stron WWW jak i twórców aplikacji (prezentacja danych oraz wymiana z innymi aplikacjami). Jeżeli pozostaniemy przy tylko takim zastosowaniu XSL to trzeba przyznać, że ta specyfikacja jest jedną z lepszych, jakie powstały w otoczeniu XML. Oczywiście należy pominąć milczeniem próby stworzenie języka zapytań opartego o XSL (w oparciu o wzorce i ich wyszukiwanie), lecz przecież specyfikacja ta nie do tego ma służyć. 3. Języki zapytań Każdy system służący do gromadzenia danych, aby miał jakiekolwiek praktyczne zastosowanie, musi posiadać narzędzia służące do ich odzyskiwania. Jeśli gromadzone są duże ilości danych, narzędzia te muszą być odpowiednio rozbudowane – powinny umożliwiać wyszukiwanie danych spełniających określone wymagania, agregowanie danych i inne, odpowiednie do przewidywanych zastosowań, operacje. Systemy specjalizowane, tworzone dla konkretnego użytkownika bardzo często zawierają gotowe funkcje tworzenia raportów i filtrowania danych, przystosowane do konkretnych zastosowań. Bardziej generyczne systemy – takie jak Systemy Zarządzania Bazami Danych wymagają narzędzi uniwersalnych: języków zapytań2. 3.1. Języki zapytań w systemach relacyjnych Wszystkie znane autorom pracy Relacyjne SZBD używają jakiejś mutacji języka SQL. Język ten powstał (jeszcze pod nazwą SEQUEL) pod koniec lat 70-tych podczas prac nad System/R – prototypem relacyjnej bazy danych, opracowywanym w laboratoriach IBM. System/R nie doczekał się komercyjnego zastosowania, SQL jednak przetrwał, i został zastosowany w produkcie firmy Relational Software – Oracle, jak również w opracowanych przez IBM systemach SQL/DS i DB2. W połowie lat osiemdziesiątych SQL wygrał konkurencję z językiem QUEL, używanym przez SZBD Ingres. Dzięki stojącej za SQL potędze IBM, język ten stał się standardem de facto. Inne pojawiające się na rynku SZBD również używały SQL jako język zapytań, zaś ANSI rozpoczęła pracę nad standaryzacją SQL. Prace te zaowocowały standardami: SQL-86, SQL-89, SQL-92 i roboczymi wersjami: SQL3 (zarzucony przed zakończeniem prac) i SQL1999 (obecnie opracowywany standard SQL). Niestety, mimo istnienia opracowanych i zatwierdzonych standardów, trudno jest dziś znaleźć SZBD stosujący się do nich w 100%. Każdy producent SZBD wprowadza „usprawnienia” i „udogodnienia”, zapominając jednak często o wprowadzeniu elementów należących do standardu Warto tu zauważyć, że systemy specjalizowane zazwyczaj budowane są na SZBD i ich narzędzia do wyszukiwania danych oparte są na językach zapytań tych SZBD. Ukrywają one zazwyczaj niewygodną dla typowego użytkownika warstwę języka zapytań, oferując łatwiejsze w użyciu (choć bardziej ograniczone) narzędzie. 2 Strona 22 Język zapytań dla XML oparty na podejściu stosowym (przykładem tu może być brak typu TIMESTAMP w systemie Oracle 8i, deklarującym zgodność z SQL-92). Nierzadko różnice te są widoczne już na poziomie syntaktyki języka (drobne różnice w sposobach zapisu wyrażeń, różnice w zbiorach słów kluczowych). Najczęstsze sposoby użycia SQL to: Zanurzony SQL – zapytania SQL są wstawiane bezpośrednio w kod programu w innym języku, w blokach rozpoczynających się deklaracją EXEC SQL. Manipulacja pozyskiwanymi (lub wstawianymi) w ten sposób danymi odbywa się z poziomu języka programowania, w którym zanurzony są instrukcje SQL. Zamiana bloków EXEC SQL na odpowiednie wywołania wykonywana jest przez preprocesor. Sposób użycia zanurzonego SQL określony jest w standardzie SQL-92 (i późniejszych SQL3 i SQL1999). Dynamiczne lub statyczne zapytania SQL, wywoływane przy pomocy odpowiednich API (ODBC, JDBC, API producenta bazy danych). API te są zazwyczaj produktami pojedynczych firm, ich pozycja standardów de facto wynika z pozycji promujących je firm. Napotykają one na szereg problemów, nazywanych zbiorczo „niezgodnością impedancji”, wymienionych i opisanych m.in. w [3]. Wynikają one z zasadniczo różnych koncepcji, z których wywodzą się języki powszechnie używane do tworzenia aplikacji (takie jak C++ lub Java) i SQL. Problemy te są możliwe do uniknięcia tylko przez użycie do tworzenia aplikacji języków zbudowanych na bazie języków zapytań – takich, jak np. Oracle PL/SQL. Niestety, języki te jak na razie mogą mieć tylko ograniczone zastosowanie – kod w takim języku wykonywany jest po stronie serwera SZBD, wskutek czego trudno zastosować taki język np. do oprogramowania interfejsu użytkownika3. SQL – Krótka charakterystyka Oparty jest na modelu relacyjnym, Dostarcza konstrukcje wysokiego poziomu do przetwarzania wielozbiorów i zbiorów krotek, Nie zapewnia swobodnego ortogonalnego kombinowania operatorów. Posiada pod tym względem bardzo ograniczone możliwości, które są często jeszcze bardziej ograniczane przez konkretne implementacje, Nie jest kompletny obliczeniowo, Zapytania SQL mogą być używane wewnątrz języków programowania, dla których zdefiniowane są wiązania. 3.1.1 3.2. Języki zapytań w systemach obiektowych O ile rynek relacyjnych SZBD można uznać za opanowany przez język SQL, o tyle na rynku obiektowych SZBD brak w chwili obecnej takiego ogólnie uznanego standardu. Standard ODMG, obejmujący między innymi OQL (Object Query Language – obiektowy język zapytań) jest implementowany tylko przez część systemów dystrybuowanych jako Obiektowe SZBD. Wielu producentów Obiektowych SZBD wydaje się albo nie dostrzegać potrzeby zaimplementowania języka zapytań (poprzestając jedynie na mechanizmach zapewnienia trwałości obiektów i ich filtrowania), albo uważa za wystarczającą implementację rozbudowanej wersji SQL. 3.2.1 OQL – Krótka charakterystyka Język OQL stanowi część standardu ODMG. Jest językiem deklaratywnym, opartym o składnię SQL. Został zaprojektowany jako język zapytań dla obiektowych baz danych. Obiekty mogą być używane w zapytaniach, są też zwracane przez zapytania. OQL może być używany zarówno z poziomu innego języka programowania (standaryzowano wiązania dla języków C++ i Java), jak i jako samodzielny język zapytań. W przeciwieństwie do SQL jest jedynie językiem zapytań, nie umożliwia wykonywania operacji zmieniających stan bazy danych, z wyjątkiem tworzenia nowych obiektów. W przypadku Oracle PL/SQL możliwe jest stworzenie interfejsu użytkownika opartego na WWW, przy użyciu pakietów PL/SQL wchodzących w skład aplikacji takich jak Oracle Web Application Server, Oracle Web DB lub Oracle Application Server. 3 Strona 23 Język zapytań dla XML oparty na podejściu stosowym Wszelkie operacje wpływające na stan bazy danych muszą być wykonywane z poziomu języka programowania. Możliwość tworzenia nowych obiektów z poziomu języka zapytań, przy jednoczesnym braku możliwości ich usuwania lub zmiany wydaje się być dość dziwne. OQL charakteryzuje się następującymi cechami ([7]): Bazuje na modelu obiektowym ODMG, Powierzchownie przypomina SQL, Przewiduje konstrukcje wysokiego poziomu do przetwarzania zbiorów obiektów, ale nie jest ograniczony do przetwarzania zbiorów (może również przetwarzać struktury, listy, tablice, itp. z taka samą efektywnością), Zapewnia swobodne ortogonalne kombinowanie operatorów, o ile tylko nie narusza to mocnej kontroli typów. Wynika to z faktu, że rezultat zapytania ma typ należący do systemu typów ODMG i w związku z tym może stanowić argument większego zapytania, Nie jest kompletny obliczeniowo, Zapytania OQL mogą być używane wewnątrz języków programowania, dla których ODMG zdefiniował wiązania. OQL może także wołać operacje zdefiniowane w tych językach programowania. Nie ma istotnej różnicy pomiędzy użyciem w zapytaniu atrybutu i metody obiektu. Nie przewiduje explicite operacji aktualizacyjnych, ale może wywoływać operacje zapisane w innych językach, które są dla tego celu zdefiniowane Zapewnia deklaracyjny (nieproceduralny) dostęp do obiektów Zgodnie z deklaracjami ODMG, Formalna semantyka OQL może być łatwo zdefiniowana. To, czy jest tak w rzeczywistości stanowi problem dyskusyjny. Faktem jest, że jak dotąd nie została ona zdefiniowana. 3.2.2 Inne istniejące rozwiązania Poza OQL pojawiły się również inne rozwiązania: SQL3 i SQL1999 wykonują (zgodnie z deklaracjami projektodawców) pewien krok w stronę obiektowości, wprowadzając m.in. ADT – abstrakcyjne typy danych. Są to jednak rozwiązania sprawiające wrażenie prowizorycznych i nie zajmujące się wieloma problemami. Rozszerzenia SQL takie jak SQL++ proponowany przez Objectivity ([4]) i VSQ proponowany przez Versant ([6]), łączące SQL-92, rozszerzenia obiektowe wprowadzone w SQL3, elementy OQL i własne propozycje producentów. Są to rozwiązania, które można uznać co najwyżej za prowizoryczne – zazwyczaj nie umożliwiają one (tak jak w przypadku VSQ i SQL++) wywoływania w ramach zapytania metod. Propozycje typu „Query By Example” proponowane w [5]. SBQL, proponowany w [3], odchodzący całkowicie od związków z SQL, unikający większości jego błędów i problemów. Najbardziej rozbudowany z proponowanych modeli przypomina ideą PL/SQL – język programowania, zintegrowany z językiem zapytań. Taka konstrukcja umożliwia między innymi użycie zapytań jako parametrów procedur (metod), użycie metod w zapytaniach, traktowanie perspektyw jako procedur. Rozwiązuje też problemy z niezgodnością impedancji. Istniejąca implementacja SZBD, używająca tego języka – system Loquis dowodzi, iż jest on możliwy do implementacji. 3.3. Języki zapytań dla XML Jako, że XML jest często wskazywany jako uniwersalny format przechowywania danych strukturalnych, dostrzeżono potrzebę stworzenia języka zapytań umożliwiającego obróbkę danych zawartych w plikach XML. Mimo tego, iż standard XML powstał już wiele lat temu, do tej pory nie udało się stworzenie standardowego języka zapytań dla XML. W3C stworzyło zalecenie dla języka zapytań pod nazwą XML Query Requirements, lecz dokument ten wzbudza wiele kontrowersji. Powstało też wiele języków niebazujących na XML Query Requirements lub bazujących na tym dokumencie tylko częściowo. Poniżej omawiamy znane nam rozwiązania w tym zakresie, jak również zalecenia W3C. Strona 24 Język zapytań dla XML oparty na podejściu stosowym 3.3.1 XML Query Requirements Jak można przeczytać na stronach W3C ([15]), celem XML Query Requirements jest stworzenie modelu danych dla dokumentów XML, zestawu operatorów działających na tym modelu, oraz języka zapytań bazującego na tych operatorach. W3C zakłada użycie języka zapytań dla XML w następujących celach: Wykonywania zapytań na dokumentach XML oraz kolekcjach dokumentów takich jak np. instrukcje obsługi, w celu znalezienia dokumentu, lub fragmentu dokumentu. Wykonywanie zapytań na dokumentach zawierających dane w celu przekształcenia ich do nowej postaci, lub zintegrowania danych z wielu źródeł. Wykonywanie zapytań na dokumentach zawierających zarówno dane jak i opisy tekstowe, takich jak katalogi, dane chorobowe pacjenta itp. Wykonywanie zapytań na danych administracyjnych (pliki konfiguracyjne, logi, profile użytkowników) Filtrowania danych napływających w formie dokumentów XML przysyłanych strumieniowo. Wykonywanie zapytań na drzewach DOM Wykonywanie zapytań na repozytoriach dokumentów w XML oraz serwerach WWW. „Wykonywanie zapytań na katalogach zawierających serwery dokumentów, typy dokumentów, pliki XML Schema, lub dokumenty. Takie katalogi mogą być łączone w celu umożliwienia wyszukiwania na wielu serwerach. System wyszukiwania dokumentów powinien pozwolić użytkownikowi na wybranie katalogów serwerów, reprezentowanych w XML, na podstawie informacji dostarczanej przez serwery, kosztu dostępu lub praw dostępu. Po wybraniu serwera, system wyszukiwania dokumentów może zwrócić rodzaje dokumentów znajdujące się na serwerze i pozwolić użytkownikowi na odpytywanie tych dokumentów”. Zapytania mogą być używane w wielu „środowiskach syntaktycznych” takich jak: URL, strona XML, JSP, ASP. Zapytania mają mieć reprezentację ciągu znaków w programie napisanym w języku programowania ogólnego zastosowania, jako argument z linii komend, lub przesyłane jako protokołu sieciowego. Autorzy dokumentu już określając założenia dotyczące języka zapytań mieszają ze sobą bardzo ogólne, ze szczegółowymi opisami konkretnych zastosowań, oraz ze sprawami czysto technicznymi mającymi mały związek z samą konstrukcją języka zapytań. Jest to po prostu typowy dokument napisany przez W3C. W3C definiuje następujące wymagania stawiane językowi zapytań dla XML: Języki zapytań zbudowane na podstawie dokumentu W3C mogą mieć różne syntaktyki, Język zapytań musi być wygodny i czytelny dla użytkownika i wyrażony w XML. Język zapytań musi być deklaratywny, oraz nie może wymuszać konkretnej strategii ewaluacji Język musi być niezależny od protokołu komunikacyjnego. Język zapytań musi określać standardowe błędy mogące powstać podczas ewaluacji zapytania. Język zapytań dla XML nie może ograniczać możliwości rozbudowy samego standardu XML. „Język zapytań dla XML musi być zdefiniowany dla skończonych instancji modelu danych. Może być zdefiniowany dla nieskończonych instancji.”. Podobnie jak cele, również wymagania stawiane językom zapytań są bardzo dalekie od ideału. W gruncie rzeczy wymaganie te określają tylko i wyłącznie budowę języka zapytań (nakazując wyrażanie zapytań w XML), pomijając praktycznie wszystkie istotne wymagania, jakie powinny znaleźć się w tym dokumencie. Strona 25 Język zapytań dla XML oparty na podejściu stosowym Model danych XML zdefiniowany w opisywanym dokumencie musi spełniać następujące założenia Model danych dla zapytań musi opierać się na informacjach otrzymanych od procesorów XML oraz XML Schema i nie może wymagać informacji niedostarczanych przez te procesory. Model danych musi pokazywać odwzorowanie konstrukcji XML w odpowiednie konstrukcje modelu danych. Model danych powinien mieć reprezentację dla wszystkich elementów niosących informację lub zawierać wyjaśnienie, dlaczego konkretna konstrukcja została pominięta. Model musi być opracowany we współpracy z XML Schema Working Group w celu zapewnienia zgodności między modelem danych a danymi dostarczonymi przez procesory XML Schema. Model danych musi reprezentować zarówno prosty typ znakowy jak i typy proste i złożone zdefiniowane w XML Schema Model danych musi umożliwiać reprezentację kolekcji dokumentów i kolekcji wartości prostych i złożonych. Model danych musi zawierać wsparcie dla referencji, włączając referencje wewnętrzne oraz do zewnętrznych dokumentów XML. Model danych musi uwzględniać elementy wprowadzane do dokumentu XML przez XML Schema, takie jak np. wartości domyślne. Model danych musi uwzględniać przestrzenie nazw. W3C wymaga od języków zapytań dla XML następującej funkcjonalności: Język zapytań musi wspierać operację na wszystkich typach danych reprezentowanych w modelu danych. Zapytania muszą umożliwiać wyrażanie prostych warunków na tekst, włączając warunki na tekst przekraczający granice elementu. Język zapytań musi wspierać kwantyfikatory ogólne i egzystencjalne. Język zapytań musi wspierać operacje na hierarchii i sekwencji struktur dokumentu. Język musi być zdolny do łączenia informacji z wielu części dokumentu, lub wielu dokumentów. Język zapytań musi zawierać operacje agregujące. Język zapytań musi zawierać operacje sortujące. Język zapytań musi umożliwiać zagnieżdżanie zapytań. Język zapytań musi wspierać wartości NULL. Język zapytań musi przenosić hierarchię i kolejność elementów z dokumentu źródłowego do dokumentu stanowiącego wynik zapytania. Język zapytań musi umożliwiać transformację struktury XML i tworzenie nowych struktur. Język zapytań musi umożliwiać przechodzenie po referencjach zarówno wewnątrz jak i na zewnątrz dokumentu. Język zapytań musi zachowywać tożsamość elementów. Język zapytań musi umożliwiać operację na literałach (dowolne dane zdefiniowane wewnątrz zapytania). Język zapytań musi umożliwiać wykonywanie prostych operacji na nazwach, takich jak porównywanie nazw elementów, atrybutów, instrukcji przetwarzania. Musi pozwalać także na operacje na kombinacji nazw i danych. Zapytania mogą wykonywać bardziej złożone operacja na nazwach. Strona 26 Język zapytań dla XML oparty na podejściu stosowym Język zapytań powinien umożliwiać dostęp do XML Schema lub DTD dla danego dokumentu. Jeżeli schemat jest reprezentowany w postaci DTD, mapowanie do XML Schema może być wymagane. Język zapytań musi operować na informacjach post-walidacyjnych otrzymanych od procesora XML Schema. Język zapytań powinien wspierać wykorzystanie zewnętrznie zdefiniowanych funkcji na wszystkich typach danych istniejących w modelu danych. Powinien definiować interfejs dla takich funkcji oraz powinien rozróżniać takie funkcje od funkcji zdefiniowanych w języku zapytań. Implementacja funkcji zewnętrznych nie jest częścią języka zapytań. Język zapytań musi udostępniać informacje środowiskowe, właściwe dla środowiska, w którym zapytanie jest wykonywane. „Zapytanie muszą być domknięte względem modelu danych dla zapytań XML. Zarówno wejście jak i wyjście zapytania muszą być zdefiniowane wyłącznie przy pomocy modelu danych dla zapytań XML. Źródła niebędące dokumentami XML mogą być odpytywane tylko i wyłącznie w przypadku, gdy zostanie dla nich zdefiniowana reprezentacja w modelu danych. Podobnie wyniki zapytań zdefiniowane są wyłącznie przy pomocy modelu danych dla zapytań XML. W oprogramowaniu wyniki te mogą być utworzone przy pomocy dowolnej, wygodnej reprezentacji, takiej jak: DOM, węzły, hiperlinki, tekst XML, lub różne inne formaty danych.” Ponadto W3C stworzyło dwa dokumenty: XML Query Use Cases oraz XQuery 1.0 Formal Semantics. Pierwszy z tych dokumentów zawiera wiele przykładowych danych wraz z przykładami zapytań i pożądanymi wynikami tych zapytań. Drugi zaś zgodnie z tytułem powinien zawierać semantykę XQuery, trudno jest natomiast określić, co rzeczywiście zawiera (ale raczej nie jest to semantyka, zgodnie z ogólnie przyjętą definicją semantyki). Zawarcie przykładów zapytań w dokumencie XML Query Use Cases kłóci się z przyjętym w dokumencie XML Query Requirements założeniem o nie narzucaniu składni języka zapytań. Podobnie jest z dokumentem XQuery 1.0 Formal Semantics, którego znaczne część poświęcona jest gramatyce języka. 3.3.2 XQuery XQuery jest językiem opartym na XML Query Requirements, XQuery 1.0 Formal Semantics i XML Query Use Cases. Istnieje kilka implementacji podzbiorów tego języka, przykładową może być XQuantum Database stworzony przez firmę Cognetic Systems ([16]). Składnia języka oparta jest na gramatyce zdefiniowanej w XQuery 1.0 Formal Semantics oraz przykładach zapytań z dokumentu XML Query Use Cases. Przykładowe zapytanie w XQuery, pochodzące z dokumentu XML Query Use Cases (przykład 1.7.4.7 Q7), wyszukujące strony z wszystkimi aukcjami, dla których zarówno sprzedawca jak i kupujący zarejestrowani są w tym samym domu aukcyjnym. namespace ma = "http://www.example.com/AuctionWatch" <Q7> { for $a in document("data/ns-data.xml")//ma:Auction let $seller_id := $a/ma:Trading_Partners/ma:Seller/*:ID, $buyer_id := $a/ma:Trading_Partners/ma:High_Bidder/*:ID where namespace-uri($seller_id) = namespace-uri($buyer_id) return $a/ma:AuctionHomepage } Strona 27 Język zapytań dla XML oparty na podejściu stosowym </Q7> Wynikiem takiego zapytania (dla przykładowych danych podanych w dokumencie) może być następująca struktura: <Q7 xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:ma="http://www.example.com/AuctionWatch" > <ma:AuctionHomepage xlink:type="simple" xlink:href="http://auctions.yabadoo.com/auction/13143816" /> </Q7> Jak widać stosunkowo proste zapytanie, jest niezbyt czytelne dla użytkownika. Bardziej skomplikowane zapytania, stają jeszcze bardziej nieczytelne. Możliwość wyszukiwania błędów w takich zapytaniach stoi pod znakiem zapytania. 3.3.3 XML-QL XML-QL był propozycją W3C przed stworzeniem XQuery. Podobnie jak w przypadku XQuery, język ten jest zdefiniowany przy pomocy przykładów i gramatyki co wydaje się niezbyt profesjonalną i precyzyjną metodą definiowania języków. Przykładowe zapytanie zawierające złączenie pochodzi z dokumentu opisującego język XML-QL ([17]). Zwraca wszystkie artykuły napisane przed autora, który napisał przynajmniej jedną książkę po 1995 roku. WHERE <article> <author> <firstname> $f </> // firstname $f <lastname> $l </> // lastname $l </> </> CONTENT_AS $a IN "www.a.b.c/bib.xml" <book year=$y> <author> <firstname> $f </> // join on same firstname $f <lastname> $l </> // join on same lastname $l </> </> IN "www.a.b.c/bib.xml", y > 1995 CONSTRUCT <article> $a </> Również ta propozycja W3C, pomijając już niejasności wynikłe z braku precyzji w definiowaniu języka, nie wydaje się zbyt łatwa w użyciu. 3.3.4 LOREL LOREL jest językiem zapytań stworzonym na uniwersytecie w Stanford w ramach projektu LORE ([18]), którego celem było stworzenie systemu zarządzenie bazą danych dla danych półstrukturalnych. Prace nad LORE rozpoczęto w 1995 roku i zakończono ogłaszając sukces w roku Strona 28 Język zapytań dla XML oparty na podejściu stosowym 2000. LOREL jest rozszerzeniem OQL. Zmiany dotyczyły obsługi danych pół-strukturalnych oraz osłabienia mocnej kontroli typów występującej w OQL.. Przykładowe zapytanie w LOREL, wyszukujące nazwy i kody pocztowe wszystkich „tanich” restauracji, w zapytaniu tym nie wiemy czy kod pocztowy będzie częścią adresu czy też elementem potomnym, oraz w którym miejscu opisu restauracji wystąpi słowo „tani”: select Guide.restaurant.name, Guide.restaurant(.address)?.zipcode where Guide.restaurant.% grep "cheap” LOREL jest jednym z bardziej sensownych i czytelnych języków zapytań dla XML. Podobieństwo do OQL pozwala w łatwy i szybki sposób przyswoić sobie ten język. Jego uniwersyteckie korzenie są widoczne w jego elegancji (w porównaniu z propozycjami W3C). W ramach projektu LORE stworzono cały system zarządzania bazą danych, z indeksowaniem i optymalizacją zapytań włącznie. 3.3.5 XQL XQL ([19]) jest, jak twierdzi jego autor „naturalnym rozszerzeniem składni XSL”, został przedstawiony w 1998 roku jako propozycja rozszerzenia składni XSL do XSL Working Group. Zakłada on wykorzystanie mechanizmów XSL w celu wykonywania zapytań na plikach XML. Pomysł ten wydaje się co najmniej wątpliwy – równie dobrze można by wykorzystywać do wykonywania zapytań inne narzędzia służące do obróbki plików tekstowych (jak AWK lub GREP). Jedyną widoczną zaletą tego języka jest stosunkowo prosta składnia nieskomplikowanych zapytań (przynajmniej w porównaniu z przedstawionymi już propozycjami W3C). Przykładowe zapytanie znajdujące węzły typu „author” o wartości tekstowej „Matthew Bob” może wyglądać tak: author[text() = 'Matthew Bob'] lub tak author[. = 'Matthew Bob'] Niestety bardziej skomplikowane zapytania, zwłaszcza wykorzystujące kolekcje lub złączenia, mimo podobnie zwięzłej formy stają się znacznie mniej czytelne. 3.3.6 Yatl Yatl powstał w Bell Laboratories, jako język, jak piszą autorzy w swoim opracowaniu na temat tego języka ([20]), do „odpytywania, konwersji i integracji danych XML”. Został zaimplementowany w całości w języku funkcyjnym (ML lub Objective CAML – autorzy nie są zdecydowani w tekście swojego opracowania). Yatl sam jest językiem funkcyjnym. Przykładowe zapytanie w języku Yatl, wzięte z opracowania „XML Query Languages: Experiences and Exemplars” ([21]) wygląda następująco: make bib [ *book [ @year [ $y ], title [ $t ] ] ] match "www.bn.com/bib.xml" with bib [ *book [ @year [ $y ], title [ $t ] ], publisher [ name [ $n ] ] ] where $n = "Addison-Wesley" and $y > 1991 Jak widać zapytanie to nie różni się zbytnio od zapytań wyrażonych w XQuery – można odnieść wrażenie, że najistotniejszym wkładem autora było zastąpienie nawiasów trójkątnych kwadratowymi. Podobnie jak wspomniane wcześniej języki jego definicja oparta jest na przykładach zapytań. 3.3.7 XML-GL Strona 29 Język zapytań dla XML oparty na podejściu stosowym XML-GL ([21]) jest to graficzny język pozwalający na reprezentowanie: dokumentów XML, DTD, zapytań XML. Składnia XML-GL oparta jest na grafach, które zdaniem twórców są najbardziej intuicyjną i naturalną reprezentacją dokumentów XML. Ta sama reprezentacja, z dodatkową notacją używana jest do reprezentowania zapytań. Przykładowe zapytanie pobrane ze strony twórców XML-GL, zwracające zamówienia wysłane do Los Angeles oraz zawierające książkę zatytułowaną „Introduction to XML”. Po lewej stronie znajduje się warunek, natomiast po prawej elementy, które mają być zwrócone jako wynik zapytania. Graficzne zapytanie, w prototypowym systemie, przekształcane jest na zapytanie w języku LOREL lub XQL, które następnie jest wykonywane. Podejście to wydaje się być ciekawym pomysłem do tworzenia szablonów zapytań mogących pomóc mniej doświadczonym użytkownikom. Jednakże bardziej skomplikowane zapytania (np. ze złączeniami) mogą stać się nieczytelne dla użytkownika. 3.3.8 WebOQL WebOQL ([23]) jest językiem funkcyjnym, opartym na wcześniejszym WebSQL. Składania WebOQL jest optycznie podobna do składni języka SQL. Wewnętrzna reprezentacja dokumentów XML ma postać hiperdrzewa. Przykładowe zapytanie (pobrane ze strony [24]), wyszukujące wszystkie publikacje autorstwa „Smitha”: [Tag:"result" / select y from x "publications"], in browse("file:pubs.xml") Strona 30 via ^*[tag = Język zapytań dla XML oparty na podejściu stosowym y in x', z in y' where z.tag = "author" and z.value ~ "Smith" ] Zapytanie wydaje się być stosunkowo proste i czytelne, prawie pozbawione lukru syntaktycznego, powszechnego w wielu innych rozwiązaniach (W3C). Niestety dokumenty dotyczące tego języka na stronie autora są uszkodzone, w związku z czym niemożliwe jest bliższe zapoznanie się z tym językiem zapytań. 3.4. Próba oceny przydatności istniejących rozwiązań 3.4.1 SQL Zalety: Język popularny, rozwiązanie oparte na SQL może zyskać łatwą akceptację środowiska, Wady: Nieprzystosowanie języka do obsługi wyrażeń ścieżkowych, atrybutów złożonych i powtarzalnych oraz innych elementów, które powinny charakteryzować nowoczesny język zapytań, zwłaszcza przeznaczony do obsługi XML. Brak możliwości ortogonalnego kombinowania operatorów. Ocena przydatności: Dosyć wątpliwa zaleta nie równoważy dyskwalifikujących to rozwiązanie wad. 3.4.2 Rozszerzenie SQL o brakujące elementy Zalety: Język popularny, rozwiązanie oparte na SQL może zyskać łatwą akceptację środowiska, Wady: Rozszerzenie SQL o wszystkie brakujące elementy pozostawi z tego języka jedynie drugorzędne elementy, takie jak np. wygląd niektórych konstrukcji. Ocena przydatności: Uważamy podążanie tą ścieżką za niezbyt sensowne – prowadzi ona w ślepy zaułek. 3.4.3 OQL Zalety: Język jest zaakceptowanym standardem, Ma wszystkie niezbędne cechy, potrzebne językowi zapytań przeznaczonemu do pracy z XML. Wady: Optymalizacja zapytań może być trudna, Ocena przydatności: Rozwiązanie to może być w miarę rozsądne i godne rozważenia. Problemem tu może być jednak pewna nadmiarowość języka – przy przetwarzaniu XML nie będzie konieczne np. wywoływanie metod obiektów, co oznacza, że zaimplementowany będzie tylko pewien podzbiór OQL. 3.4.4 SBQL Zalety: Strona 31 Język zapytań dla XML oparty na podejściu stosowym Ma wszystkie niezbędne cechy, potrzebne językowi zapytań przeznaczonemu do pracy z XML, Dobrze zdefiniowana semantyka, Łatwy w oprogramowaniu i rozbudowie, Znane są sposoby optymalizacji zapytań, Wady: Nie jest powszechnie zaakceptowanym standardem. Ocena przydatności: Uważamy ten język za najrozsądniejszy wybór. Jako że definicja języka w przypadku SBQL zajmuje się przede wszystkim jego semantyką i sposobem działania, nie zaś drugorzędnymi (według Autorów) cechami takimi jak słowa kluczowe, możliwe będzie zarówno jego łatwe zaprogramowanie, jak i dopasowanie słów kluczowych do przyjętych obecnie na świecie standardów (np. Select … From … Where …). 3.4.5 Omówione propozycje języków dla XML Zalety: Trudno znaleźć Wady: Zazwyczaj dość dziwna składnia Nawet najprostsze zapytania są wyrażane w bardzo skomplikowany sposób Ograniczone możliwości Trudna rozbudowa Pozbawione sensownych podstaw teoretycznych Trudna optymalizacja zapytań Ocena przydatności: Istniejące języki zapytań dla XML wydają się być produktami o wątpliwej przydatności i nieprzyjemnymi zarówno w implementacji, jak i w użytkowaniu. 3.4.6 Potencjalny (nieistniejący) język stworzony zgodnie z XML Query Requirements Zalety: Zgodność z propozycjami jednego z bardziej znanych konsorcjów Wady: Spora część z wymagań wydaje się być co najmniej trudna do pogodzenia ze sobą Implementacja wszystkich propozycji spowodowałaby stworzenie mało użytecznego i wygodnego języka, praktycznie niemożliwego do przyswojenia przez człowieka Część wymagań (jak obsługa kolekcji) nie ma związku z innymi istniejącymi na dzień dzisiejszy normami i standardami W3C Część wymagań (jak niezależność od protokołów sieciowych) nie ma żadnego związku z językami zapytań jako takimi – są to kwestie czysto techniczne Ocena przydatności: Zalecenia W3C dotyczące języków zapytań dla XML osiągnęły stan, w którym sugerowanie się nimi byłoby poważnym błędem, prowadzącym do stworzenia nieużytecznego narzędzia. Poważne obawy budzi również niezrozumienie terminologii fachowej przez autorów dokumentów W3C (jak choćby w przypadku dokumentu „XQuery 1.0 Formal Semantics”, którego treść ma niewiele wspólnego z tym, co rozumiemy jako semantykę języka). 3.5. Proponowane rozwiązanie Ze względu na łatwość implementacji i dobre dopasowanie do naszych potrzeb, wybieramy do realizacji SBQL. Inne cechy tego języka – takie jak łatwa rozbudowa (nawet do poziomu języka programowania zintegrowanego z językiem zapytań) oraz dobrze określona semantyka powodują, iż Strona 32 Język zapytań dla XML oparty na podejściu stosowym jest on godnym uwagi językiem. Ponadto w razie potrzeby możliwe jest opracowanie (w ramach dalszych prac rozwojowych) translatora zapytań z innego języka zapytań do SBQL (w drugą stronę mogłoby to być trudne lub niemożliwe). Strona 33 Język zapytań dla XML oparty na podejściu stosowym III. Narzędzia i teorie zastosowane podczas realizacji pracy Niniejszy rozdział stanowi próbę przedstawienia czytelnikowi narzędzi i teorii zastosowanych podczas realizacji pracy. Przedstawienie to powinno pokazać czytelnikowi zasadność dokonanych wyborów w tym zakresie. 4. Język Java Język Java został przez autorów wybrany jako język, w którym stworzona będzie prototypowa implementacja języka zapytań. Poniższy opis języka Java opiera się na materiałach firmy SUN Microsystems ([27]), jak również doświadczeniu autorów. 4.1. Co to jest Java Język Java powstał jako część projektu, którego celem było stworzenie zaawansowanego oprogramowania dla heterogenicznych środowisk. W momencie rozpoczęcia projektu dominującym językiem programowania był język C++, posiadający jednak pewne wady. Chociaż projekt oraz architektura Javy bazują głównie na języku C++, twórcy brali także pomysły z takich językach jak SmallTalk, Eiffel oraz Cedar/Mesa. W wyniku tych działań powstał język nadający się zarówno do tworzenia bezpiecznych aplikacji rozproszonych działających w heterogenicznych środowiskach, jak i praktycznie każdego innego rodzaju oprogramowania (może za wyjątkiem oprogramowania systemowego). Główne założenie języka Java to: Prostota – dla rozpoczęcie pracy z językiem Java nie jest wymagana duża liczba szkoleń, podstawowe założenia języka są proste, przez co programista może być efektywny praktycznie od początku pracy z Java Obiektowość – Java jest zorientowana obiektowo, a co więcej praktycznie wymusza programowanie obiektowe. Obiektowość Javy opiera się na koncepcjach zaprezentowanych w językach Eiffel, SmallTalk, C++, Objective C. Trudne jest określenie jakości modelu obiektowego języka Java, ponieważ opinie są bardzo rozbieżne. Naszym zdaniem jest on zdecydowanie lepszy niż model używany w języku C++, co do innych języków wymienionych w tym punkcie to magistranci nie mają wystarczających doświadczeń. Jako, że najbardziej popularnym językiem w czasach tworzenia Javy był język C++, składnia języka Java jest bardzo zbliżona do składni C++. Pozwala to na łatwą migrację programistów z C++ do Javy. Bezpieczeństwo – twórcy języka Java położyli bardzo silny nacisk na kwestie bezpieczeństwa. Było to spowodowane samymi założeniami Javy – język mający działać w środowisku rozproszonym nie może pomijać kwestii bezpieczeństwa. Trudno jest stwierdzić na ile udane jest rozwiązanie przyjęte w języku Java, warto tylko zauważyć, że Java jest obecnie dominującym językiem oprogramowania używanym w Internecie i pomimo pewnych błędów jest uznawana jako język bezpieczny. Uproszczone zarządzanie pamięcią – bardzo proste tworzenie obiektów, automatyczne odśmiecanie pamięci, co umożliwia uniknięcie wielu błędów. Przenośność – kod Javy ma być uruchomiany na wielu platformach, bez potrzeby rekompilacji, co więcej zarówno rozmiary zmiennych jak i działania operatorów są niezależne od platformy sprzętowej i operacyjnej. Strona 34 Język zapytań dla XML oparty na podejściu stosowym W związku z powyższymi wymaganiami język Java jest językiem interpretowanym, prekompilowanym. Kod języka Java kompilowany jest do kodu pośredniego tzw. „bytecode”, który następnie jest interpretowany przez maszynę wirtualną Javy. W tym miejscu warto zaznaczyć, że pomysł z prekompilacją do kodu pośredniego nie był wcale pomysłem nowatorskim (mimo starań marketingu firmy SUN, żeby wszystkich o tym przekonać), lecz był od dawna wykorzystywany w kompilatorach. Wynikiem tego podejścia jest pewien narzut wydajnościowy związany z potrzebą uruchamiania maszyny wirtualnej. Z drugiej strony interpretacja kodu pozwala na zastosowanie optymalizacji wykonywanych podczas działania programu, znacznie zwiększających wydajność aplikacji. Dzięki tym optymalizacjom Java w dzisiejszych czasach ustępuje głównie aplikacjom zawierającym znaczne ilości grafiki, a w przypadku serwerów aplikacyjnych posiada wydajność porównywalną z językiem C++. Od momentu uzyskania dojrzałości przez język Java (za moment uzyskania dojrzałości możemy uznać wprowadzenie tzw. Java 2) zyskał on bardzo dużą popularność, głównie w środowisku biznesowym. Język ten używany jest zarówno do tworzenia serwisów WWW, aplikacji internetowych, złożonych aplikacji wielowarstwowych jak również prostych aplikacji. W ostatnich latach Java zyskała bardzo duży udział w oprogramowaniu urządzeń przenośnych o niewielkich zasobach (Micro Java). 4.2. Java a inne języki programowania Poniższy punkt ukazuje podstawowe cechy języka Java w porównaniu do języka najbardziej zbliżonego do Javy a mianowicie C++ Główne cech języka Java: Wszystkie typy danych za wyjątkiem typów prostych to obiekty. Tablice w języku Java są to również obiekty. Zarządzanie pamięcią – w porównaniu do C++ zdecydowanie uproszczono zarządzanie pamięcią. Istnieje tylko operator tworzenia obiektu, a system automatycznie usuwa obiekt z pamięci, gdy obiekt nie jest już dłużej używany. Model zarządzania pamięcią oparty jest na referencjach do obiektów. W momencie, gdy liczba referencji odnosząca się do danego obiektu wynosi 0, obiekt może być usunięty z pamięci. Istotną wadą tego podejścia jest to, że w momencie powstania cyklu obiekty mogą nie być usuwane z pamięci. Wielowątkowość – Java posiada wbudowane wsparcie dla wątków, co zdecydowanie upraszcza tworzenie i zarządzanie wątkami. Java zawiera zarówno statyczną (w czasie kompilacji) jak i dynamiczną kontrolę typów. Wszystkie klasy Javy mają wspólny korzeń w hierarchii dziedziczenia. Z powodu braku wielokrotnego dziedziczenia, hierarchia klas w języku Java tworzy drzewo. Podejście to zdecydowanie ułatwia operację na kolekcjach obiektów, lecz niestety może prowadzić także do pewnych błędów wynikających z błędnego rzutowania. Optymalne byłoby wprowadzenie do Javy możliwości tworzenia kolekcji opartych na wzorcach (jak w C++). Rzeczy istniejące w C++ a niewprowadzone do języka Java Usunięto unie oraz struktury – efekt uzyskiwany za pomocą unii i struktur jest równie łatwo osiągalny za pomocą klas. Brak funkcji – w związku z tym, że Java jest językiem obiektowym, a funkcje pochodzą z programowania proceduralnego, Java nie posiada funkcji, a autorzy słusznie zauważyli, że rzeczy osiągalne za pomocą funkcji są równie łatwo osiągalne za pomocą klas i metod. Strona 35 Język zapytań dla XML oparty na podejściu stosowym Brak wielokrotnego dziedziczenia – z powodu znacznych problemów z wielokrotnym dziedziczeniem, z języka Java usunięto tę możliwość. W zamian stworzono koncepcję interfejsów. Interfejs nie jest definicją klasy, lecz definicją metod, które dane klasa implementuje. Klasa może implementować wiele interfejsów, ale dziedziczy zawsze tylko po jednej klasie. Usunięto instrukcję „goto” – zamiast instrukcji „goto” wprowadzono instrukcje „break” oraz „continue”, które zapewniają większość funkcjonalności związanej z instrukcją „goto”. Usunięcie „goto” uprościło język, lecz przede wszystkim pozbawiło programisty robienia wielu „fascynujących” błędów. Brak przeciążania operatorów – twórcy Javy uznali, że przeciążania operatorów może być łatwo zastąpione poprzez klasy i metody. Jedyną wadą takiego podejścia jest wydłużenie zapisu instrukcji. Zaletą jest uproszczenie kodu a także zwiększanie czytelności (programista nie musi się zastanawiać, czy dany operator był przeciążony. Brak automatycznej konwersji typów – w momencie, gdy konwersja typu prowadzi do utraty informacji, w języku Java konieczna jest jawna konwersja typów. Brak wskaźników – w Javie usunięto wskaźniki uważając, że wskaźniki pomagają programiście w pisaniu kodu zawierającego znaczne ilości błędów, które zazwyczaj są bardzo trudne do wykrycia. Wszystkie operacje w języku C++ wykonywane na wskaźnikach można w Javie wykonać na obiektach. Operacje wymagające wskaźników lub struktur w C można wykonać za pomocą obiektów i tablic obiektów. Zamiast arytmetyki wskaźnikowej na tablicach, dostęp do tablic w Javie jest uzyskiwany za pomocą indeksów liczbowych. Pomaga to na sprawdzania poprawności dostępu do tablic podczas działania programu i zapobiega „wychodzeniu” poza tablicą, co było częstym błędem w C. Wadą podejścia zastosowanego w Javie jest pewne spowolnienia operacji wykonywanych w C na wskaźnikach (głównie chodzi o operacje graficzne). 4.3. Java a XML Zarówno Java jak i XML mają pewne wspólne cechy wskazujące, dlaczego właśnie Java jest bardzo dobrym narzędziem do obsługi XML: Zarówno XML jak i Java są w pełni darmowe. XML jak i Java są całkowicie niezależne od platformy systemowej i sprzętowej ( w przypadku Javy ograniczeniem jest ilość działających maszyn wirtualnych dla danego środowiska) W chwili obecnej istnieją narzędzia do języka Java wspierające praktycznie wszystkie obowiązujące standardy przetwarzania dokumentów XML (SAX, DOM, JDOM). Narzędzia te są nieustannie rozwijane, aby nadążyć za ciągłymi zmianami zachodzącymi w XML. 4.4. Dlaczego właśnie Java? Istnieje kilka powodów, dla których zdecydowaliśmy się na wybranie Javy jako języka implementacyjnego: Magistranci posiadają doświadczenie w programowaniu w języku Java. Język Java dzięki swojej strukturze pozwala uniknąć wielu błędów, a także pozwala na łatwe wykrywanie i usuwanie błędów już istniejących W dniu dzisiejszym istnieją narzędzie dla języka Java umożliwiające obsługę dokumentów XML zgodnie z istniejącymi standardami. Poprzez połączenie Javy i XML uzyskujemy narzędzie działające bez dodatkowych nakładów na wielu platformach sprzętowych i systemowych. Strona 36 Język zapytań dla XML oparty na podejściu stosowym 5. Parser XERCES i standard DOM Oczywiste jest, iż aby możliwe było wykonanie jakiegokolwiek zapytania na dokumencie XML, najpierw należy uzyskać dostęp do informacji w nim zawartych. Jako celem tej pracy nie jest implementacja parsera XML lub API służącego do dostępu do dokumentu, zdecydowaliśmy się skorzystać z gotowych narzędzi i standardów przedstawionych poniżej. 5.1. Standard DOM Wyspecyfikowany przez W3C standard DOM (Document Object Model) jest interfejsem pozwalającym na dynamiczny dostęp i modyfikację zawartości, struktury i stylu dokumentu. Interfejsy należące do tego standardu zdefiniowane są w języku IDL. DOM przedstawia dokument w formie lasu (zbioru drzew). Każdy dokument zawiera: 0 lub 1 węzeł typu dokumentu (doctype node), 1 węzeł zawartości dokumentu (document node), dowolną ilość węzłów z komentarzami i instrukcjami przetwarzania. Każdy z węzłów dokumentu może zawierać dowolną liczbę węzłów potomnych. Węzły potomne mogą być: wartościami tekstowymi (reprezentującymi tekst umieszczony pomiędzy znacznikami), atrybutami danego znacznika, węzłami reprezentującymi zagnieżdzone znaczniki, innymi węzłami (np. referencjami do encji XML). Dzięki takiemu sposobowi reprezentacji dokumentów, standard DOM jest doskonałym rozwiązaniem w sytuacji, gdy dla programisty istotna jest nie kolejność występowania poszczególnych informacji w dokumencie, lecz łatwość dostępu do informacji w nim zawartych – takich właśnie jak języki zapytań. Wadą DOM jest konieczność (nie określona w standardzie, ale występująca faktycznie) przechowywania całej struktury dokumentu XML w pamięci jednocześnie. Należy jednak zauważyć, że rzadko spotyka się dokumenty XML o rozmiarach istotnie przekraczających rozmiary pamięci operacyjnej współczesnych komputerów, w związku z czym problem ten dotyczy co najwyżej urządzeń przenośnych (typu palmtop lub telefon komórkowy), lub innych urządzeń z niewielką pamięcią operacyjną. 5.1.1 Poziomy DOM Standard DOM określa tzw. Poziomy (Levels), zawierające określony zakres funkcjonalności w zakresie przetwarzania dokumentów XML. Każdy kolejny poziom oferuje więcej możliwości programiście (równocześnie jednak stawiając większe wymagania przed autorami parserów). W chwili obecnej zdefiniowane4 są 3 poziomy DOM – od najbardziej podstawowego Level 1 do najbardziej zaawansowanego Level 3. Wytworzone w ramach pracy magisterskiej oprogramowanie wymaga do działania parsera implementującego DOM Level 1. 5.1.2 Porównanie z innymi standardami i uzasadnienie wyboru Poza standardem DOM często spotykane są jeszcze dwa API implementowane przez parsery XML: SAX i JDOM. Część z dokumentów specyfikujących poszczególne poziomy jest już zamknięta, część na etapie W3C Recommendation, pozostałe są jeszcze w opracowaniu, ale część funkcjonalności już jest implementowana przez producentów narzędzi. 4 Strona 37 Język zapytań dla XML oparty na podejściu stosowym SAX (Standard API for XML Processing) jest interfejsem stosunkowo niskiego poziomu, umożliwiającym uzyskanie sekwencyjnego dostępu do zawartości dokumentu XML. W przeciwieństwie do DOM i JDOM, które tworzą reprezentację struktury dokumentu w pamięci, SAX wymaga od programisty implementacji klasy obsługującej zdarzenia, jakie mogą zajść podczas parsowania dokumentu XML (zdarzeniem może być np. napotkanie znacznika lub tekstu). Metody tej klasy są następnie wywoływane przez parser SAX. Daje to programiście znacznie większą dowolność, jeśli chodzi o sposób obsługi dokumentu XML, wymaga jednak znacznie większego nakładu pracy. API to nadaje się doskonale do implementacji narzędzi, dla których przetwarzanie sekwencyjne jest bardziej naturalne (przykładem mogą być procesory XSLT). JDOM (Java Document Object Model) jest w swoich założeniach bardzo zbliżony do DOM, jednak stworzony został z myślą o języku Java. Umożliwiło to jego twórcom wprowadzenie szeregu rozwiązań ułatwiających pracę programistom korzystającym z tego języka, jednocześnie jednak czyniąc JDOM nieprzenoszalnym. Nie uważamy, aby ułatwienia oferowane przez JDOM były znaczące na tyle, żeby rezygnować z zastosowania bardziej popularnego (i będącego standardem promowanym przez W3C) rozwiązania. 5.2. Parser XERCES W chwili obecnej na rynku znajduje się duża ilość parserów XML implementujących standard DOM. Wybrany przez nas parser XERCES będący produktem Apache Software Foundation ([10]). Wybór ten został podyktowany wcześniejszymi doświadczeniami magistrantów, zarówno z innymi produktami Apache Software Foundation, jak i z parserem XERCES. Parser ten implementuje DOM Level 1 i 2, jak również SAX Version 1 i 2 oraz XML Schema Recommendation 1.0. Umożliwia walidację dokumentów XML na podstawie DTD lub XML Schema – zarówno podczas wczytywania dokumentu, jak i podczas wprowadzania zmian/tworzenia nowego dokumentu. 6. Narzędzia wspomagające tworzenie parserów Aby przetwarzać zapytania, konieczne jest ich sparsowanie. Pierwsze wersje języka zapytań zaimplementowane w ramach prac wykorzystywały parser zstępujący typu LL(1), ręcznie zakodowany metodą zejść rekurencyjnych. Parser ten jednak był zbyt trudny w pielęgnacji, zwłaszcza biorąc pod uwagę znaczne zmiany zachodzące w definicji języka na wczesnym etapie prac. Ze względu na to, a także na możliwość uproszczenia składni języka przy zmianie typu parsera na LR(1) (lub jeden z typów pochodnych), zdecydowaliśmy się na ten krok. Jako że istnieją wygodne narzędzia do tworzenia parserów, zdecydowaliśmy się na ich użycie. W porównaniu z językami takimi jak C/C++, istnieje stosunkowo niewiele generatorów analizatorów leksykalnych i parserów generujących kod w języku Java. Odnośniki do większości z nich można znaleźć na stronie [11]. Z dostępnych narzędzi wybrane zostały dwa. 6.1. JFLEX JFLEX jest generatorem analizatorów leksykalnych autorstwa Gerwina Kleina. Został zaimplementowany w całości w języku Java, generowany kod jest w tym samym języku. JFLEX przyjmuje specyfikację leksykalną w formacie bardzo zbliżonym do tej tworzonej dla bardziej popularnych narzędzi do C/C++ (takich jak LEX lub FLEX). Jest w stanie wygenerować analizatory obsługujące klasyczny 7 lub 8 bitowy kod ASCII, jak i analizatory obsługujące standard UNICODE. Możliwość ta jest bardzo istotna w przypadku implementacji języka zapytań dla XML, ze względu na możliwość wystąpienia np. znaków diaktrycznych w zapytaniach. Strona 38 Język zapytań dla XML oparty na podejściu stosowym JFLEX został zaprojektowany z myślą o jak najłatwiejszej integracji z darmowymi generatorami parserów: CUP i BYacc/J. Wskutek tego staje się on naturalnym wyborem w sytuacji, gdy planowane jest użycie jednego z tych dwóch narzędzi. W zależności od rozmiaru specyfikacji (i utworzonego na jej podstawie automatu) możliwe jest wykorzystanie jednej z trzech metod generacji kodu wynikowego – z użyciem nie skompresowanej lub skompresowanej (metoda domyślna) tablicy przejść lub też utworzenia zagnieżdżonych instrukcji wyboru (switch). Wady i zalety poszczególnych metod opisane są szczegółowo w instrukcji JFLEX [12], podobnie jak różnice pomiędzy składnią JFLEX i FLEX oraz metody integracji z narzędziami CUP i BYacc/J. 6.2. CUP CUP jest generatorem parserów LALR autorstwa Scotta Hudsona, rozszerzonym następnie przez Franka Flannery, obecnie zaś pielęgnowanym przez C. Scotta Ananiana. Został napisany i generuje kod w języku Java. Przyjmowana przez CUP specyfikacja parsera jest bardzo zbliżona do używanej przez bardzo popularny generator parserów YACC, i opisana jest w dokumentacji CUP ([13]). CUP oferuje programistom pewne ułatwienia – na przykład możliwość zdefiniowania priorytetu i sposobu łączności (lewo- lub prawo- stronnej) dla każdego z operatorów. 7. Teoria stosowych języków zapytań Autorzy zdając sobie sprawę, iż język zapytań powinien być zbudowany na mocnych podstawach teoretycznych. Po przeanalizowaniu istniejących rozwiązań w zakresie języków zapytań, autorzy zdecydowali się na najbardziej relewantne do problemu podejście stosowe zaproponowane przez Kazimierza Subietę. Informacje dotyczące podejścia stosowego w językach programowania oparte są na: [3], [28], [29]. Informacje dotyczące podejścia stosowego w językach zapytań oparte są na: [3]. 7.1. Podejście stosowe Idea podejścia stosowego zagościła w informatyce w latach 60. Podstawową cechą tego podejścia jest istnienie stosu zawierającego informacje o środowisku działania programu. Pojęcie środowiska działania programu według Kazimierza Subiety ([3]) oznacza „zestaw wszystkich bytów programistycznych czasu wykonania (zmiennych, stałych, obiektów, funkcji, procedur, typów, klas, itd.), które są dostępne dla programisty w danym punkcie sterowania programu”. Takie podejście do środowiska działania programu znajduje wyraźne odzwierciedlenie w większości języków programowanie, w których to stos wołań (ang. call stack), lub stos środowiskowy odgrywa kluczową rolę. Podejście stosowe pozwala na traktowanie środowiska jako struktury zmiennej w czasie działania programu. W związku z zastosowaniem stosów w językach programowania opisane zostaną zalety tego podejścia w kontekście języków programowania. W większości języków programowania zachowywane są następujące zasady zarządzania środowiskiem sterowania programu ([3]): Środowisko lokalne procedury posiada priorytet względem środowiska globalnego. Ta zasada pozwala programiście na pomijanie stanu środowiska globalnego podczas pisania procedur. Programista może wywoływać z procedury inne procedury lub funkcje. Szczególną wersją tej zasady są wywołania rekurencyjne. Strona 39 Język zapytań dla XML oparty na podejściu stosowym Programista podczas tworzenia procedury nie może w niej uwzględniać elementów środowiska wykonania, które dopiero się w niej pojawią. Zasady te umożliwiają tworzenie programów efektywniej, oraz z mniejszą ilością błędów. W wielu językach, takich jak C, Pascal, Java zmienne lokalne są usuwane w momencie zakończenia działania funkcji (metody), oraz ponieważ funkcja(metoda) zwraca wynik po otrzymaniu wyników od wszystkich funkcji(metod), które sama wywołała, możemy stwierdzić, że takie wywołanie zachowuje się zgodnie z zasadą LIFO(last in – first out), która dokładanie odpowiada zasadzie działania stosu. W przypadku języków takich jak ML, Schema, gdy istnieją w zagnieżdżone funkcje wraz z funkcjami zwracającymi funkcje występuje potrzeba istnienia zmiennej lokalnej dłużej niż wywołanie funkcji, w której ta zmienna się znajduje. W tym przypadku użycie samego stosu nie wystarcza i potrzebne są dodatkowe zabiegi w celu uzyskanie tej funkcjonalności. Stos środowiskowy w językach programowania spełnia następujące funkcji: Przechowywanie zmiennych lokalnych funkcji (procedury, metody) Przechowywanie parametrów funkcji (procedury, metody) Przechowywanie adresu powrotu z funkcji – adres, pod który przechodzi sterowanie w momencie zakończenia procedury Przechowywania wartości zwracanych przez funkcję (metodę, procedurę) Kontrolowanie zakresu nazw zmiennych a także wiązanie nazw zmiennych. W celu łatwiejszego zarządzania stosem środowiskowym, dzielony jest one na części zwane ramkami (sekcjami). Pojedyncza ramka, zwana także rekordem aktywacji jest to obszar stosu, w którym znajdują się zmienne lokalne, parametry, wartość zwracana przez funkcję. Nowa ramka pojawia się na wierzchołku stosu w momencie wywołania procedury (metody, funkcji). Po zakończeniu wywołania funkcji ramka jest usuwana z wierzchołka stosu. Aktualna metoda m1 wywołuje metodę m2 Wartość zwracana m2 Aktualne parametry m2 Zapamiętany stan procesora Dane lokalne dla m2 Wartość zwracana m1 Wartość zwracana m2 m1 Dane tymczasowe Wartość zwracana m1 Aktualne parametry m1 Aktualne parametry m1 Aktualne parametry m1 Zapamiętany stan procesora Zapamiętany stan procesora Zapamiętany stan procesora Dane lokalne dla m1 Dane lokalne dla m1 Dane lokalne dla m1 Poprzednie ramki m1 Dane tymczasowe (sekcje) Poprzednie ramki m1 Dane tymczasowe (sekcje) Poprzednie ramki m1 Dane tymczasowe (sekcje) Na podstawie [28] Strona 40 Język zapytań dla XML oparty na podejściu stosowym Taka konstrukcja stosu pozwala na wywoływanie procedur z wnętrza procedur a także na rekurencje, ponieważ każde wywołanie procedury (metody, funkcji) posiada własne zmienne lokalne, parametry itp. Jednocześnie w związku z kontrolą zakresu nazw, wiązanie zmiennych następuje na właściwym poziomie, co jest sprawą kluczową (szczególnie przy rekurencji gdzie nazwy zmiennych mamy identyczne dla funkcji wywoływanej i wywołującej). Wiązanie jest to zastępowanie nazw występujących w tekście programu na byty programistyczne czasu wykonania, np. na adresy RAM, identyfikatory obiektów, adresy startowe procedur, itd. ([3]) Wiązanie nazw zmiennej jest to zastępowanie tekstu oznaczającego daną zmienną występującego w kodzie programu na adres w pamięci gdzie przechowywana jest wartość tej zmiennej. Możemy wyróżnić wiązanie statyczne (wczesne) oraz dynamiczne (późne). Wiązanie statyczne odbywa się w trakcie kompilacji, dynamiczne zaś dopiero w momencie działania programu. Wiązanie dynamiczne na stosie środowiskowym posiada bardzo proste zasady działania: Rozpoczynamy poszukiwanie od wierzchołka stosu Jeżeli nie znaleziono szukanej wartości przechodzimy do ramki znajdującej się poniżej. Proces ten kontynuujemy, do momentu znalezienia szukanej wartości W przypadku nie znalezienie wartości przeszukujemy zmienne globalne, dołączane biblioteki, zmienne systemowe itp. Podczas wiązania może się okazać, że należy pominąć niektóre sekcje stosu środowiskowego. Spowodowane jest to tym, środowisko lokalne procedury (metody, funkcji) nie powinno być widoczne w drugiej procedurze (metodzie, funkcji). Także w językach obiektowych bądź wprowadzających moduły może zaistnieć potrzeba pomijania sekcji. Należy pominąć także sekcje związane z modułami, klasami innymi niż te odpowiadające aktualnie wykonywanej procedurze (metodzie, funkcji). p1 woła p2. Procedura p1 znajduje się wewnątrz modułu m1, zaś procedura p2 znajduje się wewnątrz modułu m2. Wykonywany jest blok b wewnątrz p2. Wierzchołek stosu Zmienne zadeklarowane wewnątrz bloku b Kolejność poszukiwani a zmiennej x Zmienne i parametry procedury p2 Prywatne i publiczne własności modułu m2 Własności importowane przez moduł m2 Zmienne i parametry procedury p1 Prywatne i publiczne wartości modułu m1 Własności importowane przez moduł m1 ..... Referencje do wszystkich modułów Referencje do własności środowiska globalnego Dół stosu Algorytm wiązania nazw (na podstawie [3]) Podejścia stosowego w językach programowania gwarantuje następujące właściwości: Programiści nie mają dostępu do wnętrza wywoływanych procedur (metod, funkcji) Brak potrzeby uzgadniania lokalnych nazw zmiennych w różnych procedurach (każda procedura ma środowisko lokalne, które ma pierwszeństwo w przypadku wiązania zmiennych). Strona 41 Język zapytań dla XML oparty na podejściu stosowym Możliwość wywoływania procedur z wnętrza procedur, wraz z wywoływaniami rekurencyjnymi. Możliwe jest to dzięki istnieniu lokalnego środowiska każdego wywołania procedury. 7.2. Podejście stosowe a języki zapytań W literaturze istnieje kilka punktów widzenia na to, jaka jest istota języka zapytań. Jednym z nich jest traktowanie języków zapytań jako wyrażeń wysokiego poziomu zintegrowanych z językiem programowania. Jest to koncepcja o tyle odmienna od pozostałych w szczególności od obecnie najbardziej popularnej (zanurzania języka zapytań w istniejącym języku programowania), ponieważ zakłada stworzenie całkowicie nowego języka, którego integralną częścią będą zapytania. Rozwiązanie to pozwala na bardzo efektywne tworzenie aplikacji, ponieważ programista nie musi poznawać wielu języków (programowania i zapytań) do tworzenia logiki aplikacji, oraz komunikacji z bazą danych. Przykładem takiego języka jest PL/SQL firmy Oracle. Niestety obecne tego typu rozwiązania są zazwyczaj nacechowane ograniczeniami, brakiem uniwersalności oraz innymi wadami. Zakładając takie podejście do języka zapytań można zauważyć, że podejście stosowe jest praktycznie idealne do stworzenia języka zapytań, zawierającego konstrukcje istniejące w językach programowania. Jako pierwszy zauważył to Kazimierz Subieta, który opracował teorię podejścia stosowego dla języków zapytań a także opracował działający prototyp takiego języka (LOQIS powstały w latach 1990-1991). Aby dostosować podejście stosowe, używane do tej pory głównie w językach programowania do specyfiki języka zapytań należy poczynić szereg założeń, co do stosu środowisk. Podstawowe założenia stosu środowisk to: Traktować w jednakowy sposób kolekcie i dane indywidualne Stos nie będzie zawierał wartości zmiennych, obiektów. Spowodowane jest to faktem, iż w zakładanym podejściu odwołania do tego samego obiektu, mogą pojawiać się w wielu miejscach stosu. Na stosie będą przechowywane tylko zbiory „binderów”. Stos będzie podzielony na sekcje zawierające pewne informacje o środowisku wykonania. Na dole stosu znajdować się będą sekcje globalne. Sekcje globalne to: baza danych, zmienne środowiskowe systemu komputerowego, zmienne globalne, itp. Stos będzie w jednorodny sposób traktował zarówno dane ulotne jak i trwałe (znajdujące się w bazie danych) Jak już wspomniano wcześniej na stosie występować będą bindery. „Binder jest parą <n, x>, gdzie n jest zewnętrzną nazwą (nazwą zmiennej, stałej, obiektu, funkcji, perspektywy, procedury, metody, itd.), zaś x jest bytem czasu wykonania (zwykle referencją do obiektu).” ([3]). Bindery są używane do wiązania nazw występujących w zapytaniu na byty czasu wykonania. Nowa sekcja na stosie środowisk tworzona jest we wszystkich przypadkach określonych dla języków programowania, oraz dla pewnych operatorów zwanych „nie-algebraicznymi”. Zmiana ta stanowi podstawową zmianę w stosunku do standardowego podejścia stosowego i warunkowana jest właściwościami języków zapytań. Operatory „nie-algebraiczne” swoim działaniem na stosie przypominają bloki programów. Operatory „nie-algebraiczne” są to operatory niedające sprowadzić się w prosty sposób do algebry. Określone są następujące operatory „nie-algebraiczne” określone dla podejścia stosowego: Where – operator selekcji „.” – operator kropki jest to operator projekcji, nawigacji Operator zależnego złączenia Operator sortowania Strona 42 Język zapytań dla XML oparty na podejściu stosowym Kwantyfikatory Równie istotne jak zdefiniowanie właściwości stosu środowisk jest określenie „Stanu”. Jako „Stan” w podejściu stosowym rozumiemy stany wszystkich obiektów znajdujących się w składzie obiektów, oraz stan stosu środowisk. Zapytania nigdy nie zwracają obiektów a jedynie referencje do obiektów, lub struktury złożone z referencji, wartości elementarnych i nazw. Podobnie jak w przypadku języków programowania także w językach zapytań trzeba określić zasady wiązania nazw. Podobnie jak w językach programowanie wyszukiwanie zaczynamy od wierzchołka stosu. Wyszukiwanie kontynuujemy aż do znalezienia sekcji, w której znajduje się „Binder” z nazwą odpowiadającą szukanej nazwie. Rezultatem jest wartość wszystkich „binderów” w danej sekcji posiadających szukaną nazwę. Podstawową zaletą zastosowania podejścia stosowego do tworzenia języków zapytań jest z pewnością „czystość” oraz przejrzystość nowo utworzonego języka. Co więcej poprzez zastosowanie podejścia stosowego można bez problemów odrzucić wiele ograniczeń istniejących w aktualnie używanych językach zapytań jak SQL, OQL itp.. Język zapytań zbudowany w oparciu o podejście stosowe charakteryzuje się bardzo małą ilością konstrukcji gramatyczno-semantycznych. Dodatkowo, ponieważ języki programowaniu także budowane są w oparciu o podejście stosowe, w miarę łatwym zadaniem jest dobudowanie instrukcji imperatywnych do języka zapytań, tworząc z niego pełnoprawny język programowania, doskonale nadający się do tworzenia aplikacji operujących na bazach danych. Oparcie języka zapytań o podejście stosowe pozwala na wykorzystanie wielu ciekawych i relatywnie prostych optymalizacji. Więcej informacji na temat optymalizacji znajduje się w pracy doktorskiej pana Jacka Płodzienia ([30]). 7.3. Podejście stosowe na tle innych teorii W punkcie tym pokażemy wady istniejących teorii, na których budowane są języki zapytań zarówno do baz relacyjnych jak i obiektowych. Pominiemy tutaj wszystkie teorie, które powstały dla języków zapytań i skoncentrujemy się na dwóch teoriach mających zdecydowanie najwięcej zwolenników: Algebra relacyjna i rachunek relacyjny – podstawową wadą algebry i rachunku relacji jest brak pokrycia całości języka. Algebra relacyjna nie przewiduje istnienia operatorów imperatywnych (INSERT, DELETE, UPDATE), które są integralną częścią języka zapytań bazującego na tych teoriach. Także operacje grupowania i porządkowania nie występują w algebrze relacyjnej Algebry obiektowe – podstawowe wady podobne jak w algebrze relacyjnej. Brak możliwości dokonywanie operacji imperatywnych na obiektach. Algebry obiektowe traktują także pewne operatory nie-algebraiczne jako algebraiczne. Powstał także rachunek obiektowy, który pokazywano jako równoważny algebrze obiektowej ([31], [32]). Jak widać dwie podstawowe teorie na których opierają się języki zapytań, nie wystarczają aby w całości opisać dany język. Problemy powstałe z tego powodu są doskonale widoczne na przykładzie ewolucji SQL, gdzie w miarę rozbudowywania języka o nowe właściwości, jego skomplikowanie rosło w niesamowitym tempie, przy jednoczesnym braku czytelnej semantyki, oraz wielu ograniczeniach na zapytania dopuszczalne w tym języku. Zastosowanie podejścia stosowego do tworzenia języków zapytań, usuwa większość problemów, z którymi borykali się twórcy języków budowanych na innych teoriach. Dając jednocześnie bardzo silne narzędzie zarówno w ręce twórców języka zapytań jak i późniejszych użytkowników tego języka. Strona 43 Język zapytań dla XML oparty na podejściu stosowym 7.4. Podejście stosowe a XML Standard XML posiada kilka cech umożliwiających w miarę naturalne odwzorowanie XML na język zapytań oparty o podejście stosowe. Pierwszą z nich jest traktowanie kolekcji. Zarówno w XML jak i w podejściu stosowym kolekcje tworzy się nie poprzez specjalne struktury, lecz poprzez identyczne nazwy obiektów. Kolejną cechą XML, która doskonale dopasowuje się do podejścia stosowego jest stosunek do wartości zerowych (null). W XML wartości te są po prostu pomijane, co wydaje się być bardzo dobrą zasadą. Istnieje jednak kilka problemów związanych z XML, które powodują pewne problemy przy traktowaniu XML jako bazy danych. Po pierwsze obiekty XML nie posiadają wewnętrznego identyfikatora. Powstaje, więc problem z określeniem identyfikatorów dla XML. Brak jest również w XML standardu dotyczącego możliwości tworzenia relacji, a istniejące propozycje standardów określania relacji (XLink, XPointer) trudno jest uznać za doskonałe. Strona 44 Język zapytań dla XML oparty na podejściu stosowym IV. Omówienie rezultatów pracy Poniższy rozdział przedstawia rezultaty prac. Opis składa się z dwóch części – omówienia języka zapytań dla XML, oraz API udostępnianego przez prototypową implementację tego języka. 8. Omówienie języka zapytań dla XML stanowiącego zasadniczy rezultat pracy Omówienie języka zapytań dla XML przedstawia składnię oraz semantykę tego języka. Aby ułatwić zrozumienie działania poszczególnych operatorów, autorzy oprócz semantyki każdego z nich przedstawiają również przykład użycia wraz z przykładowymi danymi i uzyskiwanym wynikiem. 8.1. Składania języka Składnia, syntaktyka (syntax), formalna budowa napisów języka określona przez jego gramatykę. Program poprawny składniowo nie musi być poprawny semantycznie. Bliskie pytaniu o składnię jest pytanie: „jak to (naprawdę) powinno wyglądać?”. ([14]) W związku z tym, że stworzony przez nas język zapytań, opiera się na podejściu stosowym dla języków zapytań, składnia jego jest podobna do składni języka SBQL (Stack-Based Query Language) opracowanego przez Kazimierza Subietę ([3]). Możemy wyróżnić następujące podstawowe elementy zapytania: Łańcuch znaków w apostrofach np. ‘Kowalski’, ‘Warszawa’ jest zapytaniem, traktowany jest jako dana typu tekstowego. Łańcuch znaków bez apostrofów, możliwy do konwersji na liczbę zmiennoprzecinkową traktowany jest jako dane typu zmiennoprzecinkowego Łańcuch znaków w apostrofach ‘true’ lub ‘false’, z dokładnością do rozmiaru znaków, będzie traktowany jako dana logiczna lub tekstowa w zależności od operatora. Łańcuch znaków bez apostrofów nie możliwy do konwersji na liczbę zmiennoprzecinkową związany będzie do elementu o nazwie odpowiadającej łańcuchowi znaków, znajdującego się na stosie środowisk. Łańcuch ten musi być zgodny ze standardami nazewnictwa węzłów XML. Może być zmodyfikowany poprzez wyrażenie eliptyczne ellipse lub operację $ oznaczającą zawężenie wyszukiwania danej nazwy tylko do wierzchołka stosu środowisk. Zapytania można łączyć ze sobą za pomocą operatorów. Operatory ze względu na syntaktykę możemy podzielić na unarne oraz binarne, oraz ze względu na wykorzystanie stosu środowisk na algebraiczne oraz nie-algebraiczne. Jeżeli operator „op” jest oznaczeniem unarnego operatora algebraicznego, a „q” zapytaniem wówczas „op q” jest zapytaniem. Przykładami operatorów tego typu operatorów są: count, -, exists itd. Jeżeli operator „op” jest oznaczeniem binarnego operatora algebraicznego, a „q1” oraz „q2” są zapytaniami, wówczas „q1 op q2” jest również zapytaniem. Przykładami operatorów tego typu są: +,-,/,*, AND itd. Jeżeli operator „op” jest oznaczeniem operatora nie-algebraicznego niebędącego kwantyfikatorem, a „q1” oraz „q2” są zapytaniami, wówczas „q1 op q2” jest również zapytaniem. Przykładami operatorów nie-algebraicznych jest operator selekcji (where), projekcji lub nawigacji (.), operator zależnego złączenia (DepJoin) itd. Strona 45 Język zapytań dla XML oparty na podejściu stosowym Jeżeli operator „op” jest oznaczeniem kwantyfikatora, a „q1” oraz „q2” są zapytaniami wówczas „FOR ALL q1 HOLDS q2” jest zapytaniem i oznacza kwantyfikator uniwersalny, oraz „FOR ANY q1 HOLDS q2” jest również zapytaniem i oznacza kwantyfikator egzystencjalny. Zapisy te są równoważne „q1 op q2” jednakże zdecydowaliśmy się zachować w miarę tradycyjną składanie do tego typu operatorów. Jeżeli „q” jest zapytaniem wówczas „(q)” jest również zapytaniem. Pozwala to na dowolne używanie nawiasów a co za tym idzie, zmieniać priorytety operatorów. Jeżeli „q” jest zapytaniem, zaś n jest wyrażeniem tekstowym („test”, „zmienna”), wówczas „q as n” jest również zapytaniem, Operator as jest unarnym operatorem zmiany nazwy, wykorzystywany jest do definiowania pomocniczej nazwy. Jeżeli „q” jest zapytaniem, zaś n jest wyrażeniem tekstowym („test”, „zmienna”), wówczas „q group as n” jest również zapytaniem. Przykładowe zapytania zgodne ze zdefiniowaną składnią: 1356.12 ‘Warszawa’ -2 8*14 nazwisko = ‘Kowalski’ Osoba where (nazwisko = ‘Kowalski’) (Osoba where (nazwisko = ‘Kowalski’)).(1.3*Zarobek) FOR ALL Osoba HOLDS (Wiek>50) (2+2)*3 ((Osoba as p) DepJoin (p.pracujeW.Dzial as d)).(p.nazwisko, d.nazwa) Rysunek podsumowujący składnie zdefiniowaną w języku zapytań dla XML zapytanie ::= wyrażenie tekstowe zapytanie ::= wyrażenie liczbowe zapytanie ::= nazwa węzła zapytanie ::= ellipse nazwa węzła | $nazwa węzła zapytanie ::= opUnary zapytanie opUnary oznacza algebraiczny unarny operator zapytanie ::= zapytanie opBinarny zapytanie opBinary oznacza algebraiczny binarny operator zapytanie ::= zapytanie opNieAlg zapytanie opNieAlg oznacza operator nie-algebraiczny opNieAlg ::= where |.| DepJoin zapytanie ::= FOR ANY zapytanie HOLDS zapytanie zapytanie ::= FOR ALL zapytanie HOLDS zapytanie zapytanie ::= (zapytanie) zapytanie ::= zapytanie as wyrażanie tekstowe zapytanie ::= zapytanie group as wyrażanie tekstowe Strona 46 Język zapytań dla XML oparty na podejściu stosowym 8.2. Stos rezultatów Ponieważ podczas ewaluacji zapytania mogą być potrzebne wyniki cząstkowe, potrzebna jest struktura, na której przechowywać będziemy zarówno wyniki cząstkowe jak i rezultat całego zapytania. W większości języków zapytań funkcję tą pełni stos arytmetyczny, w naszym przypadku konieczne jest nieznaczna modyfikacja stosu arytmetycznego, ponieważ na stosie rezultatów znajdować się będą tablice węzłów będące rezultatami zapytań. Wszystkie operacje na stosie rezultatów odbywają się tylko na elementach znajdujących się na wierzchołku stosu ( w zależności od operatora mogą to być jeden lub dwa elementy).Elementy stosu znajdujące się poniżej staną się widoczne dopiero w momencie usunięcia odpowiedniej liczby elementów z wierzchołka stosu rezultatów. 8.3. Semantyka języka zapytań dla XML Semantyka (angielskie semantics), znaczenie przyporządkowane symbolom i napisom języka. W przypadku języka programowania jego semantyka jest wyznaczana przez faktyczne zachowanie się sprzętu lub innych składowych systemu komputerowego, wynikające z interpretacji jednostek programowych (instrukcje, deklaracje). Bliskie pytaniu o semantykę jest pytanie: „co to (naprawdę) powoduje?”. ([14]) Semantyka stworzonego przez nas języka zapytań dla XML zdefiniowana jest poprzez metody implementujące operatory. Operatory te wywoływane są przez rekurencyjną metodę, executeQuery, która dokonuje odpowiednich wywołań. Ponieważ w naszej implementacji języka zapytań nie implementujemy operatorów zmieniających stan, zachowane są następujące założenia: Podczas ewaluacji zapytania nie zmienia się stan składu obiektów Podczas ewaluacji zapytania stan stosu środowisk może ulec zmianie, lecz po zakończeniu ewaluacji, będzie taki sam jak przed ewaluacją zapytania Podczas ewaluacji zapytania „q” nie zmienia się ta część stosu rezultatów, która istniała w momencie rozpoczęcia ewaluacji zapytania. W trakcie ewaluacji mogą być dodawane i usuwane elementy ze stosu rezultatów, lecz po zakończeniu ewaluacji zapytania, na stosie rezultatów będzie o jeden element więcej niż przed rozpoczęciem ewaluacji. Definicja semantyki będzie sterowana składnią, oznacza to, że metodę executeQuery będzie wspomagał analizator gramatyczny(w naszym przypadku LR(1) wygenerowany dla podanej składni), który dokona rozbioru zapytanie na podzapytanie wraz z operatorami łączącymi te podzapytania. Po wyliczeniu wyniku podzapytania, rezultat całego zapytania jest tworzony w oparciu o wyniki podzapytań. Po ewaluacji zapytania rezultat zostaje odłożony na stos rezultatów. W związku z tym powinien być on „konsumowany” przez operator języka lub interfejsu, dla którego zapytania było parametrem. Doskonałym przykładem takiego operatora jest operator delete lub update. Zapytaniem elementarnym w stworzonym przez nas języku, może być wyrażenie tekstowe, liczbowe lub też identyfikator obiektu znajdującego się w składzie. W takim przypadku procedura ewaluacji jest bardzo prosta. Jeżeli jest to wartość tekstowa lub liczbowa, jest ona po prostu wkładana na wierzchołek stosu rezultatów. W przypadku, gdy jest to identyfikator obiektu znajdującego się w składzie dokonywane jest wiązanie tej nazwy na stosie środowisk, a następnie wstawienie wyniku na wierzchołek stosu rezultatów. We wszystkich pozostałych przypadkach najpierw dokonywany jest rozbiór zapytania na jedno lub dwa podzapytania oraz operator. Następnie wyliczany jest rezultat podzapytań i łączony w rezultat całego zapytania zgodnie z operatorem. Proces ten jest z natury rekurencyjny, który kończy się w momencie rozłożenia zapytania na zapytania elementarne. Operatory łączące podzapytania możemy podzielić na algebraiczne i nie-algebraiczne. Podstawowa różnica między operatorami algebraicznymi i nie-algebraicznymi to ich stosunek do stosu środowisk. Strona 47 Język zapytań dla XML oparty na podejściu stosowym Operatory algebraiczne do swojego działania nie potrzebują stosu środowisk, używają tylko i wyłącznie stosu rezultatów, natomiast operatory nie-algebraiczne oprócz korzystania ze stosu rezultatów, odwołują się i wykonują operacje na stosie środowisk. Przykładowa baza danych, na której będziemy pokazywać działania przykładowych operatorów wygląda następująco: <baza> <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Bylejaki</Nazwisko> <Pensja>1500</Pensja> <Premia>0</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>1700</Pensja> <Premia>0</Premia> </Pracownik> <Dzial> <Nazwa>Produkcja</Nazwa> </Dzial> </baza> 8.3.1 Operatory algebraiczne Podstawową cechą operatorów algebraicznych jest fakt, ze kolejność ewaluacji argumentów nie ma wpływu na wynik. Stanowi to zasadniczą różnicę w stosunku do operatorów nie-algebraicznych. Ewaluacja zapytanie z operatorem algebraicznym dla operatora unarnego polega na ewaluacji podzapytania pobrania wyniku, a następnie wstawienia na stos rezultatów rezultatu działania operatora na wynik ewaluacji podzapytania. Dla algebraicznych operatorów binarnych jedyną różnicą jest konieczność ewaluacji dwóch podzapytań. Ewaluację operatów algebraicznych można zapisać w następujący sposób: wynik(op(q1)) = op(wynik(q1)) – dla operatora unarnego wynik(q1 op q2) = wynik(q1) op wynik(q2) Strona 48 Język zapytań dla XML oparty na podejściu stosowym Możemy wyodrębnić kilka charakterystycznych zaimplementowanych w naszym języku: grup operatorów algebraicznych Operatory dotyczące liczb całkowitych i rzeczywistych: „+”„–”, „*”, „/” Zapytanie: 2+3*12-10/2 Wynik: 33 Zapytanie: baza.Pracownik.((Pensja.TextValue)+(Premia.TextValue)) Wynik: 3000.0 1500.0 1900.0 Operatory działające na łańcuchach tekstowych: operator konkatenacji „&” Zapytanie: baza.Pracownik.((Nazwisko.TextValue)& (' ' & (Imie.TextValue))) Wynik: 'Kowalski Jan' 'Bylejaki Kamil' 'Kowalski Kamil' Operatory logiczne: AND, OR, ! Zapytanie: baza.Pracownik where ((Pensja.TextValue=2000) (Nazwisko.TextValue!='Kowalski')) OR Wynik: <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Bylejaki</Nazwisko> <Pensja>1500</Pensja> <Premia>0</Premia> </Pracownik> Generyczny operator porównania na równość, oznaczany „=”, oraz operator odwrotny „!=”. W naszej implementacji operatory te zdefiniowane są dla liczb, wyrażeń tekstowych, identyfikatorów obiektów (poprzez referencje). Np. Zapytanie: 2=2 Wynik: ‘true’ Zapytanie: baza.Pracownik where (Nazwisko.TextValue='Kowalski') Wynik: <Pracownik> <Imie>Jan</Imie> Strona 49 Język zapytań dla XML oparty na podejściu stosowym <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>1700</Pensja> <Premia>200</Premia> </Pracownik> Operatory porównywania nie na równość – działają zarówno na liczbach jak i wartościach tekstowych: <.>,>=.<= Zapytanie: 2>=2 Wynik: ‘true’ Zapytanie: ‘Ala' > 'Beaty' Wynik: ‘false’ Zapytanie: baza.Pracownik where (Pensja.TextValue>1800) Wynik: <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> Funkcje działające na kolekcjach. Są to takie operatory jak count (zliczający liczbę elementów w kolekcji), sum (sumujące liczby znajdujące się w kolekcji), exists (sprawdza czy kolekcja jest niepusta). Zapytanie: count(baza.Pracownik.Pensja.TextValue) Wynik: 3 Zapytanie: sum(baza.Pracownik.Pensja.TextValue) Wynik: 5200 8.3.2 Operator definiowania pomocniczej nazwy Operatory definiowania pomocniczej nazwy pojawiły się w relacyjnych językach zapytań, gdzie noszą nazwę „zmiennych”. Po zdefiniowaniu mogą być używane w warunkach selekcji, złączeń itp.. Operator definiowania pomocniczej nazwy jest operatorem unarnym parametryzowanym nazwą. Operator ten jest praktycznie niezbędny do wyrażenia niektórych zapytań. W naszej implementacji nosi on nazwę „as”. Jeżeli x jest zapytaniem zwracającym pewną kolekcję to „x as n” zwróci kolekcję etykietowaną poprzez nazwę „n” np. Strona 50 Język zapytań dla XML oparty na podejściu stosowym Zapytanie: baza.Pracownik zwróci wynik: <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Bylejaki</Nazwisko> <Pensja>1500</Pensja> <Premia>0</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>1700</Pensja> <Premia>200</Premia> </Pracownik> zaś zapytanie: baza.Pracownik as prac zwróci: <prac> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </prac> <prac> <Imie>Kamil</Imie> <Nazwisko>Bylejaki</Nazwisko> <Pensja>1500</Pensja> <Premia>0</Premia> </prac> <prac> <Imie>Kamil</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>1700</Pensja> <Premia>200</Premia> </prac> Strona 51 Język zapytań dla XML oparty na podejściu stosowym Jak widać została zmieniona nazwa węzła – efekt ten jest niestety wynikiem specyfiki tego języka zapytań, spowodowanej użyciem XML jako bazy danych. Operator „as” może być dowolnie zagnieżdżany w związku z tym zapytanie (baza.Pracownik as prac) as pracus jest jak najbardziej poprawne. Operator „as” zdecydowanie ułatwia tworzenie niektórych zapytań, np. w momencie, gdy potrzebujemy w zapytaniu dwukrotnie odnieść się do tej samej kolekcji obiektów np.: Zapytanie zwracające pracowników zarabiających więcej od przynajmniej jednego pracownika: (((baza.Pracownik as p1),(baza.Pracownik as p2)) where ((p1.Pensja.TextValue) > (p2.Pensja.TextValue))).p1.Pensja.TextValue Zwróci wynik: 2000 2000 1700 Czasami może pojawić się potrzeba grupowania obiektów, do tego celu służy operator „group as”. Operator ten opakowuje kolekcję zwróconą przez podzapytania w nowy węzeł o nazwie podanej jako parametr operatora. Operator ten jest użyteczny w przypadku, gdy chcemy nazwać cały wynik zapytania a nie elementy wyniku tego zapytania. Przykładowe zapytanie: baza.Pracownik group as Pracownicy Zwraca następujący wynik: <Pracownicy> <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Bylejaki</Nazwisko> <Pensja>1500</Pensja> <Premia>0</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>1700</Pensja> <Premia>200</Premia> </Pracownik> <Pracownicy> 8.3.3 Operator budowania struktury Bardzo często zachodzi potrzeba stworzenia struktury. Operator „,” zaimplementowany w języku zapytań, dla XML, swoim zachowaniem bardzo przypomina, operator o tej samej nazwie („,”). Działa on praktycznie jak iloczyn kartezjański, tylko z jednym małym wyjątkiem, mianowicie, jeżeli Strona 52 Język zapytań dla XML oparty na podejściu stosowym jeden z elementów jest pusty, jest on podczas wyliczania iloczynu pomijany. Wynikiem działania operatora jest kolekcja węzłów o nazwie „StructNode”, z których każdy zawiera cząstkowy wynik tak zdefiniowanego iloczynu kartezjańskiego. Przykładowe zapytanie wykorzystujące operator „,”: ((baza.Pracownik where (Pensja.TextValue>1800)), (baza.Dzial)) Wynikiem tego zapytania jest: <StructNode> <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Dzial> <Nazwa>Produkcja</Nazwa> </Dzial> </StructNode> 8.3.4 Operatory nie-algebraiczne Operatory nie-algebraiczne stanowią istotę podejścia stosowego. Do tej kategorii operatorów należą operatory selekcji (where), operator kropki, operator zależnego złączenia oraz kwantyfikatory. Wszystkie wyżej wymienione operatory są operatorami binarnymi. Mimo znacznego podobieństwa (syntaktycznego) do operatorów algebraicznych, semantyka operatów nie-algebraicznych nie daje się łatwo sprowadzić do algebry. Podstawową różnicą pomiędzy operatorami algebraicznymi i niealgebraicznymi jest to, iż operatory nie-algebraiczne mogą wykonywać operację na stosie środowisk (jest on niezbędny dla działania operatorów nie-algebraicznych). Stan stosu środowisk jest zmienny w czasie wykonywania operatora, lecz po zakończeniu działania, jest taki sam jak przed rozpoczęciem ewaluacji operatora (jeżeli operator nie ma działań ubocznych). Poniżej podany jest nieformalny opis ewaluacji zapytania „q1 opNieAlg q2”: 1. Dokonaj ewaluacji zapytania q1. Wynikiem jest kolekcja węzłów. 2. Dla każdego węzła „e” należącego do wyniku q1 wykonaj: a. Pobierz wnętrze węzła „e” – wynikiem jest zbiór binderów „z” b. Stwórz nową sekcję na wierzchołku stosu środowisk i wstaw tam „z”. c. Dokonaj ewaluacji zapytania q2. d. Oblicz wynik pośredni dla elementu e, poprzez połączenie e z wynikiem ewaluacji q2. Funkcja łącząca zależy od operatora. e. Usuń nowo wstawioną sekcję ze stosu środowisk 3. Zsumuj wszystkie wyniki pośrednia. Funkcja sumująca zależna jest od rodzaju operatora. Operatory nie-algebraiczne różnią się między sobą wyłącznie sposobem obliczania wyniku pośredniego, oraz sposobem sumowania wyników pośrednich. Poniżej podane są definicje operatorów wraz z opisem: Strona 53 Język zapytań dla XML oparty na podejściu stosowym Operator where Operator where jest operatorem selekcji. Odpowiada on operatorom selekcji znanym, z SQL, czy OQL. Składnia: q1 where q2 Sposób obliczania wyniku pośredniego: dla danego elementu e należącego do wyniku q1 zwraca jednoelementową kolekcją zawierającą element e w przypadku, gdy dla tego e ewaluacja podzapytania q2 zwróciła ‘true’, w przeciwnym wypadku zwraca pustą kolekcję. Sumowanie wyników pośrednich: sumuj (mnogościowo) wszystkie wyniki pośrednie. Przykładowe zapytanie: baza.Pracownik where (Pensja.TextValue >= 1700) Wynikiem zapytanie jest: <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>1700</Pensja> <Premia>200</Premia> </Pracownik> Operator kropki Operator „.” jest to operator projekcji, nawigacji Składnia: q1.q2 Sposób obliczania wyniku pośredniego: pomija e, zwraca wynik ewaluacji q2. Sumowanie wyników pośrednich: sumuj (mnogościowo) wszystkie wyniki pośrednie. Przykładowe zapytanie: baza.Pracownik.Pensja Wynikiem zapytanie jest: <Pensja>2000</Pensja> <Pensja>1500</Pensja> <Pensja>1700</Pensja> Operator zależnego złączenia Składnia: q1 DepJoin q2 Sposób obliczania wyniku pośredniego: Dla każdego elementu e2 będącego wynikiem ewaluacji q2, tworzy strukturę łącząc e z e2. Wynikiem pośrednim jest kolekcja tak stworzonych struktur. Sumowanie wyników pośrednich: sumuj (mnogościowo) wszystkie wyniki pośrednie. Strona 54 Język zapytań dla XML oparty na podejściu stosowym Przykładowe zapytanie: baza.Dzial DepJoin (baza.Pracownik) Wynikiem zapytanie jest: <StructNode> <Dzial> <Nazwa>Produkcja</Nazwa> </Dzial> <Pracownik> <Imie>Jan</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>2000</Pensja> <Premia>1000</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Bylejaki</Nazwisko> <Pensja>1500</Pensja> <Premia>0</Premia> </Pracownik> <Pracownik> <Imie>Kamil</Imie> <Nazwisko>Kowalski</Nazwisko> <Pensja>1700</Pensja> <Premia>200</Premia> </Pracownik> </StructNode> Kwantyfikator egzystencjalny Składnia: FOR ANY q1 HOLDS q2 Sposób obliczania wyniku pośredniego: pomija e, zwraca wynik ewaluacji q2. Sumowanie wyników pośrednich: zwraca ‘true’, jeżeli chociaż jeden wynik pośredni zwrócony przez q2 jest ‘true’, w przeciwnym przypadku zwraca ‘false’. Przykładowe zapytanie: FOR ANY (baza.Pracownik) HOLDS (Pensja.TextValue>1600) Wynikiem zapytanie jest: ‘true’ Kwantyfikator uniwersalny Składnia: FOR ALL q1 HOLDS q2 Strona 55 Język zapytań dla XML oparty na podejściu stosowym Sposób obliczania wyniku pośredniego: pomija e, zwraca wynik ewaluacji q2. Sumowanie wyników pośrednich: zwraca ‘false’, jeżeli chociaż jeden wynik pośredni zwrócony przez q2 jest ‘false’, w przeciwnym przypadku zwraca ‘true’. Przykładowe zapytanie: FOR ALL (baza.Pracownik) HOLDS (Pensja.TextValue>1600) Wynikiem zapytanie jest: ‘false’ 8.3.5 Operacje ellipse i $ Operacja ellipse Składnia operacji ellipse jest następująca: ellipse nazwa gdzie nazwa jest nazwą obiektu istniejącego w składzie danych. Wynikiem działania operacji ellipse jest kolekcja zawierająca wszystkie węzły o danej nazwie, niezależnie od miejsca w strukturze XML, w której się oryginalnie znajdowały. Przykładowe zapytanie: ellipse Pensja Wynikiem zapytania jest następująca kolekcja: <Pensja>2000</Pensja> <Pensja>1500</Pensja> <Pensja>1700</Pensja> Operacja $ Użycie operacji $ przed nazwą obiektu, określa, że wiązania danej nazwy ma nastąpić tylko i wyłącznie na wierzchołku stosu środowisk (stos środowisk nie jest przeszukiwany w celu znalezienia bindera o danej nazwie). Operacja ta jest niezmiernie przydatna w przypadku, gdy mamy do czynienia z odwołaniem do nazwy, która nie istnieje w danym elemencie węzła, ale istnieje już na stosie środowisk (np. gdy w elemencie nadrzędnym istnieje atrybut o takiej nazwie jaką wyszukujemy). Ponieważ podejście XML, jeżeli mamy wartość zerową (pustą), to węzeł o danej nazwie nie występuje w danym elemencie. W związku, z tym wiązanie nazw w tym przypadku powinno być ograniczone tylko do wierzchołka stosu środowisk. 8.4. Linki i sposób ich użycia W celu zwiększenia możliwości języka zapytań wprowadzona została możliwość definiowania „linków” prowadzących do innych węzłów w ramach bazy danych (niekoniecznie do tego samego pliku). 8.4.1 Sposób wprowadzenia linków do bazy danych W celu wprowadzenia linka do bazy danych należy wykonać dwie czynności: Węzeł, do którego chcemy stworzyć link musi otrzymać atrybut id o unikalnej wartości w ramach bazy (jeśli jeszcze takiego atrybutu nie posiada) W węźle, w którym chcemy stworzyć link należy stworzyć węzeł potomny o dowolnej nazwie (będzie ona nazwą linka), mający atrybut pointer=”true” i wartość tekstową równą wartości atrybutu id, do którego link ma prowadzić. 8.4.2 Sposób wykorzystania linków w zapytaniach Strona 56 Język zapytań dla XML oparty na podejściu stosowym Linki w zapytaniu wykorzystuje się w ten sam sposób, jakby węzeł, do którego prowadzi link był zagnieżdżony w węźle stanowiącym link. Przykładowo, jeżeli fragment bazy danych wygląda następująco: <baza> <pracownik id=”AA121”> <nazwisko>Kowalski</nazwisko> <imie>Jan</imie> </pracownik> <zaklad> <nazwa>Duza Firma S.A.</nazwa> <prezes pointer=”true”>AA121</prezes> </zaklad> </baza> możemy sprawdzić, kto jest prezesem firmy Duza Firma S.A. w sposób następujący: (baza.zaklad where nazwa.TextValue=’Duza Firma S.A.’).prezes.pracownik otrzymując następujący wynik: <ResultSet> <pracownik id=”AA121”> <nazwisko>Kowalski</nazwisko> <imie>Jan</imie> </pracownik> </ResultSet> Należy przy tym pamiętać o tym, iż w celu prawidłowego zadania zapytania należy znać typ węzła, do którego prowadzi link. Jeśli w powyższym przykładzie zadalibyśmy zapytanie (zaklad where nazwa.TextValue=’Duza Firma S.A.’).prezes.osoba otrzymalibyśmy jako wynik zbiór pusty – link nie prowadzi do węzła typu osoba: <ResultSet> </ResultSet> Węzeł stanowiący link może zawierać inne, zagnieżdżone węzły, oraz mieć dodatkowe atrybuty, nie może jednak mieć w swojej wartości tekstowej informacji innych, niż id węzła do którego prowadzi link. Jeśli w wartości tekstowej węzła stanowiącego link będą dodatkowe dane, system wykonujący zapytania uzna je za część identyfikatora poszukiwanego obiektu – i nie znajdzie go (lub znajdzie niewłaściwy). Z tego samego powodu nie należy umieszczać w ramach jednego węzła stanowiącego link identyfikatorów dwóch różnych węzłów docelowych. Jeśli w ramach jednego węzła chcemy stworzyć kilka linków o tej samej nazwie, należy dla każdego linka stworzyć osobny węzeł stanowiący link, tak jak w poniższym przykładzie: </pracownik> <zaklad> <nazwa>Duza Firma S.A.</nazwa> <prezes pointer=”true”>AA121</prezes> <wiceprezes pointer=”true”>AA122</prezes> <wiceprezes pointer=”true”>AA123</prezes> <wiceprezes pointer=”true”>AA124</prezes> </zaklad> 8.4.3 Nałożone ograniczenia System nakłada na użytkownika tylko jedno ograniczenie – identyfikatory węzłów w ramach bazy danych muszą być unikalne. Jeśli po dołączeniu do bazy kolejnego pliku XML warunek ten przestanie być spełniany, wszystkie linki przestaną funkcjonować – wyrażenia ścieżkowe takie jak Strona 57 Język zapytań dla XML oparty na podejściu stosowym podane w przykładach powyżej nie będą dawały oczekiwanych wyników. Nadal możliwe będzie uzyskanie podobnych efektów poprzez zapytania używające równości atrybutów. Zalecamy również nie używanie w identyfikatorach znaków klasyfikowanych jako „białe spacje” – spacji, tabulatorów itd. Węzły stanowiące link również powinny nie zawierać takich znaków – sposób ich obsługi przez używany parser XML może być nie do końca zgodny z oczekiwanym przez użytkownika. 8.4.4 Wady i zalety przyjętego systemu Przyjęty system realizacji linków charakteryzuje się następującymi wadami i zaletami: Wszystkie linki działają jednokierunkowo. Jedyna możliwością znalezienia węzłów stanowiących linki, jeśli znamy węzeł, do którego prowadzi link, jest zadanie zapytania wykorzystującego równość atrybutów i wartości tekstowych (tzn. id=węzeł.TextValue). Możliwe jest zrealizowanie odpowiednika asocjacji z atrybutami – węzeł stanowiący link może posiadać dodatkowe atrybuty i węzły potomne, które możemy wykorzystywać jako atrybuty związku. Oczywiście należy pamiętać o wspomnianej wyżej jednokierunkowości takiego związku. Należy ręcznie dbać o to, aby linki prowadziły do jakiegoś węzła. Brak jest automatycznych mechanizmów usuwania „wiszących” linków. Należy dbać o to, aby identyfikatory węzłów nie powtarzały się w ramach grupy plików wykorzystywanych jako baza danych. Możliwe byłoby wprowadzenie mechanizmów służących do automatycznej zmiany id pochodzących z różnych plików (np. przez prefiksowanie), utrudniałoby to jednak tworzenie linków pomiędzy różnymi plikami XML. 9. Omówienie API udostępnianego przez system Opracowany język zapytań może być wykorzystywany albo za pośrednictwem aplikacji klienckiej, albo poprzez udostępniane API. Poniżej znajduje się opis metod udostępnianych przez poszczególne obiekty, istotnych z punktu widzenia programisty chcącego wykorzystać opracowane klasy we własnej aplikacji: 9.1. Klasa edu.t2r.magisterka.QueryExecutor Klasa QueryExecutor jest główną klasą, implementującą wszystkie operatory oraz większość mechanizmów języka zapytań. Do większości zastosowań wystarcza użycie metod udostępnianych przez tą klasę. 9.1.1 public QueryExecutor() Domyślny, bezparametrowy konstruktor. 9.1.2 public org.w3c.dom.Document mountDatabase(String databaseName) Metoda służy do załadowania dokumentu XML pełniącego rolę bazy danych. Parametr databaseName służy do podania nazwy i ścieżki do dokumentu XML. Zwraca obiekt typu org.w3c.dom.Document (na wypadek gdyby potrzebny był programiście). Jeśli używany parser DOM nie wspiera operacji Traversal, podniesie wyjątek RuntimeException ze stosowną informacją. 9.1.3 public org.w3c.dom.Node evaluateQuery(String query) throws edu.t2r.magisterka.TypeMismatchException, Exception Metoda służy do ewaluacji zapytania. Parametr query służy do przekazania zapytania, zwrócony będzie obiekt typu org.w3c.dom.Node, zawierający węzeł typu ResultNode, „opakowujący” wynik zapytania. Metoda ta może zwrócić wyjątek edu.t2r.magisterka.TypeMismatchException informujący Strona 58 Język zapytań dla XML oparty na podejściu stosowym o wykryciu niezgodności typów podczas ewaluacji zapytania, lub też wyjątek typu Exception przekazany ze skanera (klasa edu.t2r.magisterka.Lexer) lub parsera (klasa edu.t2r.magisterka .parser), informujący o problemach powstałych podczas parsowania zapytania. Opis wyjątków zwracanych przez skaner i parser znajduje się w dokumentacji generatorów: skanerów (JFlex) i parserów (CUP). 9.1.4 public boolean relationsUsed() Metoda zwraca informacę o tym, czy włączona jest obsługa linków. 9.1.5 public Node createNode(String value) Metoda służy do stworzenia węzła typu TEXT_NODE o wartości zadanej w parametrze. 9.1.6 public Node createNode(String type, String value) Metoda ta służy do stworzenia węzła o nazwie zadanej w parametrze type, mającego węzeł potomny typu TEXT_NODE o wartości zadanej w parametrze value. 9.1.7 public Node createNode(Node[] nodes, String type) Metoda ta służy do stworzenia węzła mającego węzły potomne zadane w parametrze nodes, o nazwie zadanej w parametrze type. 9.1.8 public Node createNode(String type, Node node1, Node node2) Metoda ta służy do stworzenia węzła mającego dwa węzły potomne zadane w parametrach node1 i node2, o nazwie zadanej w parametrze type. 9.1.9 public void clearResultsStack() Metoda ta służy do oczyszczenia stosu rezultatów w wypadku wystąpienia wyjątku. Powinna być użyta po wystąpieniu wyjątku, a przed zadaniem kolejnego zapytania (np. w klauzuli catch). 9.1.10 public ReferenceManager refManager Zmienna publiczna typu edu.t2r.magisterka.ReferenceManager przechowująca zarządzający referencjami. Opis metod udostępnianych przez obiekt znajduje się poniżej. obiekt 9.1.11 public LinkManager linkManager Zmienna publiczna typu edu.t2r.magisterka. LinkManager przechowująca obiekt zarządzający linkami. Opis metod udostępnianych przez obiekt znajduje się poniżej. 9.2. Klasa edu.t2r.magisterka.ReferenceManager Klasa ReferenceManager jest klasą, odpowiedzialną za przechowywanie informacji o referencjach węzłów oraz kopiach danego węzła (w związku ze specyfiką DOM konieczne jest tworzenie kopii węzłów „klonów”). Metody udostępniane przez daną klasę, pozwalają na dodawanie informacji zarówno o oryginałach jak i kopiach, jak również pobierania informacji dotyczących węzła. 9.2.1 public boolean isClone(Node node) Metoda zwraca informację czy dany węzeł jest „klonem” (kopią oryginalnego węzła). 9.2.2 public boolean isReal(Node node) Metoda zwraca informację czy dany węzeł jest węzłem oryginalnym. 9.2.3 public boolean addClone(Node realNode, Node cloneNode) Metoda służy do dodawania węzłów-kopii („klonów”), dla węzła oryginalnego. 9.2.4 public Node[] getClones(Node realNode) Strona 59 Język zapytań dla XML oparty na podejściu stosowym Metoda służy do pobierania węzłów-kopii dla podanego węzła. 9.2.5 public void addReal(Node realNode) Metoda służy do dodawania węzłów oryginalnych. 9.2.6 public Node getReal(Node cloneNode) Metoda służy do pobierania węzła oryginalnego (referencji) w stosunku do podanego węzła. 9.2.7 public void doCleanUp() Metoda służy do czyszczenia informacji o „klonach” (należy ją wykonać po lub przed ewaluacją zapytania). 9.3. Klasy klasa edu.t2r.magisterka.parser i edu.t2r.magisterka.Lexer Opisy metod udostępnianych przez te klasy i sposobów ich użycia znajdują się w dokumentacji generatorów: skanerów (JFlex) i parserów (CUP). Metody te mogą być użyteczne, jeśli aplikacja ma udostępniać użytkownikowi informacje związane z procesem parsowania zapytania (np. wskazywać błędy w zapytaniu). 9.4. Klasa edu.t2r.magisterka.LinkManager Klasa LinkManager używana jest do zarządzania informacją o węzłach, do których mogą być prowadzone linki (posiadających atrybut id). Metody tej klasy będą musiały być wykorzystywane przez programistę wykonującego aktualizacje bazy przy pomocy metod DOM, lub rozbudowującego system o możliwość wykonywania operacji aktualizacyjnych. 9.4.1 public LinkManager(QueryExecutor executor) Konstruktor, pobierający obiekt typu QueryExecutor, który będzie wykorzystywać tą instancję. 9.4.2 public Node[] getRelated(String foreignKey) Metoda zwraca jednoelementową tablicę węzłów, jeśli znajdzie węzeł odpowiadający identyfikatorowi zawartemu w parametrze, lub zero elementową, jeśli nie znajdzie takiego węzła. 9.4.3 public void addDestinationNode(String nodeValue, org.w3c.dom.Node destinationNode) throws Exception Metoda dodaje węzeł przekazany jako parametr drugi, z identyfikatorem przekazanym jako parametr pierwszy, do struktury danych przechowującej informacje o węzłach posiadających unikalne identyfikatory. Jeśli okaże się, że nastąpiła próba zdublowania identyfikatora (inny węzeł o tym identyfikatorze istniał w bazie wcześniej), podniesiony zostanie wyjątek z odpowiednią informacją. W takim przypadku metoda ta wyłączy również stosowanie relacji w bazie danych. Metoda ta powinna być używana przez programistów dodających nowe węzły do bazy danych. 9.4.4 Wskazane zmiany klasy przy rozszerzaniu funkcjonalności języka o możliwość wykonywania operacji aktualizacyjnych. Należy wprowadzić metody umożliwiające zmianę identyfikatora, pod jakim zapisany jest obiekt, usuwanie identyfikatorów oraz ponowną kontrolę unikalności identyfikatorów w bazie (w celu ewentualnego włączenia relacji). Takich metod będzie również potrzebował programista wykonujący aktualizacje bazy przy pomocy metod DOM. Strona 60 Język zapytań dla XML oparty na podejściu stosowym 9.5. Metody służące do operacji na węzłach XML Co prawda w obecnie zaimplementowanej wersji język zapytań nie przewiduje operacji aktualizacyjnych (takich jak wstawianie, usuwanie lub modyfikacja węzłów), można jednak wykonywać takie operacje przy pomocy metod udostępnianych przez interfejs DOM. Metody te opisane są w specyfikacji interfejsu DOM na stronach W3C, oraz w specyfikacjach API parserów. Ponieważ, po zaimplementowaniu operatorów aktualizacyjnych, może być również wymagane zapisywanie zmodyfikowanych węzłów na dysk, warto dodać, iż specyfikacja interfejsu DOM zawiera klasę XMLSerializer odpowiedzialną za zapisywanie struktury XML na dysk (lub inne wyjście). Uwaga – aby prawidłowo posłużyć się operacjami aktualizacyjnymi należy najpierw odzyskać referencje do oryginalnego węzła na podstawie kopii uzyskanej w wyniku wykonania zapytania. Sposób odzyskania referencji omówiony jest w punkcie 2.2 tego rozdziału. Przy modyfikowaniu atrybutu id węzłów (niezalecane w obecnej wersji), lub też przy dodawaniu tego atrybutu do istniejących/nowych węzłów należy również używać metod opisanych w punkcie 2.4 tego rozdziału. Nie użycie tych metod uniemożliwi budowę prawidłowo działających linków do węzłów. Strona 61 Język zapytań dla XML oparty na podejściu stosowym V. Omówienie implementacji Rozdział ten przedstawia implementację języka zapytań. Jego lektura może pomóc w lepszym zrozumieniu działania języka, jak również jest istotna dla osób chcących rozbudować lub zmodyfikować prototypową implementację. 10. Rozwiązania implementacyjne – struktury danych Poniżej znajduje się opis struktur danych wraz z wyjaśnieniem celowości użytych rozwiązań. 10.1.Skład obiektów W związku z tym, że wykorzystujemy standard DOM do parsowania dokumentów XML, oraz faktem, iż założeniem pracy było obsługiwanie tylko średniej wielkości dokumentów XML, do przechowywanie elementów XML używamy standardowego dokumentu XML wytworzonego podczas parsowania dokumentu XML przez parser XML. Wadą takiego rozwiązania jest stosunkowo wysokie, zużycie pamięci, aczkolwiek przy dzisiejszych pojemnościach pamięci, dokumenty średniej wielkości powinny bez problemów zmieścić się w pamięci współczesnego komputera. 10.2.Stos środowisk i rezultatów Ponieważ podejście stosowe zakłada istnienie stosu środowisk konieczna było stworzenia tego typu stosu w naszej implementacji języka zapytań. Zgodnie z założeniami podejścia stosowego dla języków zapytań podstawowe założenia stosu środowisk to ([3]): Traktowanie w jednakowy sposób kolekcji i danych indywidualnych. Stos nie będzie zawierał wartości zmiennych, obiektów. Spowodowane jest to faktem, iż w zakładanym podejściu odwołania do tego samego obiektu, mogą pojawiać się w wielu miejscach stosu. Na stosie będą przechowywane tylko zbiory „binderów”. Stos będzie podzielony na sekcje zawierające pewne informacje o środowisku wykonania. Na dole stosu znajdować się będą sekcje globalne. Sekcje globalne to: baza danych, zmienne środowiskowe systemu komputerowego, zmienne globalne, itp. Stos będzie w jednorodny sposób traktował zarówno dane ulotne jak i trwałe (znajdujące się w bazie danych) W naszej implementacji każda sekcja składa się z tablicy binderów, które to jako jedyna mogą znajdować się na stosie środowisk. Na samym dole stosu znajduje się sekcja bazy danych. Nie uznaliśmy za konieczne wprowadzanie sekcji ze zmiennymi środowiska komputerowego, ani sekcji zez zmiennymi globalnymi. Dodanie takich sekcji jest relatywnie proste i nie powinno sprawić większego problemu. W naszej implementacji sekcja bazy danych zawiera bindery z referencjami wszystkich węzłów, od których możemy rozpocząć zapytania (ponieważ każdy plik XML musi mieć jeden węzeł główny, dla każdego wczytanego pliku XML jest to jeden element). Dodatkowo w sekcji bazy danych znajdują się bindery z referencjami do wszystkich węzłów (nietekstowych), nazwy tych binderów rozpoczynają się od „ellipse ”. Umożliwia to wykonywanie zapytań eliptycznych, które rozpoczynają się od „ellipse ”. Zapytanie eliptyczne w naszej implementacji zwraca wszystkie węzły o nazwie zadanej po wyrażeniu „ellipse ”. Takie podejście cechuje się prostotą implementacji, a ponieważ nazwy węzłów w XML nie mogą zawierać spacji, nie wystąpi sytuacja, w której nazwa Strona 62 Język zapytań dla XML oparty na podejściu stosowym węzła pokryje się z nazwą bindera używanego do wyrażeń eliptycznych. W naszej implementacji dopuściliśmy następujące operacje na stosie środowisk: isEmpty – sprawdzenie czy stos jest pusty (nie zawiera żadnej sekcji). peek – pobiera tablicę binderów znajdującą się na wierzchołku stosu (null jeżeli stos jest pusty) push(binder) - dodaje binder do sekcji znajdującej się na wierzchołku stosu. Jeżeli binder o danej nazwie już istnieje w danej sekcji nie wykonywana jest żadna operacja. pushAndMerge(binder) – do sekcji znajdującej się na wierzchołku stosu. Jeżeli binder o danej nazwie już istnieje w danej sekcji do binder dodawana jest kolejna referencja powiązana z tym binderem. search(nazwa bindera).- wyszukuje binder o danej nazwie, rozpoczynając od wierzchołka stosu. Jeżeli sekcja nie zawiera bindera o danej nazwie, przeszukiwana jest kolejna sekcja znajdująca się bezpośrednio pod aktualnie przeglądaną sekcją. Jeżeli żadna sekcja nie zawiera bindera o danej nazwie zwracany jest null. raiseStack – tworzy nową sekcję na wierzchołku stosu. lowerStack – usuwa sekcję z wierzchołka stosu, zwracając tablicę binderów z usuwanej sekcji. getStackHeight – zwraca bieżącą wysokość stosu. Równie istotny jak stos środowisk jest stos rezultatów. Na stosie tym odkładana są wyniki działania operatorów. Także argumenty operatorów pobierane są ze stosu rezultatów. W naszej implementacji na stosie rezultatów odkładane są tablice węzłów (ang. Notes). Węzły znajdujące się w tablicach zgodne są ze standardem DOM.. Jedyne operacje wykonywane na stosie rezultatów to pobranie i wstawienie tablicy węzłów. Z tego powodu jako stosu rezultatów użyliśmy standardowego stosu dostarczanego wraz z językiem Java. 10.3.Bindery Zgodnie z założeniami podejścia stosowego dla języków zapytań opracowanego przez Kazimierza Subietę na stosie środowisk, muszą znajdować się bindery. Bindery używane są do wiązania nazw występujących w zapytaniu na byty czasu wykonania (np. referencje, stałe itp.). Oryginalnie binder był parą <n,x>, gdzie „n” było zewnętrzną nazwą (np. zmiennej, stałej, obiektu itp.), a „x” bytem czasu wykonania (zwykle byłą to referencja do obiektu). W naszej implementacji binder jest to para <n,k>, gdzie „n” jest również zewnętrzną nazwą, lecz „k” jest zbiorem węzłów w rozumieniu DOM odpowiadających danej nazwie. Różnica wynikająca z tego jest taka, iż w naszym przypadku w danej sekcji stosu środowisk może znajdować się najwyżej jeden binder o danej nazwie, oraz w naszym przypadku bindery przechowują referencje do węzłów DOM. Operacje określone dla bindera to: Tworzenie bindera o danej nazwie Dodawanie nowych referencji węzłów Pobieranie referencji węzłów Pobieranie nazwy bindera. 10.4.Zarządzanie referencjami Podczas tworzenia języka zapytań, okazało się, że z powodu przyjętych założeń, co do składu obiektów, występują problemy z zachowaniem identyczności referencji. Strona 63 Język zapytań dla XML oparty na podejściu stosowym 10.4.1 Wpływ DOM na referencje. Podczas ewaluacji zapytania często dochodzi do sytuacji, gdy musimy przepisać węzeł z jednego dokumentu do innego. Operacja taka zachodzi często, ponieważ stos wyników w naszym przypadku zawiera tylko i wyłącznie węzły w rozumieniu DOM. Operacje takie jak zmiana, nazwy, tworzenie węzła opakowującego tworzonego np. podczas budowania struktur wymaga przepisania węzła z jednego dokumentu do innego. Optymalnym rozwiązaniem w tym przypadku byłoby przepisanie referencji do elementu. Niestety standard DOM nie zezwala na takie przenoszenie węzła z dokumentu do dokumentu, ponieważ każdy węzeł ma przypisany do siebie dokument, do którego należy. W związku z tym, aby przenieść element do innego dokumentu należy zaimportować węzeł. Niestety operacja to powoduje stworzenie nowego węzła, o tej samej strukturze, lecz zupełnie innej referencji. Powoduje to, że porównywanie takich węzłów referencyjnie nie ma większego sensu, co więcej w przypadku dobudowania do aktualnego systemu operacji imperatywnych (np. aktualizacji, usuwania) operacje takie mogą mieć bardzo ciekawe efekty (np. uaktualnienie tylko części węzłów, które należałoby uaktualnić). 10.4.2 Dlaczego zarządzanie referencjami jest potrzebne. Ponieważ chcieliśmy w naszym systemie zaimplementować porównywanie elementów poprzez referencje a nie porównywanie struktury, konieczne okazało się zaimplementowanie dodatkowych struktur danych pozwalających na pobieranie referencji oryginalnego obiektu dla obiektu zaimportowanego. Dodatkowo posiadając możliwość zdobycia referencji oryginału, a także referencji wszystkich klonów oryginału, możliwe jest zaimplementowanie operacji imperatywnych dokonywanych na obiektach. 10.4.3 Opis zaimplementowanego rozwiązania Rozwiązanie, które przyjęliśmy opiera się na dwóch tablicach pomocniczych struktur składających się z numerycznego identyfikatora węzła oraz referencji do danego węzła. Jedna z tablic zawiera węzły „oryginalne” tzn. takie, które tworzone są w momencie dodawania nowego pliku XML do bazy danych. Są to wszystkie węzły, atrybuty znajdujące się w danym pliku XML. Ponadto, ponieważ węzły XML nie muszą posiadać unikalnego identyfikatora, każdemu z elementów dodawanych do tablicy „oryginałów” nadawany jest unikalny numer. Numer ten jest jednakowy podczas całego czasu działania programu, aczkolwiek może być różny pomiędzy kolejnymi wywołaniami programu. Kolejna tablica „klonów” zawiera struktury składające się z identyfikatora oryginału (liczba nadawana podczas dodawania do tablicy „oryginałów”) oraz referencji do węzłaklonu. Wpisy do tablicy „klonów” dodawane są w momencie zaimportowaniu węzła. Ponieważ możliwe jest importowanie węzła, który jest „klonem” w związku z tym przed właściwym wstawieniem do tablicy, pobierany jest węzeł „oryginalny” dla węzła importowanego. Takie podejście pozwala na bardzo łatwe przejście z modelu gdzie nie były zapamiętywane referencje do modelu je obsługującego. W celu łatwiejszego tworzenia i utrzymania kodu, obsługa referencji do węzłów znajduje się w oddzielnej klasie udostępniającej zestaw metod, do dodawania i pobierania referencji do węzłów. Klasa ta udostępnia następujące metody: isClone(Node) – sprawdza czy węzeł podany jako parametr jest „klonem” (czy wektor klonów zawiera element od danej referencji) isReal(Node) – sprawdza czy węzeł podany jako parametr jest „oryginałem” (czy wektor oryginałów zawiera element od danej referencji) addClone(oryginal, klon) – dodaje nowy element do wektora „klonów”, zapisując referencje klonu i identyfikator oryginału do wektora „klonów". getClones(node) – zwraca tablicę węzłów, będącymi klonami węzła podanego jako parametr, lub też węzła będącego oryginalnym w stosunku do węzła podanego jako parametr (jeżeli podany węzeł jest „klonem”). Wykonanie tej metody polega na wyszukaniu węzła oryginalnego w stosunku do parametru (może to być ten sam węzeł) Strona 64 Język zapytań dla XML oparty na podejściu stosowym a następnie przeszukanie wektora „klonów” w celu znalezienia wszystkich elementów będących „klonami” węzła oryginalnego. W związku z tym możliwe jest, istnienie w wyniku metody węzła podanego jako parametr. getReal(node) – zwraca węzeł „oryginalny” w stosunku do węzła pobranego jako parametr. Zwraca „null”, jeżeli węzeł podany jako parametr nie występuje ani w tablicy „oryginałów” ani w tablicy „klonów”. Jeżeli węzeł będący parametrem jest już węzłem „oryginalnym” zwracany jest ten węzeł. doCleanUp – powoduje wyczyszczenie tablicy „klonów”. Metoda ta wywoływana jest po zakończeniu ewaluacji zapytania. addReal(node) – dodaje węzeł do wektora „oryginałów” nadając mu jednocześnie unikalny identyfikator. 11. Rozwiązania implementacyjne – implementacja operatorów algebraicznych Operatory algebraiczne są operatorami niepodnoszącymi stosu środowisk. Operują one jedynie na stosie rezultatów, używając (w zależności od operatora) jednego lub dwóch górnych elementów tego stosu, i umieszczając wynik na szczycie stosu rezultatów. Uwaga – na rysunkach ilustrujących działanie operatorów algebraicznych nie została pokazana zawartość stosu środowisk – z punktu widzenia tych operatorów jest ona nieistotna. 11.1.Operatory arytmetyczne Operatory arytmetyczne realizują podstawowe operacje arytmetyczne. Ogólnie przyjęte zasady dotyczące kolejności działań (najsilniej wiąże „unarny -” potem mnożenie i dzielenie, następnie dodawanie i odejmowanie) są przestrzegane. 11.1.1 Operatory „+”, „–„, „*”, „/” Ilość argumentów: 2 Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów i wykonuje na nich odpowiednie działanie arytmetyczne, jeżeli oba elementy mogą być skonwertowane na typ liczbowy. W przeciwnym wypadku podnoszony jest wyjątek TypeMismatchException. Wynik jest odkładany na stosie rezultatów. Strona 65 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Stos rezultatów Przed 12 12 Stos środowiskowy Stos rezultatów Po 144 Rysunek 5 - 1 przykład działania operatora "*" Uwagi: Wyjątek rzucany przy próbie dodania wartości innych niż typy liczbowe wynika z braku koncepcji, co konkretnie miałoby być wynikiem takiego działania. 11.1.2 Operator „– unarny” Ilość argumentów: 1 Zachowanie: Operator pobiera górny element ze stosu rezultatów. Jeśli element może być skonwertowany na typ liczbowy, element zostaje odjęty od 0 (zamiana znaku), a następnie wynik zostaje odłożony na stos rezultatów. Stos środowiskowy Stos rezultatów Przed 12 Stos środowiskowy Stos rezultatów Po -12 Rysunek 5 - 2 przykład działania operatora "unarny -" Uwagi: Wyjątek rzucany przy próbie zanegowania wartości innych niż typy liczbowe wynika z braku koncepcji, co konkretnie miałoby być wynikiem takiego działania. 11.2.Operatory działające na łańcuchach tekstowych 11.2.1 Operator „&” Ilość argumentów: 2 Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów. Oba są traktowane jako łańcuchy tekstowe, zostają skonkatenowane, a wynik zostaje odłożony na stos rezultatów. Jeśli przynajmniej jeden z elementów nie jest wartością Strona 66 Język zapytań dla XML oparty na podejściu stosowym atomową (jest węzłem o typie innym niż TEXT_NODE CDATA_SECTION_NODE), konwersja na łańcuch tekstowy niemożliwa i podnoszony jest wyjątek TypeMismatchException. Stos środowiskowy Przed lub jest Stos rezultatów ‘cd’ ‘ab’ Stos środowiskowy Stos rezultatów Po ‘abcd’ Rysunek 5 - 3 przykład działania operatora "&" Uwagi: Wyjątek rzucany przy próbie dodania wartości innych niż typy atomowe wynika z braku koncepcji, co konkretnie miałoby być wynikiem takiej „konkatenacji”. 11.3.Operatory logiczne 11.3.1 Operatory „AND”, „OR” Ilość argumentów: 2 Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów. Jeśli oba są łańcuchami tekstowymi, równymi (z dokładnością do wielkości znaków) true (dla prawdy) lub false (dla fałszu), na odpowiadającym im wartościom logicznym wykonywana jest odpowiednia operacja logiczna, a następnie wynik skonwertowany na łańcuch tekstowy odkładany jest na stos. Jeśli chociaż jeden z pobranych elementów nie jest łańcuchem tekstowym, lub jego wartość jest inna niż true lub false, podnoszony jest wyjątek TypeMismatchException. Strona 67 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Przed Stos rezultatów ‘true’ ‘false’ Stos środowiskowy Stos rezultatów Po ‘false’ Rysunek 5 - 4 przykład działania operatora "AND" Uwagi: Przyjęte rozwiązanie wprowadzające możliwość obsługi wartości logicznych jest jednym z kilku możliwych. Podobnie jak pozostałe prowadzi do różnego rodzaju problemów (takich jak możliwość przypadkowego wstawienia do pliku XML w miejsca, w których użytkownik oczekuje wartości „logicznych” innych danych. Umiejętne wykorzystanie DTD lub XML Schema może pozwolić na uniknięcie przynajmniej części problemów). 11.3.2 Operator „!” Ilość argumentów: 1 Zachowanie: Operator pobiera górny element ze stosu rezultatów. Jeśli jest on łańcuchem tekstowym, równym (z dokładnością do wielkości znaków) true (dla prawdy) lub false (dla fałszu), na odpowiadającej wartości logicznej zostaje wykonana operacja negacji, a wynik skonwertowany na łańcuch tekstowy odkładany jest na stos. Jeśli pobrany element nie jest łańcuchem tekstowym, lub jego wartość jest inna niż true lub false, podnoszony jest wyjątek TypeMismatchException. Stos środowiskowy Stos rezultatów Przed ‘false’ Stos środowiskowy Stos rezultatów Po ‘true’ Rysunek 5 - 5 przykład działania operatora "!" Uwagi: Do tego operatora odnoszą się te same uwagi, co do operatorów „AND” i „OR” Strona 68 Język zapytań dla XML oparty na podejściu stosowym 11.4.Operatory porównań 11.4.1 Operator„=” Ilość argumentów: 2 Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów. Jeśli oba mogą zostać skonwertowane na typ liczbowy, są konwertowane i porównywane jako liczby. Jeśli konwersja na typ liczbowy jest niemożliwa, ale możliwe jest potraktowanie obu elementów jako łańcuchów tekstowych, elementy są porównywane jako łańcuchy tekstowe. W przeciwnym wypadku porównywane są referencje do elementów. Wynik porównania (true/false), zamieniony na łańcuch tekstowy umieszczany jest na stosie rezultatów. Jeśli przynajmniej jeden z pobranych elementów jest tablicą o długości większej niż 1, podnoszony jest wyjątek TypeMismatchException. Stos środowiskowy Stos rezultatów Przed 12 12 Stos środowiskowy Stos rezultatów Po ‘true’ Rysunek 5 - 6 przykład działania operatora "=" Uwagi: Porównywanie referencji odbywa się zgodnie z zasadami opisanymi w części dotyczącej struktur danych. 11.4.2 Operatory „<”, „>” Ilość argumentów: 2 Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów. Jeśli oba mogą zostać skonwertowane na typ liczbowy, są konwertowane i porównywane jako liczby. Jeśli konwersja na typ liczbowy jest niemożliwa, ale możliwe jest potraktowanie obu elementów jako łańcuchów tekstowych, elementy są porównywane jako łańcuchy tekstowe – elementy większe są łańcuchami tekstowymi dalszymi w porządku alfabetycznym. W przeciwnym wypadku podnoszony jest wyjątek TypeMismatchException. Wynik porównania (true/false), zamieniony na łańcuch tekstowy umieszczany jest na stosie rezultatów. Jeśli przynajmniej jeden z pobranych elementów jest tablicą o długości większej niż 1, podnoszony jest wyjątek TypeMismatchException. Strona 69 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Stos rezultatów Przed 13 12 Stos środowiskowy Stos rezultatów Po ‘false’ Rysunek 5 - 7 przykład działania operatora ">" Uwagi: Wynik porównania łańcuchów tekstowych może zależeć od wersji systemu operacyjnego, JRE, lokalnych ustawień i innych czynników. 11.4.3 Operator „!=” Ilość argumentów: 2 Zachowanie: Operator wywołuje najpierw operator „=” a następnie operator „!”. Stos środowiskowy Stos rezultatów Przed 12 12 Stos środowiskowy Stos rezultatów Po ‘false’ Rysunek 5 - 8 przykład działania operatora "!=" Uwagi: Informacje odnoszące się do działania operatorów „=” i „!” odnoszą się również do działania tego operatora. 11.4.4 Operatory „<=”, „>=” Ilość argumentów: 2 Zachowanie: Najpierw wywoływany jest odpowiedni operator („>” dla „<=”, „<” dla „>=”) a następnie operator „!”. Strona 70 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Stos rezultatów Przed 12 12 Stos środowiskowy Stos rezultatów Po ‘true’ Rysunek 5 - 9 przykład działania operatora ">=" Uwagi: Informacje odnoszące się do działania operatorów „>”, „<” i „!” odnoszą się również do działania tego operatora. 11.5.Operatory działające na kolekcjach 11.5.1 Operator „count” Ilość argumentów: 1 Zachowanie: Operator pobiera górny element ze stosu rezultatów i zlicza zawarte w nim węzły, wartości liczbowe i tekstowe (bez schodzenia w dół ich struktury) jakie zawiera ten element. Wynik – ilość znalezionych węzłów - zostaje zwrócony na stos rezultatów. Stos środowiskowy Stos rezultatów Przed <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> <pracownik>Wierzbowski</ pracownik> Stos środowiskowy Stos rezultatów Po 3 Rysunek 5 - 10 przykład działania operatora "count" Uwagi: 11.5.2 Operator „exists” Ilość argumentów: 1 Zachowanie: Operator pobiera górny element ze stosu rezultatów. Jeśli element ten jest niepusty (zawiera przynajmniej jeden węzeł, wartość liczbową lub tekstową) zwraca na stos rezultatów wartość logiczną true, w przeciwnym wypadku Strona 71 Język zapytań dla XML oparty na podejściu stosowym zwraca wartość logiczną false (wartości te są skonwertowane na łańcuchy tekstowe). Stos środowiskowy Stos rezultatów Przed <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> <pracownik>Wierzbowski</ pracownik> Stos środowiskowy Stos rezultatów Po ‘true’ Rysunek 5 - 11 przykład działania operatora "exists" Uwagi: 11.5.3 Operator „sum” Ilość argumentów: 1 Zachowanie: Operator pobiera górny element ze stosu rezultatów i sumuje zawarte w nim wartości liczbowe. Jeśli napotka węzeł lub wartość tekstową, podnosi wyjątek TypeMismatchException. Wynik – suma - zostaje zwrócony na stos rezultatów. Stos środowiskowy Przed Stos rezultatów 2 3 3.4 4 12 Stos środowiskowy Stos rezultatów Po 24.4 Rysunek 5 - 12 przykład działania operatora "sum" Uwagi: 11.6.Operatory zmiany nazwy 11.6.1 Operator „as” Ilość argumentów: 2 Strona 72 Język zapytań dla XML oparty na podejściu stosowym Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów. Element znajdujący się na szczycie stosu rezultatów traktowany jest jako łańcuch tekstowy odpowiadający nowej nazwie. Element znajdujący się bezpośrednio pod nim zawiera tablicę węzłów, których nazwa ma ulec zmianie. Następnie stworzone zostają węzły odpowiadające węzłom oryginalnym. Dodatkowo w celu umożliwienia porównywania referencyjnego oryginału z węzłem o zmienionej nazwie (jest on tworzony, w związku inna jest jego referencja), dodajemy do klasy ReferenceManager informacje o tym, że nowo utworzone węzły są klonami już istniejących. Operator odkłada na stosie rezultatów tablicę węzłów o nowej nazwie. Liczba węzłów w zwracanej tablicy jest równa liczbie węzłów, którym zmieniono nazwę. Stos środowiskowy Przed Stos rezultatów ‘x’ <pracownik>Kowalski</pracownik> Stos środowiskowy Stos rezultatów Po <x>Kowalski</x> Rysunek 5 - 13 przykład działania operatora "as" Uwagi: 11.6.2 Operator „group as” Ilość argumentów: 2 Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów. Element znajdujący się na szczycie stosu rezultatów traktowany jest jako łańcuch tekstowy odpowiadający nowej nazwie. Element znajdujący się bezpośrednio pod nim zawiera tablicę węzłów, których mają znaleźć się węźle o nowej nazwie. Następnie tworzony jest nowy węzeł o nowej nazwie. W kolejnym kroku wszystkie węzły podane jako drugi operator dodawane są jako elementy-dzieci do nowego węzła. Operator odkłada na stosie rezultatów jednoelementową tablicę zawierającą nowo utworzony węzeł. Strona 73 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Przed Stos rezultatów ‘x’ <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Stos środowiskowy Po Stos rezultatów <x> <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> </x> Rysunek 5 - 14 przykład działania operatora "group as" Uwagi: 11.7.Złączenia 11.7.1 Operator „,” Ilość argumentów: 2 Zachowanie: Operator pobiera dwa górne elementy ze stosu rezultatów. Oba są traktowane jako tablice węzłów. Wynikiem działania jest tablica węzłów o nazwie „StructNode”. Każdy z węzłów „StructNode” odpowiada jednemu z wyników zmodyfikowanego iloczynu kartezjańskiego (patrz Uwagi) parametrów. Na stos rezultatów odkładana jest tablica węzłów „StructNode”. Jeżeli aktualnie przetwarzany element jest typu „StructNode” to wtedy zamiast niego używana jest tablica wszystkich węzłów-dzieci znajdujących się w tym aktualnie przetwarzanym elemencie. Stos środowiskowy Przed Stos rezultatów <firma>Pracodawca S.A.<firma> <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Stos środowiskowy Stos rezultatów <StructNode> <pracownik>Kowalski</pracownik> <firma>Pracodawca S.A.<firma> </StructNode> <StructNode> <pracownik>Malinowski</pracownik> <firma>Pracodawca S.A.<firma> </StructNode> Po Rysunek 5 - 15 przykład działania operatora "," Strona 74 Język zapytań dla XML oparty na podejściu stosowym Uwagi: Różnica w działaniu tego operatora ze standardowym iloczynem kartezjańskim polega na tym, że gdy jeden z elementów jest pusty, iloczyn kartezjański zwraca zbiór pusty, natomiast operator „,” zwraca tablicę węzłów „StructNode”, w których znajdują się pojedyncze elementy niepustego zbioru. 12. Rozwiązania implementacyjne – implementacja operatorów nie-algebraicznych Operatory nie-algebraiczne stanowią istotę podejścia stosowego. Podstawową różnica między nimi a operatorami algebraicznymi jest wykonywanie operacji na stosie środowisk. 12.1.Operatory selekcji 12.1.1 Operator „where” Ilość argumentów: 2 Zachowanie: Operator pobiera górny element ze stosu rezultatów, jako drugi argument otrzymuje poddrzewo rozbioru gramatycznego zapytania. Dla każdej wartości (węzła, wartości liczbowej, łańcucha tekstowego) z pobranego elementu ewaluuje otrzymane podzapytanie. Jeśli w wyniku ewaluacji podzapytania dla danego elementu otrzymano przynajmniej jeden łańcuch tekstowy o wartości true, dana wartość dodawana jest do zbioru wyników. Następnie otrzymany zbiór wyników odkładany jest na stos rezultatów. Stos środowiskowy Stos rezultatów Przed <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Stos środowiskowy Podczas Po Stos rezultatów <TextValue>Kowalski</TextValue> <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> ‘true’ <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> <pracownik>Kowalski</pracownik> Rysunek 5 - 16 przykład działania operatora "where" Uwagi: Strona 75 Język zapytań dla XML oparty na podejściu stosowym 12.2.Kwantyfikatory 12.2.1 Operator „for any holds” Ilość argumentów: 2 Zachowanie: Operator pobiera górny element ze stosu rezultatów, jako drugi argument otrzymuje poddrzewo rozbioru gramatycznego zapytania. Dla każdej wartości (węzła, wartości liczbowej, łańcucha tekstowego) z pobranego elementu podnosi stos środowisk, wstawiając jego zawartość na szczyt tego stosu, a następnie ewaluuje otrzymane podzapytanie. Jeśli w wyniku ewaluacji podzapytania dla dowolnego elementu otrzymano przynajmniej jeden łańcuch tekstowy o wartości true, operator zwraca na stos rezultatów wartość true (zamienioną na łańcuch tekstowy), w przeciwnym wypadku zwraca wartość false. Stos środowiskowy Stos rezultatów Przed <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Stos środowiskowy Podczas Stos rezultatów <TextValue>Kowalski</TextValue> Po <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> ‘true’ <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> ‘true’ Rysunek 5 - 17 przykład działania operatora "for any holds" Uwagi: 12.2.2 Operator „for all holds” Ilość argumentów: 2 Zachowanie: Operator pobiera górny element ze stosu rezultatów, jako drugi argument otrzymuje poddrzewo rozbioru gramatycznego zapytania. Dla każdej wartości (węzła, wartości liczbowej, łańcucha tekstowego) z pobranego elementu podnosi stos środowisk, wstawiając jego zawartość na szczyt tego stosu, a następnie ewaluuje otrzymane podzapytanie. Jeśli w wyniku ewaluacji podzapytania dla każdego z elementów otrzymano przynajmniej jeden łańcuch tekstowy o wartości true, operator zwraca na stos rezultatów wartość true (zamienioną na łańcuch tekstowy), w przeciwnym wypadku zwraca wartość false. Strona 76 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Stos rezultatów Przed <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Stos środowiskowy Podczas Stos rezultatów <TextValue>Kowalski</TextValue> Po <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> ‘false’ <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> ‘false’ Rysunek 5 - 18 przykład działania operatora "for all holds" Uwagi: 12.3.Złączenia 12.3.1 Operator „depjoin” Ilość argumentów: 2 Zachowanie: Operator nie-algebraiczny realizujący zależne złączenie. Dla każdego elementu z pierwszego parametru podnoszony jest stos środowisk, na który wstawiane są bindery z wnętrza elementu. Następnie względem takiego stosu środowisk, wykonywane jest pod-zapytanie. Wynik tego pod-zapytania jest łączony poprzez węzeł „StructNode” z aktualnie przetwarzanym elementem z pierwszego parametru. Po wykonaniu operatora na stosie wyników znajduje się tablica węzłów typu „StructNode”. Strona 77 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Stos rezultatów Przed <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Stos środowiskowy Podczas Stos rezultatów <TextValue>Kowalski</TextValue> <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Po <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> <StructNode> ‘Kowalski’ <pracownik>Kowalski</pracownik> </StructNode> <StructNode> ‘Malinowski’ <pracownik>Malinowski</pracownik> </StructNode> Rysunek 5 - 19 przykład działania operatora "depjoin" Uwagi: 12.4.Inne operatory 12.4.1 Operator „.” Ilość argumentów: 2 Zachowanie: Operator pobiera górny element ze stosu rezultatów, jako drugi argument otrzymuje poddrzewo rozbioru gramatycznego zapytania. Dla każdej wartości (węzła, wartości liczbowej, łańcucha tekstowego) z pobranego elementu podnosi stos środowisk, wstawiając jego zawartość na szczyt tego stosu, a następnie ewaluuje podzapytanie. Wyniki ewaluacji podzapytania dodawane są do zbioru rezultatów, który na koniec ewaluacji umieszczany jest na stosie rezultatów. Strona 78 Język zapytań dla XML oparty na podejściu stosowym Stos środowiskowy Stos rezultatów Przed <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Stos środowiskowy Podczas Stos rezultatów <TextValue>Kowalski</TextValue> <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> Po <pracownik>Kowalski</pracownik> <pracownik>Malinowski</pracownik> ‘Kowalski’ Rysunek 5 - 20 przykład działania operatora "." Uwagi: Implementacja tego operatora różni się od istniejącej w SBQL – w szczególności zapytania typu „zapytanie.” nie jest poprawnym zapytaniem. Ten sposób implementacji nie ogranicza znacząco możliwości ekspresji języka (jedyną klasą zapytań, jaka nie może zostać zadana jest ta z powyższego przykładu), zwiększając jednocześnie czytelność kodu i zapytań. 13. Rozwiązania implementacyjne – operacje ellipse i $ W języku zaimplementowano również dwa dodatkowe sposoby wiązania do elementów na stosie środowisk (dla wygody nazwane operacjami). Poniżej znajduje się opis ich implementacji. 13.1.Implementacja operacji 13.1.1 Operacja ellipse Operacja ellipse realizowana jest przez wykorzystanie stosu środowisk. Podczas wstępnego przechodzenia drzewa tworzone są na spodzie stosu środowisk bindery do węzła będącego „korzeniem” dokumentu XML oraz do wszystkich węzłów znajdujących się w dokumencie XML. Binder do węzła będącego korzeniem jest tworzony zarówno pod nazwą tożsamą z nazwą węzła (np. baza_pracowników), jak i pod nazwą ellipse nazwa_węzła (np. ellipse baza_pracowników). Bindery do wszystkich pozostałych węzłów tworzone są tylko pod nazwą ellipse nazwa_węzła. Jako że XML nie dopuszcza nazw tagów lub atrybutów o nazwach zawierających spację, nie ma możliwości utworzenia bindera o takiej nazwie poprzez jakiekolwiek operacje w ramach języka zapytań (np. przy operacji „as” podniesiony zostanie przez parser DOM wyjątek informujący o próbie nadania niedozwolonej nazwy). Podczas parsowania zapytania wyrażenie ellipse identyfikator zostanie Strona 79 Język zapytań dla XML oparty na podejściu stosowym rozpoznane jako identyfikator węzła, a następnie związane na spodzie stosu środowisk (w jedynym miejscu, w którym wystąpi). 13.1.2 Operacja $ Jeśli identyfikator węzła rozpoczyna się znakiem $, metoda PutTableOnStack rozpozna nazwę jako mającą być wiązaną płytko – tylko na szczycie stosu środowisk i odpowiednio ograniczy zakres poszukiwania węzłów o tej nazwie. 13.2.O czym należy pamiętać przy rozszerzaniu funkcjonalności języka o operacje aktualizacji W razie rozszerzania języka o operacje aktualizacji należy pamiętać o dodaniu bindera do węzła o nazwie ellipse nazwa_węzła przy dodawaniu nowych węzłów do bazy – w przeciwnym wypadku niemożliwe będzie dotarcie do tych węzłów przy pomocy operacji ellipse. Podobnie w wypadku zmiany nazw węzłów należy usunąć jeden binder i dodać drugi. 14. Rozwiązania implementacyjne – implementacja linków Poniżej znajduje się opis struktur danych i algorytmów użytych w celu wprowadzenia obsługi linków do języka zapytań. 14.1.Zebranie informacji o węzłach z identyfikatorami Podczas ładowania pliku XML obchodzone jest całe drzewo XML. Jedną z czynności wykonywanych podczas obchodzenia drzewa jest zebranie identyfikatorów węzłów (wartości ich atrybutów id) i referencji do nich. Jeśli identyfikator jest już umieszczony w wektorze idVector, oznacza to iż obiekt o danym identyfikatorze istnieje już w systemie i obsługa linków zostaje wyłączona. W przeciwnym wypadku identyfikatory dodawane są do wektora idVector, zaś referencje do węzła umieszczone zostają w tablicy haszującej relatedNodes, z numerem węzła jako identyfikatorem. 14.2.Obsługa linków w trakcie wykonywania zapytań Podczas wykonywania metody getInnards, wywoływanej przez każdy operator niealgebraiczny, analizowane jest wnętrze węzła. Jeśli węzeł ma atrybut pointer o wartości true (z dokładnością do wielkości liter), a obsługa linków jest włączona, w tablicy haszującej relatedNodes wyszukiwany jest węzeł o identyfikatorze (wartości atrybutu id) równym danej tekstowej (TextValue) zawartej w węźle. Jeśli taki węzeł zostanie znaleziony, zostaje on umieszczony na stosie środowisk razem z innymi węzłami potomnymi. 14.3.O czym należy pamiętać przy rozszerzaniu funkcjonalności języka o operacje aktualizacji Przy rozszerzaniu języka o operacje aktualizacji należy pamiętać o aktualizacji wektora idVector, tablicy haszującej relatedNodes oraz zmiennej logicznej useRelations w wypadku, gdy dokonywane są operacje na węzłach posiadających identyfikatory. W wyniku operacji aktualizacyjnych identyfikatory mogą ulec zmianie, powstać nowe obiekty posiadające identyfikatory, mogą też zostać usunięte już istniejące obiekty z identyfikatorami. Strona 80 Język zapytań dla XML oparty na podejściu stosowym 15. Rozwiązania implementacyjne – interpretacja zapytań Parser zapytań został zrealizowany przy pomocy narzędzi JFlex i CUP. Łańcuch tekstowy z treścią zapytania zostaje przez parser zamieniony na drzewo rozbioru gramatycznego. 15.1.Konstrukcja skanera Skaner został stworzony przy pomocy narzędzia JFlex. Narzędzie to generuje skanery wykorzystujące automaty skończone to dopasowywania łańcuchów tekstowych do wzorców, zdefiniowanych przy pomocy wyrażeń regularnych. Szczegółowe informacje o zasadach działania JFlex i innych narzędzi tej klasy znajdują się w dokumentacji tego programu. Plik z definicją wzorców użyty do wygenerowania skanera za pomocą JFlex znajduje się poniżej. package edu.t2r.magisterka; import java_cup.runtime.Symbol; %% %class Lexer %unicode %ignorecase %cup %implements sym %{ private Symbol sym(int sym) { return new Symbol(sym); } private Symbol sym(int sym, Object val) { return new Symbol(sym, val); } %} /* floating point literals */ DoubleLiteral = ({FLit1}|{FLit2}|{FLit3}) {Exponent}? FLit1 = [0-9]+ \. [0-9]* FLit2 = \. [0-9]+ FLit3 = [0-9]+ Exponent = [eE] [+-]? [0-9]+ /*string literal*/ StringLiteral = '[^']*' /*table identifier*/ Shallow = \$ Deep = "ellipse " Identifier = ({Shallow}|{Deep})?[:jletter:][:jletterdigit:]* %% <YYINITIAL> { "+" { return (sym(OP_ADD)); } "-" { return (sym(OP_SUB)); } "*" { return (sym(OP_MUL)); } "/" { return (sym(OP_DIV)); } "," { return (sym(COMMA)); } "(" { return (sym(LPAR)); } Strona 81 Język zapytań dla XML oparty na podejściu stosowym ")" { return (sym(RPAR)); } "&" { return (sym(OP_CONC)); } ">=" { return (sym(OP_GRQ)); } "<=" { return (sym(OP_LEQ)); } "=" { return (sym(OP_EQ)); } "!=" { return (sym(OP_NEQ)); } ">" { return (sym(OP_GR)); } "<" { return (sym(OP_LE)); } "!" { return (sym(OP_NOT)); } "AND" {return (sym(OP_AND));} "OR" {return (sym(OP_OR));} "FOR ANY" { return (sym(OP_FORANY)); } "FOR ALL" { return (sym(OP_FORALL)); } "HOLDS" { return (sym(OP_HOLDS)); } "EXISTS" { return (sym(OP_EXISTS)); } "WHERE" { return (sym(OP_WHERE)); } "COUNT" { return (sym(OP_COUNT)); } "SUM" { return (sym(OP_SUM)); } "AS" { return (sym(OP_AS)); } "DEPJOIN" { return (sym(OP_DEPJOIN)); } "GROUP AS" { return (sym(OP_GROUPAS)); } "." { return (sym(DOT)); } {DoubleLiteral} { return (sym(DOUBLE_LITERAL,yytext())); } {Identifier} {return(sym(TABLE_ID,yytext())); } {StringLiteral} {return(sym(STRING_LITERAL,yytext())); } " " {} . {throw new Error("Ilegal character <"+yytext()+">");} } 15.2.Konstrukcja parsera Parser został stworzony przy pomocy narzędzia CUP. Narzędzie to generuje parsery typu LALR(1) na podstawie dostarczonej definicji gramatyki. Jako że dla każdej konstrukcji gramatycznej możliwe jest zdefiniowanie podejmowanych akcji, możliwości parserów stworzonych w ten sposób są w zasadzie zależne tylko od programisty. Proponowane rozwiązanie opiera się na konstrukcji drzewa rozbioru gramatycznego – rozwiązanie to umożliwia przyszłą rozbudowę systemu o optymalizację zapytań na drodze analizy i przekształcania drzewa rozbioru. Plik z definicją gramatyki użyty do wygenerowania parsera za pomocą CUP znajduje się poniżej. package edu.t2r.magisterka; //arithmetic operators terminal OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_UMINUS; //text operator terminal OP_CONC; //comparision operators terminal OP_EQ, OP_NEQ, OP_LE, OP_GR, OP_LEQ, OP_GRQ; //boolean operators terminal OP_AND, OP_OR, OP_NOT; //collection operators terminal OP_COUNT, OP_EXISTS, OP_SUM; //selection operator and quantifiers terminal OP_WHERE, OP_FORANY, OP_FORALL, OP_AS, OP_DEPJOIN, OP_GROUPAS, OP_HOLDS; //parenthesis et al Strona 82 Język zapytań dla XML oparty na podejściu stosowym terminal LPAR, RPAR, COMMA, DOT; //literals and table identifiers terminal STRING_LITERAL, DOUBLE_LITERAL, TABLE_ID; //query tree root non terminal TreeNode queryel; //binary operator non terminal BinaryOperator binop; //unary operator non terminal UnaryOperator unop; non terminal LiteralValue stringLiteral; non terminal LiteralValue tableLiteral; non terminal LiteralValue doubleLiteral; //precendence lists //selection and quantifiers go last precedence left OP_WHERE, OP_FORANY, OP_FORALL, OP_DEPJOIN; precedence left COMMA; //logical operators go third precedence left OP_AND, OP_OR; precedence left OP_EQ, OP_NEQ, OP_LE, OP_LEQ, OP_GR, OP_GRQ; //arithmetic operators go second precedence left OP_ADD, OP_SUB; precedence left OP_MUL, OP_DIV; precedence left OP_CONC; //unary operators go first precedence left OP_GROUPAS, OP_AS; precedence left OP_UMINUS; precedence left OP_SUM, OP_COUNT, OP_EXISTS; precedence left OP_NOT; precedence left DOT; //rules //query ::= DOUBLE_LITERAL binop DOUBLE LITERAL {::}; queryel ::= stringLiteral:l {: RESULT = new TreeNode (l); :}| doubleLiteral:l {: RESULT = new TreeNode (l); :}| tableLiteral:l {: RESULT = new TreeNode (l); :}| LPAR queryel:l RPAR {: RESULT = new TreeNode (l); :}| binop:l {: RESULT = new TreeNode (l); :}| unop:l {: RESULT = new TreeNode (l); :}; Strona 83 Język zapytań dla XML oparty na podejściu stosowym stringLiteral ::= STRING_LITERAL:l {: RESULT = new LiteralValue ((String)l,sym.STRING_LITERAL); System.out.println("STRING:"+l); :}; doubleLiteral ::= DOUBLE_LITERAL:l {: RESULT = new LiteralValue ((String)l,sym.DOUBLE_LITERAL); System.out.println("DOUBLE:"+l); :}; tableLiteral ::= TABLE_ID:l {: RESULT = new LiteralValue ((String)l,sym.TABLE_ID); System.out.println("TABLE:"+l); :}; binop ::= queryel:l OP_ADD queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_ADD); :}| queryel:l OP_SUB queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_SUB); :}| queryel:l OP_DIV queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_DIV); :}| queryel:l OP_CONC queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_CONC); :}| queryel:l OP_MUL queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_MUL); :}| queryel:l OP_EQ queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_EQ); :}| queryel:l OP_NEQ queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_NEQ); :}| queryel:l OP_LE queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_LE); :}| queryel:l OP_LEQ queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_LEQ); :}| queryel:l OP_GR queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_GR); :}| queryel:l OP_GRQ queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_GRQ); :}| queryel:l OP_AND queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_AND); :}| queryel:l OP_OR queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_OR); :}| queryel:l OP_WHERE queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_WHERE); :}| OP_FORANY queryel:l OP_HOLDS queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_FORANY); :}| OP_FORALL queryel:l OP_HOLDS queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_FORALL); :}| queryel:l COMMA queryel:r {: RESULT = new BinaryOperator (l,r,sym.COMMA); :}| queryel:l OP_AS tableLiteral:r {: RESULT = new BinaryOperator (l,r,sym.OP_AS); r.opcode=sym.STRING_LITERAL; :}| queryel:l DOT queryel:r {: RESULT = new BinaryOperator (l,r,sym.DOT); :}| queryel:l OP_DEPJOIN queryel:r {: RESULT = new BinaryOperator (l,r,sym.OP_DEPJOIN); :}| queryel:l OP_GROUPAS tableLiteral:r {: RESULT = new BinaryOperator (l,r,sym.OP_GROUPAS); r.opcode=sym.STRING_LITERAL; :}; unop ::= OP_COUNT queryel:l {: RESULT = new UnaryOperator (l,sym.OP_COUNT); :}| OP_EXISTS queryel:l {: RESULT = new UnaryOperator (l,sym.OP_EXISTS); :}| Strona 84 Język zapytań dla XML oparty na podejściu stosowym OP_NOT queryel:l {: RESULT = new UnaryOperator (l,sym.OP_NOT); :}| OP_SUM queryel:l {: RESULT = new UnaryOperator (l,sym.OP_SUM); :}| OP_SUB queryel:l {: RESULT = new UnaryOperator (l,sym.OP_UMINUS); :}; 15.3.Konstrukcja drzewa rozbioru gramatycznego Parser zwraca drzewo rozbioru gramatycznego, zbudowane z obiektów należących do czterech klas: TreeNode – obiekty typu TreeNode to elementy, których napotkanie nie pociąga za sobą żadnej akcji poza zejściem na niższy poziom drzewa. Obiekty tego typu tworzone są przy napotkaniu konstrukcji takich jak nawiasy – są one konieczne, ze względu na sposób, w jaki zorganizowany jest proces budowy drzewa. Mogłyby być one po zbudowaniu drzewa usuwane, jednak operacja taka pociągałaby za sobą dodatkowy koszt (obejście całego drzewa), wyższy od kosztu zachowania ich w strukturze drzewa. Jeśli w przyszłości zostanie zaimplementowana optymalizacja zapytań przez przebudowę drzewa, węzły typu TreeNode będą mogły być usuwane w ramach tego procesu. UnaryOperator – obiekty typu UnaryOperator reprezentują operatory jednoargumentowe. Obiekty tego typu tworzone są przy napotkaniu konstrukcji takich jak operatory „!” lub „unarny –”. BinaryOperator – obiekty typu BinaryOperator reprezentują operatory dwuargumentowe. Obiekty tego typu tworzone są przy napotkaniu konstrukcji takich jak operatory „+” lub „where”. LiteralValue – obiekty typu LiteralValue reprezentują liście drzewa, będące wartościami liczbowymi, łańcuchami tekstowymi lub nazwami węzłów. Przykładowo, dla zapytania (baza.Pracownik where ((Pensja.TextValue=2000) (Nazwisko.TextValue!='Kowalski'))) drzewo rozbioru wygląda tak, jak na następnej stronie Strona 85 OR Język zapytań dla XML oparty na podejściu stosowym where . or baza Pracownik = != . 2000 . Kowalski Pensja Nazwisko TextValue Rysunek 5 - 21 przykładowe drzewo rozbioru zapytania Strona 86 TextValue Język zapytań dla XML oparty na podejściu stosowym Podczas wykonywania zapytania drzewo obchodzone jest rekurencyjnie w porządku infiksowym, tzn: Ewaluowana jest lewa gałąź poddrzewa (którego korzeniem jest bieżący węzeł), jeśli jest niepusta. Rozpoznawany jest operator: o Jeśli węzeł drzewa jest typu TreeNode, nie jest wykonywane żadne działanie. o Jeśli węzeł drzewa jest typu LiteralValue, na stosie rezultatów umieszczana jest wartość uzyskana z ewaluacji prawej gałęzi poddrzewa (tzn. wartość liczbowa, łańcuch tekstowy lub węzły XML odpowiadające podanej nazwie). W prawidłowo skonstruowanym drzewie, dla węzłów typu LiteralValue lewa gałąź poddrzewa jest pusta. o Jeśli węzeł drzewa jest typu UnaryOperator, wywoływany jest odpowiedni operator jednoargumentowy. o Jeśli węzeł drzewa jest typu BinaryOperator, mogą zajść dwa przypadki: Operator reprezentowany przez ten węzeł jest operatorem algebraicznym. W takim wypadku ewaluowana jest prawa gałąź poddrzewa, a następnie wywołany zostaje odpowiedni operator dwuargumentowy. Operator reprezentowany przez ten węzeł jest operatorem niealgebraicznym. W takim wypadku wywoływany jest odpowiedni niealgebraiczny operator dwuargumentowy, z prawą gałęzią poddrzewa jako argumentem – jej ewaluacja będzie następnie wywoływana z wnętrza tego operatora. Strona 87 Język zapytań dla XML oparty na podejściu stosowym VI. Zakończenie 16. Trudności przy realizacji pracy W trakcie realizacji pracy napotkaliśmy na szereg trudności związanych zarówno z narzędziami jak i strukturą dokumentów XML. Trudności te są opisane poniżej. 16.1.Wpływ DOM na sposób realizacji pracy Wybór DOM jako standardu dostępu do dokumentu XML, w znaczący sposób wpłynął na implementację. DOM stanowi bardzo wygodne narzędzie dostępu do struktury i danych zawartych w dokumencie XML, wprowadza jednak szereg ograniczeń utrudniających implementację algorytmów zastosowanych w naszej pracy. 16.1.1 DOM a stos rezultatów W związku z tym, iż wyniki zapytań, przechowywane na stosie rezultatów mają postać węzłów DOM, które mogą pochodzić z kilku różnych dokumentów, potrzebne było przenoszenie węzłów (referencji węzłów) między dokumentami. Niestety standard DOM nie przewiduje możliwości umieszczenia tej samej instancji węzła w kilku dokumentach. W związku z powyższym konieczne jest tworzenie kopii węzłów („klonów”). Niestety w momencie tworzenia kopii, kopia otrzymuje inną referencję niż oryginalny węzeł. Podobna konieczność zachodzi przy operacji zmiany nazwy. Aby działanie operatora porównania na równość w przypadku węzłów, gdy chcemy porównywać referencje, było możliwe konieczne było wprowadzenie mechanizmu odzyskiwania referencji oryginalnych węzłów. 16.1.2 Kolekcje w DOM Ponieważ istnieją implementacje DOM dla wielu języków programowania, kolekcje DOM nie są zgodne z kolekcjami zaimplementowanymi w Javie. W związku z tym konieczna jest konwersja jednych struktur na inne. 16.1.3 Wartości tekstowe w DOM Opis standardu DOM określa sposób zwracania wartości tekstowych znajdujących się wewnątrz węzłów XML. W ramach jednego węzła może wystąpić dowolna liczba wartości tekstowych. Ponadto znaki końca linii są traktowane jako pełnoprawne znaki, co może kłócić się z intuicją niektórych użytkowników. Ponieważ zamierzeniem twórców nie było wprowadzanie zmian do sposobu obsługi dokumentów XML przez DOM, nie dokonano żadnych zmian w stosunku do DOM. Użytkownik może w łatwy sposób dokonać tej zmiany samodzielnie (poprzez edycję dokumentu XML, lub wprowadzenie zmian do kodu źródłowego aplikacji). 16.2.Inne napotkane trudności 16.2.1 Brak typów danych w XML Jako, że postanowiliśmy nie ograniczać się tylko do obsługi dokumentów ze zdefiniowanym XML Schema określającym typy, poważnym problemem było zdecydowanie się na strategię wnioskowania o typach danych tekstowych zawartych w dokumencie XML. Ponieważ ograniczanie się tylko do wartości tekstowych wydawało się zbyt mocnym ograniczeniem, wprowadzono obsługę danych liczbowych – zmiennoprzecinkowych, oraz danych logicznych. W tym celu wykorzystano istniejące w języku Java metody konwersji łańcuchów znakowych na odpowiednie typy. Jeśli Strona 88 Język zapytań dla XML oparty na podejściu stosowym konwersja udaje się, dane traktowane są jako dane odpowiedniego typu, w przeciwnym wypadku traktowane są jako łańcuch znaków. W celu dokonaniu zmiany typu z liczbowego na tekstowy należy dokonać konkatenacji z pustym łańcuchem. 16.2.2 Linki Mimo istnienia wielu potencjalnych rozwiązań problemu tworzenia powiązań między węzłami w dokumentach XML, żaden z nich nie wydał się zadowalający. W związku z tym, zdecydowano się na implementację własnego modelu tworzenia powiązań (opis rozwiązania znajduje się w Rozdziale Czwartym niniejszej pracy). 17. Wady i zalety przyjętego rozwiązania 17.1.Zalety przyjętego rozwiązania Stworzony język zapytań jest językiem zdefiniowanym znacznie dokładniej niż inne znane magistrantom języki zapytań do XML. Jest językiem w pełni ortogonalnym, łatwo poddającym się rozbudowie, zwięzłym oraz czytelnym dla użytkownika i opartym na bardzo mocnych podstawach teoretycznych. Wykorzystanie standardowych narzędzi do parsowania zapytań umożliwia bardzo łatwą adaptację składni do potrzeb użytkownika. Wykorzystanie standardu DOM umożliwia korzystanie z potencjalnych udogodnień wprowadzonych w kolejnych wersjach standardu oraz implementacjach parserów. Zastosowanie podejścia stosowego w implementacji języka zapytań pozwala na skorzystanie z algorytmów optymalizacji zapytania zaproponowane przez Jacka Płodzienia ([30]). 17.2.Wady przyjętego rozwiązania Wykorzystanie drzewa DOM jako składu obiektów, co opisano powyżej. Stworzony przez autorów język nie stosuje się w pełni do wymagań XML Query Requirements, co może być argumentem dla krytyków tego rozwiązania, aczkolwiek autorzy pracy nie uważają tego za wadę. Za wadę może być również uważana niewielka liczba zaimplementowanych operatorów oraz brak operacji aktualizacyjnych. Wada ta może być jednak łatwo usunięta, gdyż język ten jest bardzo prosty w rozbudowie, a celem autorów było pokazanie możliwości stworzenie języka zapytań dla XML w oparciu o podejście stosowe. 18. Potencjalne zastosowania pracy 18.1.Możliwości wykorzystania rezultatu pracy w konstrukcji repozytorium dokumentów Jednym z celów niniejszej pracy jest stworzenie podstaw do budowy nowoczesnych, efektywnych i wygodnych w użytkowaniu repozytoriów dokumentów. Efektem naszej pracy jest w pełni działający, zaimplementowany język zapytań dla XML. W jaki sposób język ten może zostać wykorzystany w konstrukcji repozytoriów? Co należy zrobić, aby mógł być jeszcze lepszy w takich zastosowaniach? Jak pokazaliśmy w Rozdziale 2, istniejące obecnie systemy do tworzenia repozytoriów dokumentów są bardzo dopracowane w większości obszarów. Ich największą słabością jest mało wygodny system wyszukiwania danych, nierzadko wymagający długiego nawigowania po powiązaniach między dokumentami. Język zapytań obsługujący strukturę danych tak elastyczną jak XML, rozbudowany o mechanizm powiązań może znacząco ułatwić wyszukiwanie interesujących Strona 89 Język zapytań dla XML oparty na podejściu stosowym danych. Ilość systemów używających danych zapisanych w formacie XML rośnie z dnia na dzień, zaś konwersja danych z baz danych do XML jest stosunkowo mało skomplikowana, tak więc nie należy spodziewać się z tej strony problemów z adaptacją języka zapytań do istniejących systemów. W przypadku dużych repozytoriów danych pliki XML mogą okazać się zbyt nieefektywne, z przyczyn objętościowych - znaczną część pliku XML zajmują znaczniki (co powoduje duże zużycie miejsca na dysku), zaś przyjęty system zakładający załadowanie całej bazy do pamięci może nie być najlepszym rozwiązaniem dla dużych zbiorów danych. W celu efektywnej obsługi takich systemów należy stworzyć implementację języka zapytań wykorzystującą bardziej zaawansowany model składu, z użyciem plików w formacie binarnym z indeksowaniem (i innymi rozwiązaniami znanymi z baz relacyjnych). 18.2.Możliwości wykorzystania pracy w konstrukcji aplikacji Poza repozytoriami, istnieje szereg innych zastosowań, w których magistranci widzą możliwość zastosowania rezultatu swoich prac lub ich rozwinięcia: Wiele aplikacji używa XML jako standardu wymiany danych. Język zapytań umożliwiający przetwarzanie dokumentów XML może posłużyć jako bardzo przydatny komponent służący do budowy takich systemów. Często spotyka się aplikacje wykorzystujące proste, lekkie bazy klasy MySQL lub Hypersonic SQL. Język (i jego implementacja) będący rezultatem pracy ma przewagę nad tymi produktami pod względem uniwersalności, przy zbliżonej wydajności. Przejście na inny model składu (rezygnacja z XMLowej reprezentacji danych) może dodatkowo poprawić wydajność i możliwości systemu. Co prawda magistranci nie uważają XML jako idealnego, lekkiego rozwiązania bazodanowego, jednak w porównaniu z rozwiązaniami zastosowanymi w wymienionych (bardzo popularnych) bazach jest on co najmniej równie dobry. Wskazane byłoby w takim przypadku rozbudowanie języka o konstrukcje służące do modyfikacji danych. Magistranci dostrzegli problemy ze zrozumieniem idei działania języków opartych na semantyce stosowej wśród studentów. W obecnej wersji system jest na tyle prosty, że możliwe jest stosunkowo łatwe zmodyfikowanie go w celu stworzenia narzędzia edukacyjnego, prezentującego sposób działania tej klasy języków, i możliwość zapoznania się z ich możliwościami. 19. Możliwości rozwoju pracy Rezultat pracy – język zapytań do XML oparty na semantyce stosowej jest w swojej obecnej wersji rozwiązaniem stosunkowo prostym. Możliwości jego rozwoju, mające na celu zwiększenie możliwości i poszerzenie obszaru zastosowań są bardzo duże. Możliwe jest wprowadzenie dodatkowych cech takich jak: Perspektywy – zarówno zmaterializowane jak i niezmaterializowane, Wykorzystanie informacji zawartych w DTD lub XML Schema, w celu wnioskowania o typach danych, kontroli struktury itd. Wprowadzenie cech obiektowych takich jak klasy, dynamiczne role itp. (wiązałoby się to również z rozszerzeniem języka o możliwość definiowania metod) Wprowadzenie optymalizatora zapytań W toku prac magistranci doszli do wniosku, iż pomimo powierzchownej atrakcyjności, XML, w skutek różnych związanych z nim problemów, nie jest dobrym rozwiązaniem dla aplikacji typu bazodanowego. W związku z tym atrakcyjna wydaje się przebudowa systemu w celu zmiany modelu Strona 90 Język zapytań dla XML oparty na podejściu stosowym składu obiektów. Poza ułatwieniem realizacji wspomnianych już rozszerzeń, umożliwiłoby to następujące udoskonalenia: Wprowadzenie mocnej kontroli typów Możliwość obsługi dużych zbiorów danych przez zastosowanie indeksowania i innych technik znanych z istniejących systemów bazodanowych Zwiększenie zgodności implementacji z teorią – w chwili obecnej można wskazać miejsca, w których istniejące rozwiązania są rezultatem kompromisów między teorią a ograniczeniami wykorzystanych narzędzi (przede wszystkim przebudowa modelu składu obiektów oraz stosu rezultatów). Dzięki ich usunięciu możliwe byłoby dalsze uproszczenie kodu i struktur danych. Dodanie obsługi znaków diaktrycznych dla standardów kodowania innych niż Unicode. Podsumowując, możliwości rozszerzenia i kontynuacji prac są bardzo duże – wskazane obszary to tylko wierzchołek góry lodowej. Strona 91 Język zapytań dla XML oparty na podejściu stosowym Podsumowanie Niniejsza praca magisterska osiągnęła stawiane przed nią zadania. Stworzono język zapytań dla XML oparty na podejściu stosowym, udowadniając przydatność tego podejścia do tworzenia języków zapytań również dla danych pół-strukturalnych. Pomimo napotkanych trudności stworzono w pełni działający prototyp języka zapytań, którego łatwość użycia i rozbudowy jest znacznie wyższa niż innych znanych autorom rozwiązań. Rezultat niniejszej pracy daje możliwość prowadzenia dalszych prac mających na celu stworzenie jeszcze silniejszych i znacznie bardziej rozbudowanych narzędzi mogących znaleźć zastosowanie w wielu istotnych (również z biznesowego punktu widzenia) obszarach. Strona 92 Język zapytań dla XML oparty na podejściu stosowym Bibliografia [1]. Ricardo Baeza-Yates, Berthier Ribeiro-Neto Modern Information Retrieval strony 99-116 Addison-Wesley Longman Limited, New York 1999. [2]. Ian H. Witten, Alistair Moffat, Timothy C. Bell Managing Gigabytes: Compressing and Indexing Documents and Images, Second Edition strony 469-483 Morgan Kaufmann Publishers, San Francisco 1999 [3]. Kazimierz Subieta Teoria I Konstrukcja obiektowych języków zapytań [4]. http://www.objectivity.com [5]. http://www.db4o.com [6]. http://www.versant.com [7]. Kazimierz Subieta Wprowadzenie do standardu ODMG część 4. [8]. William Y. Mars, Christophe Blanche, Edward A. Overly Architecture for Information in Digital Libraries, D-Lib Magazine, February 1997 [9]. Chris Marlin Commercial CM Systems http://see.cs.flinders.edu.au/seweb/scm/comtools.html [10]. www.apache.org [11]. www.compiler-construction.org [12]. www.jflex.de [13]. www.cs.princeton.edu/~appel/modern/java/CUP/ [14]. Zdzisław Płoski Słownik Encyklopedyczny – Informatyka, Wydawnictwa Europa. ISBN 83-87977-16-0. Rok wydania 1999 [15]. www.w3c.org [16]. http://www.cogneticsystems.com/xquery/xquery.html [17]. http://www.w3.org/TR/NOTE-xml-ql/ [18]. http://www-db.stanford.edu/lore/ [19]. http://www.ibiblio.org/xql/ [20]. belllabs.com/user/simeon/icfp.ps [21]. http://www.w3.org/1999/09/ql/docs/xquery.html [22]. http://xerox.elet.polimi.it/xml-gl/ [23]. http://www.cs.toronto.edu/~gus/weboql/ [24]. http://www.w3.org/TandS/QL/QL98/pp/wql.html [25]. Simon North XML Dla Każdego, Helion 2000 [26]. McLaughlin Brutt Java i XML, Helion 2001 [27]. http://java.sun.com/docs/white/langenv/ [28]. Andrew W. Appel Modern Compiler Implementation in Java, Cambridge University Press 1999 [29]. Aho Alfred V., Sethi Ravi, Ullman Jeffrey D Kompilatory. Reguły, metody i narzędzia, WNT 2002 [30]. http://www.ipipan.waw.pl/~jpl/ [31]. K. Subieta, J. Leszczylowski. A Critique of Object Algebras ,November 1995, dostępne pod adresem http://www.ipipan.waw.pl/~subieta/EngPapers/index.html [32]. K. Subieta, Y. Kambayashi, J. Leszczylowski, K. Yokota. Object Algebras: What is Wrong?, July 1995, dostępne pod adresem http://www.ipipan.waw.pl/~subieta/EngPapers/index.html Strona 93