Zadanie 3 Poprawkowe XML i nowoczesne technologie zarządzania treścią 2007/08 Wprowadzenie Należy napisać program w Javie, który czytając w trybie SAX plik z listą operacji, wykonuje zadane operacje na drzewach DOM. Jednocześnie do innego pliku zapisywane są logi z wykonania operacji. Klasa wykonywalna programu powinna nazywać się Main. Program uruchamiany będzie z dwoma parametrami: ścieżką do pliku z operacjami i ścieżką do pliku z logami. Program operuje na zmiennych, które wskazują elementy (nie inne rodzaje węzłów!) w drzewach DOM. Zmienne identyfikowane są nazwami. Każda operacja może odnieść sukces lub porażkę. Porażka występuje wtedy, gdy nie są spełnione warunki niezbędne do wykonania operacji (jak opisano poniżej przy operacjach) lub podczas próby jej wykonania wyrzucany jest wyjątek (np. brak pliku). W przypadku porażki jednej operacji (także wyłapanego wyjątku) należy wykonywać kolejne operacje, nie przerywać programu. Format pliku z operacjami Plik z operacjami jest dokumentem XML zgodnym ze schematem operacje.xsd. Program powinien sprawdzić poprawność strukturalną dokumentu. W przypadku niezgodności powinien się zakończyć ze stosownym komunikatem, nie wykonując pozostałych do końca poleceń. Wszystkie elementy definiujące operacje znajdują się w przestrzeni nazw http://www.mimuw.edu.pl/%7eczarnik/xml/operacje. Jedynie element insertcontent może zawierać podelementy i atrybuty z innych przestrzeni nazw. Lista operacji zawiera kolejne definicje operacji, każda w kolejnym elemencie XML. Nazwa elementu to nazwa operacji, zgodnie z poniższym opisem, a w atrybutach podane są parametry operacji. Ponadto element może posiadać atrybut id, który identyfikuje operację w logach. Element insertcontent posiada też zawartość. Operacje Operacje readfromfile i createtree tworzą nowe zmienne (lub nadpisują istniejące). Pozostałe operacje kończą się porażką jeśli zmienna, której używają, nie została wcześniej utworzona. readfromfile Wczytanie dokumentu z pliku do drzewa DOM i przypisanie na podaną zmienną. Po wczytaniu zmienna wskazuje na element główny dokumentu. Jeśli zmienna istniała już wcześniej, jej dotychczasowa wartość jest zastępowana. Parsowanie ma być namespace aware i niewalidujące. Operacja ponosi porażkę w przypadku braku dostępu do pliku bądź błędów podczas parsowania.
var nazwa zmiennej, której przypisywane jest wczytane drzewo. Atrybut obowiązkowy. path ścieżka do pliku, który należy wczytać. Atrybut obowiązkowy. savetofile Zapisanie drzewa DOM wskazywanego przez zmienną do podanego pliku. Wartość zmiennej nie jest zmieniana. Plik jest nadpisywany. var nazwa zmiennej wskazującej na drzewo. Obowiązkowy. path ścieżka do pliku, do którego należy zapisać dokument. Obowiązkowy. document Równy yes lub no, domyślnie przyjmujemy no. Dla yes do pliku wypisywany jest cały dokument. Dla no wypisywane jest jedynie bieżący element wraz z poddrzewem. encoding kodowanie znaków, w jakim należy zapisać dokument. Jeśli nie występuje, należy przyjąć domyślne kodowanie systemu. createtree Utworzenie nowego drzewa (dokument z pustym elementem głównym) i przypisanie na podaną zmienną. Po utworzeniu zmienna wskazuje na element główny dokumentu. Jeśli zmienna istniała już wcześniej, jej dotychczasowa wartość jest zastępowana. var nazwa zmiennej, na którą przypisywane jest utworzone drzewo. Obowiązkowy. localname lokalna część nazwy elementu głównego. Obowiązkowy. ns identyfikator przestrzeni nazw, w której ma znaleźć się element główny. Napis pusty oznacza przestrzeń nazw o pustym identyfikatorze. Atrybut obowiązkowy. prefix prefiks nazwy elementu. Jeśli prefix nie występuje, element ma znaleźć się w domyślnej przestrzeni nazw. validate Walidacja dokumentu wskazywanego przez zmienną (całego dokumentu, nie poddrzewa) względem podanego schematu. Należy założyć, że plik ze schematem nie jest zmieniany w trakcie działania programu. Operacja odnosi sukces, jeśli dokument jest zgodny ze schematem. Operacja kończy się porażką jeśli dokument nie jest zgodny ze schematem (w logach należy wypisać komunikat od walidatora) lub podczas walidacji występuje błąd. Walidacja może zmienić dokument (np. wstawić domyślne wartości atrybutów). var nazwa zmiennej wskazującej drzewo. Obowiązkowy. schema ścieżka do pliku ze shcematem. Obowiązkowy.
moveup Przesunięcie wskaźnika zmiennej do rodzica. Jeśli wskaźnik jest już w elemencie głównym, operacja ponosi porażkę a wskaźnik zostaje w miejscu. moveleft i moveright Przesunięcie wskaźnika zmiennej do sąsiedniego elementu, odpowiednio poprzedzającego i następnego. Jeśli takiego nie ma, operacja ponosi porażkę a wskaźnik zostaje w miejscu. movetochild Przesunięcie wskaźnika zmiennej do elementu, który jest dzieckiem bieżącego elementu. localname lokalna część nazwy elementu. Jeśli nie występuje, bierzemy pod uwagę podelementy o dowolnej nazwie. ns identyfikator przestrzeni nazw elementu. Jeśli występuje, bierzemy pod uwagę tylko elementy z podanej przestrzeni nazw. Napis pusty oznacza przestrzeń nazw o pustym identyfikatorze. Jeśli ns nie występuje, bierzemy pod uwagę podelementy z dowolnej przestrzeni nazw. n numer podelementu (numerujemy od 1), atrybut obowiązkowy. Wskaźnik ma przejść do n tego podelementu spełniającego warunki związane z nazwami. Jeśli nie ma takiego elementu, operacja ponosi porażkę, a wskaźnik nie przesuwa się. insertcontent Wstawienie do drzewa węzłów podanych bezpośrednio w definicji operacji. Zawartość insertcontent ma zostać sparsowana i wstawiona do drzewa DOM, za ostatnim dzieckiem bieżącego elementu. Uwzględnione mają być wszystkie elementy (wraz z atrybutami) i węzły tekstowe, należy zachować przestrzenie nazw. Zawartość ma zostać sparsowana rekurencyjnie, z zachowaniem struktury XML. Należy pominąć komentarze i instrukcje przetwarzania. Wstawione mają być także atrybuty elementu insertcontent, o ile ich identyfikator przestrzeni nazw jest niepusty i różny od http://www.mimuw.edu.pl/%7eczarnik/xml/operacje. Gdyby atrybuty już istniały, mają zostać nadpisane. insertvar Wstawienie do drzewa elementu wskazywanego przez inną zmienną. Do bieżącego węzła, za ostatnim dzieckiem ma zostać wstawiona kopia elementu wskazywanego przez drugą zmienną i
całego jego poddrzewa. var nazwa zmiennej, do której dodajemy podelement. Obowiązkowy. from nazwa zmiennej, z której element kopiujejmy. Obowiązkowy. remove Usunięcie z drzewa elementu wskazywanego przez zmienną. Jeśli jest to element główny, operacja ma odnieść porażkę. Po usunięciu zmienna ma wskazywać rodzica usuniętego elementu. var nazwa zmiennej. Obowiązkowy. deep Równy yes lub no, domyślnie przyjmujemy no. Dla yes usuwane jest całe poddrzewo. Dla no usuwany jest tylko sam element, a wszystkie jego dzieci są podnoszone poziom wyżej, tzn. zostają wstawione w miejsce usuwanego elementu. Przestrzenie nazw Całe przetwarzanie (zarówno SAX jak i DOM) ma być namespace aware. Program powinien zachowywać przestrzenie nazw w węzłach kopiowanych poleceniem insertvar oraz parsowanych poleceniem insertcontent, a także zachowywać przestrzenie nazw w poddrzewie podczas spłaszczania dokumentu poleceniem remove. Istotne jest to, aby w dokumentach wypisanych poleceniem savetofile nazwy elementów i atrybutów należały do tych samych przestrzeni nazw, co przy wczytywaniu. Nie ma obowiązku zachowywania tych samych prefiksów. Plik z operacjami może nie zmieścić się w pamięci. Natomiast można przyjąć, że w pamięci zmieszczą się wszystkie drzewa DOM (tzn. w przypadku braku pamięci program ma prawo zachować się w dowolny sposób). Logi Plik z logami jest zwykłym plikiem tekstowym. Należy go otwierać w trybie dopisywania. Dla każdej operacji w pliku powinien znaleźć się wpis o formacie opisanym poniżej. Format pojedynczego wpisu Wpis zawiera (napisy w jednym wierszy są rozdzielone pojedynczymi spacjami): nazw ę operacji, identyfikator operacji (jeśli podano atrybut napis SUCCESS lub FAIL, id), nazw ę elementu, na któr ą wskazuje zmienna po wykonaniu operacji (nazwa kwalifikowana, z ewentualnym prefiksem), w przypadku porażki: od nowego wiersza opis błędu ( getmessage() wyją tku lub kilka własnych słów w przypadku błędu wykrytego przez program), pusty wiersz oddzielający wpisy.
Paczka Program powinien działać w Javie 6.0. Program powinien używać domyślnych implementacji SAX i DOM dostępnych poprzez klasy SAXParserFactory i DocumentBuilderFactory, ewentualnie DOMImplementationRegistry. Klasy powinny być umieszczone w pakiecie pl.edu.mimuw.ab123456.zad3, gdzie ab123456 to wydziałowy login studenta. Należy wysłać archiwum ZIP lub TGZ, o nazwie równej loginowi studenta, zawierające: plik z opisem rozwiązania, kod źródłowy klas, jeśli do kompilacji nie wystarczy Opis rozwiązania powinien zawierać: imi ę i nazwisko autora oraz numer indeksu, krótki opis przyjętego sposobu rozwiązania, javac *.java Makefile lub skrypt Ant. przyjęte założenia, podjęte nietrywialne decyzje i ich uzasadnienie. W kodzie programu należy umieścić krótkie komentarze w kluczowych miejscach, a także komentarze zgodne z konwencjami javadoc dla własnych klas i metod. Ocena Na ocenę wpływ będą miały: Poprawność działania (testy) [4 pkt]. Poprawność w stosowaniu SAX i DOM (analiza kodu) [2 pkt]. Efektywność rozwiązania (testy i analiza kodu) [2 pkt]. Struktura i estetyka kodu, komentarze, opis [2 pkt]. Uwagi końcowe O więcej szczegółów i w razie wątpliwości można pytać mailowo: czarnik@mimuw.edu.pl Proszę sprawdzać FAQ. Rozwiązania (w postaci archiwum ZIP o nazwie równej loginowi, pliki w archiwum powinny być podpisane np. w komentarzu umieszczonym na początku dokumentu) należy wysyłać do 4 marca 2008 włącznie na adres: czarnik@mimuw.edu.pl.