Both sides previous revision
Poprzednia wersja
Nowa wersja
|
Poprzednia wersja
|
pl:miw:miw08_prolog_xml [2008/06/06 12:13] miw |
pl:miw:miw08_prolog_xml [2019/06/27 15:50] (aktualna) |
====== Opis ====== | ====== Opis ====== |
| __**Projekt zakończony**__ |
| |
Wojciech Szymański <wojtek.szym@gmail.com> | Wojciech Szymański <wojtek.szym@gmail.com> |
| |
| |
Przetestowano następujące implementacje prologu: SWI-Prolog, BProlog, Amzi! Prolog, MINERVA, JIProlog oraz YAP Prolog. | Przetestowano następujące implementacje prologu: SWI-Prolog, BProlog, Amzi! Prolog, MINERVA, JIProlog oraz YAP Prolog. |
| |
| |
| |
==== SWI-Prolog ==== | ==== SWI-Prolog ==== |
| |
SWI-Prolog posiada pakiet //**sgml2pl**// - [[http://www.swi-prolog.org/packages/sgml2pl.html|SWI-Prolog SGML/XML parser]]. Pakiet ten posiada możliwości parsowania dokumentów XML wraz z namespaces oraz plików XML opartych o model DOM. Podstawowym predykatem służącym do parsowania jest: //**load_xml_file(+File,-ListOfContents)**//. Natomiast predykat służący do przetworzenia postaci prologowej na postać xml ma postać: //**xml_write(+Stream, +Term, +Options)**//. | SWI-Prolog posiada pakiet //**sgml2pl**// - [[http://www.swi-prolog.org/packages/sgml2pl.html|SWI-Prolog SGML/XML parser]]. Pakiet ten posiada możliwości parsowania dokumentów XML wraz z namespaces oraz plików XML opartych o model DOM. Podstawowym predykatem służącym do parsowania jest: //**load_xml_file(+File,-ListOfContents)**//. Natomiast predykat służący do przetworzenia postaci prologowej na dokument XML ma postać: //**xml_write(+Stream, +Term, +Options)**//. |
| |
Po wpisaniu w prologu: | Po wpisaniu w prologu: |
] ). | ] ). |
</code> | </code> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
==== JIProlog ==== | ==== JIProlog ==== |
Struktura postaci prologowej jest w postaci zagnieżdżonych termów zaczynając od //xml_document// i idąc wgłąb //xml_element//, //xml_attribute// oraz //xml_text//. | Dokument XML po sparsowaniu w JIProlog jest przedstawiony w postaci zagnieżdżonych termów zaczynając od //xml_document// i idąc wgłąb //xml_element//, //xml_attribute// oraz //xml_text//. |
| |
Charakterystyczne dla postaci prologowej są: | Charakterystyczne dla postaci prologowej są: |
* //**xml_document(Prolog, Root) [ [version = V, encoding = E], DocType]**// | * //**xml_document([ [version = Version, encoding = Encoding], DocType], Root).**//, gdzie argumentami są: |
* //**xml_element(Name, Attributes, Children)**// | * //**[ [version = Version, encoding = Encoding], DocType]**// - lista składająca się z listy zawierającej informacje o kodowaniu i wersji pliku XML oraz z informacji o typie dokumentu |
* //**xml_attribute(Name, Value)**// | * //**Root**// - korzeń dokumentu XML |
* //**xml_text(Content)**// | * //**xml_element(Name, Attributes, Children)**// - kolejne elementy pliku XML. Argumentami są: |
| * //**Name**// - nazwa węzła |
| * //**Attributes**// - lista atrybutów zawierająca termy postaci: //**xml_attribute(Name, Value)**//, gdzie argumentami są: |
| * //**Name**// - nazwa atrybutu |
| * //**Value**// - wartość atrybutu |
| * //**Children**// - lista kolejnych dzieci węzła, zawierająca ponownie termy //**xml_element(Name, Attributes, Children)**// oraz //**xml_text(Content)**// - tekst węzła |
| |
| Poniżej przedstawiono sparsowany plik XML w JIProlog: |
| <code prolog> |
| X=xml_document([version = 1.0, encoding = UTF-8], [], |
| xml_element(hml, [], [xml_text(), |
| xml_element(type_set, [], [xml_text()]), xml_text(), |
| xml_element(attribute_set, [], [xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_0), |
| xml_attribute(name, Thermostat), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_1), |
| xml_attribute(name, Time), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_2), |
| xml_attribute(name, Temperature), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_3), |
| xml_attribute(name, Date), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_4), |
| xml_attribute(name, Hour), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_5), |
| xml_attribute(name, season), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_6), |
| xml_attribute(name, operation), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_7), |
| xml_attribute(name, thermostat_settings), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_8), |
| xml_attribute(name, day), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_9), |
| xml_attribute(name, month), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_10), |
| xml_attribute(name, today), |
| xml_attribute(value, single)], |
| []), xml_text(), |
| xml_element(att, [ |
| xml_attribute(class, ro), |
| xml_attribute(id, att_11), |
| xml_attribute(name, hour), |
| xml_attribute(value, single)], |
| []), xml_text() |
| ]), xml_text(), |
| xml_element(property_set, [], [xml_text(), |
| xml_element(property, [xml_attribute(id, prp_0)],[xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_0)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_1)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_1)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_2)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_2)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_1)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_3)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_2)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_4)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_3)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_4)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_5)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_6)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_5)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_3)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_4)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_6)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_5)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_6)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_7)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_7)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_8)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_5)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_9)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_6)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_10)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_3)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_11)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_4)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_12)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_8)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_9)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_10)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_13)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_9)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_14)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_8)], []), xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_10)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_15)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_8)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_16)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_10)], []), xml_text() |
| ]), xml_text(), |
| xml_element(property, [xml_attribute(id, prp_17)], [xml_text(), |
| xml_element(attref, [xml_attribute(ref, att_11)], []), xml_text() |
| ]), xml_text() |
| ]), xml_text(), |
| xml_element(tph, [], [xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_1), xml_attribute(src, prp_0)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_2), xml_attribute(src, prp_1)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_3), xml_attribute(src, prp_1)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_4), xml_attribute(src, prp_2)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_5), xml_attribute(src, prp_4)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_6), xml_attribute(src, prp_4)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_7), xml_attribute(src, prp_3)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_8), xml_attribute(src, prp_6)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_9), xml_attribute(src, prp_6)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_10), xml_attribute(src, prp_5)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_11), xml_attribute(src, prp_5)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_12), xml_attribute(src, prp_10)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_13), xml_attribute(src, prp_12)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_14), xml_attribute(src, prp_12)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_15), xml_attribute(src, prp_14)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_16), xml_attribute(src, prp_14)], []), xml_text(), |
| xml_element(trans, [xml_attribute(dst, prp_17), xml_attribute(src, prp_11)], []), xml_text() |
| ]), xml_text(), |
| xml_element(ard, [], [xml_text(), |
| xml_element(dep, [xml_attribute(dependent, prp_7), xml_attribute(independent, prp_8)], []), xml_text(), |
| xml_element(dep, [xml_attribute(dependent, prp_7), xml_attribute(independent, prp_9)], []), xml_text(), |
| xml_element(dep, [xml_attribute(dependent, prp_8), xml_attribute(independent, prp_13)], []), xml_text(), |
| xml_element(dep, [xml_attribute(dependent, prp_16), xml_attribute(independent, prp_15)], []), xml_text(), |
| xml_element(dep, [xml_attribute(dependent, prp_9), xml_attribute(independent, prp_16)], []), xml_text(), |
| xml_element(dep, [xml_attribute(dependent, prp_9), xml_attribute(independent, prp_17)], []), xml_text() |
| ]) |
| ])) |
| </code> |
| |
| |
| |
| |
| |
| |
| |
===== Implementacja API w SWI-Prolog ===== | ===== Implementacja API w SWI-Prolog ===== |
| Ogólnodostępne wersje prologu nie posiadają mechanizmów do generowania dokumentów XML-DOM. Jedynie JIProlog dysponuje takimi możliwościami. Predykaty pozwalające na budowę dokumentu XML w JIProlog zostały omówione w sekcji ([[pl:miw:miw08_prolog_xml#jiprolog|JIprolog]]) W związku z tym postanowiono zaimplementować własne API do budowania plików XML. Jako wersję prologu przyjęto SWI-Prolog. Zaimplementowano następujące główne predykaty: |
| - //**create_root/2**// - tworzenie korzenia dokumentu XML |
| - //**app_child/4**// - dodawanie dzieci |
| - //**add_attribute/3**// - dodawanie atrybutów |
| |
| Plik zawierający pełne API dostępny jest do pobrania {{:pl:miw:miw08_prolog_xml:xml_api.pl|tutaj}} |
| |
| W przyszłości funkcjonalności API można dalej rozszerzać, np. o predykaty umożliwiające usuwanie dzieci, usuwanie atrybutów, czy też zmianę nazwy atrybutu bądź jego wartości. |
| |
| |
| |
| |
| |
| |
===== Przykład użycia API ===== | ===== Przykład użycia API ===== |
| W celu prezentacji działania API przygotowano przykład, w którym pokazane zostało generowanie dokumentu XML (budowanie dokumentu podobnego do pliku pochodzącego z systemu VARDA). |
| |
| Budowanie dokumentu XML rozpoczyna się od stworzenia korzenia. |
| |
| ==== Tworzenie korzenia ==== |
| Korzen dokumentu xml tworzymy wykorzystując predykat: |
| <code prolog> |
| create_root(Name,ID_name). |
| </code> |
| Jako parametry podajemy kolejno: |
| * nazwę korzenia |
| * prefiks id, np. podając **cd**, zostanie stworzony **id=cd_0** gdzie **0** będzie kolejno nadawaną liczbą, startując od zera. |
| |
| Po użyciu tego predykatu pojawi się nam główny element struktury prologowej stanowiący korzeń dokumentu xml. |
| |
| Przykład: |
| <code prolog> |
| ?- create_root(hml,hml). |
| |
| Yes |
| ?- listing(element). |
| |
| :- dynamic element/3. |
| |
| element(hml, [id=hml_0], []). |
| </code> |
| |
| Po stworzeniu korzenia dokumentu XML przechodzimy do dodawania kolejnych dzieci. |
| |
| |
| |
| |
| |
| |
| |
| ==== Dodawanie dzieci ==== |
| Dodawanie dzieci do korzenia dokumentu lub do istniejących rodziców wykonuje się za pomocą predykatu: |
| <code prolog> |
| app_child(Parent,P_id,Child,ChildIdName). |
| </code> |
| W predykacie tym jako argumenty podajemy kolejno: |
| * Nazwę rodzica |
| * Id rodzica - jeśli istnieje wiele elementów o tej samej nazwie, podajemy id rodzica, jeśli nie jest ważne do którego rodzica chcemy dodać dziecko wpisujemy "_" (dziecko zostanie dodane do pierwszego istniejącego rodzica) |
| |
| :!::!:**//UWAGA//**:!::!: |
| |
| Kiedy podajemy **id** rodzica, do którego chcemy przypisać dziecko, podajemy pełny tekst, np. **//id=prp_1//**. |
| * Nazwa dziecka |
| * prefiks id dziecka; Podając **ala** zostanie stworzony prefiks **ala_**, któremu automatycznie zostanie przydzielona kolejna liczba, np. **ala_1**. |
| |
| Dodanie dziecka o nazwie **//type_set//** i id **//typ_s//** do rodzica **//hml//** (korzeń) przedstawia poniższy kod: |
| <code prolog> |
| ?- app_child(hml,_,type_set,typ_s). |
| </code> |
| Powstaje następująca struktura, korzeń **//hml//** ma na liście dziecko **//type_set//** z id o podanym prefiksie i przydzielonym numerze. |
| <code prolog> |
| element(hml, [id=hml_0], [element(type_set, [id=typ_s_0], [])]). |
| </code> |
| |
| W podobny sposób dodajemy dzieci: |
| * attribute_set <code prolog> ?- app_child(hml,_,attribute_set,att_s). </code> |
| * property_set <code prolog> ?- app_child(hml,_,property_set,prp_s). </code> |
| * tph <code prolog> ?- app_child(hml,_,tph,tph). </code> |
| * ard <code prolog> ?- app_child(hml,_,ard,ard). </code> |
| |
| W celu dodania za jednym razem większej ilości dzieci używamy predykatu pochodnego: |
| <code prolog> |
| app_child(Parent,P_id,Child,ChildIdName,How_many). |
| </code> |
| Dodatkowym argumentem jest //**How_many**//, który oznacza ilość dodawanych dzieci. |
| |
| Jest to przydatne np, podczas dodawania wielu dzieci **//att//** do rodzica **//attribute_set//**. |
| Po użyciu predykatu: |
| <code prolog> |
| app_child(attribute_set,_,att,att,12). |
| </code> |
| zostanie dodanych dwanaście dzieci do rodzica **//attribute_set//**. |
| |
| Podobnie dodajemy: |
| * dzieci **//property//** do rodzica **//property_set//** <code prolog> ?- app_child(property_set,_,property,prp,18)</code> |
| * dzieci **//trans//** do rodzica **//tph//** <code prolog> ?- app_child(tph,_,trans,tr,17).</code> |
| * dzieci **//dep//** do rodzica **//ard//** <code prolog> ?- ?- app_child(ard,_,dep,dp,6).</code> |
| |
| Następnie pozostaje tylko dodanie odpowiednich dzieci **//attref//** do odpowiednich rodziców **//property//**. |
| Tu ponownie wykorzystujemy wyżej wymieniany predykat, ale już z podaniem ID rodzica. Przykładowo, po wpisaniu: |
| <code prolog> ?- app_child(property,id=prp_1,attref,att_r,2)</code> |
| dodane zostaną dwoje dzieci **//attref//** z id o prefiksie //**att_r_**// do rodzica **//property//** o id **//id=prp_1//**. |
| |
| ---- |
| :!::!:**//UWAGA//**:!::!: |
| |
| Kiedy podajemy **id** rodzica, do którego chcemy przypisać dziecko, podajemy pełny tekst, np. **//id=prp_1//**. |
| ---- |
| |
| |
| W ten sposób stworzono cały szkielet dokumentu XML o zadanym korzeniu oraz zadanych dzieciach. Każdy element posiada własne, unikalne id. Ostatnią rzeczą będzie dodawanie odpowiednich atrybutów. |
| |
| |
| |
| ==== Dodawanie atrybutów ==== |
| Atrybuty do wybranego elementu dodaje się przy użyciu predykatu, |
| <code prolog> |
| add_attribute(Parent,P_id,Attr). |
| </code> |
| gdzie jako argument podajemy kolejno: |
| * nazwę elementu, do którego chcemy dodać atrybut |
| * id elementu, do którego chcemy dodać atrybut |
| * atrybut (//nazwa=wartość//), który chcemy dodać |
| |
| ---- |
| |
| :!::!://**UWAGA**//:!::!: |
| |
| Kiedy podajemy **id** elementu, do którego chcemy dodać atrybut, podajemy pełny tekst, np. **//id=att_0//**. |
| |
| Podobnie jest w przypadku podawania atrybutu. Podajemy pełny tekst zawierający znak **//"="//** , np. **//name=thermostat//** |
| ---- |
| |
| Przykładowo użycie |
| <code prolog> |
| ?- add_attribute(att,id=att_0,name=thermostat). |
| </code> |
| spowoduje dodanie atrybutu **//name=thermostat//** do elementu **//att//** o id **//id=att_0//**. |
| |
| W ten sam sposób możemy dodać każdy atrybut do każdego istniejącego elementu w "prologowej" strukturze XML. |
| |
| |
| |
| |
| ==== Tworzenie pliku xml ==== |
| |
| Plik XML tworzymy przy użyciu predykatu |
| <code prolog> |
| prolog2xml(File). |
| </code> |
| Po wpisaniu: |
| <code prolog> |
| ?- prolog2xml('test.xml'). |
| </code> |
| zostanie utworzony plik XML o nazwie test. |
| |
| Możemy też skorzystać z predykatu |
| <code prolog> |
| save(File). |
| </code> |
| który zapisze w podanym pliku aktualną "prologową" strukturę XML oraz aktualny stan nadanych id, np. |
| <code prolog> |
| save('wiedza.pl'). |
| </code> |
| |
| Przykład dokumentu XML wygenerowanego z użyciem API znajduje się {{:pl:miw:test.xml|tutaj}}. |
| |
====== Projekt ====== | ====== Projekt ====== |