Rozdział
-->
5[Author:T]
.
Obsługa dokumentów XML w JavaScripcie
Kiedy już znasz JavaScript, przynajmniej w zakresie potrzebnym do naszych potrzeb, możemy zacząć pracę z Obiektowym modelem dokumentu (DOM), standardem interfejsu programistycznego do obsługi dokumentów XML opracowanym przez W3C. Zanim powstał standard DOM, parsery i procesory różnie traktowały dokumenty XML, a co gorsza wszystko się stale zmieniało. Wraz z przedstawieniem DOM XML nareszcie wprowadzono jakiś standard obsługi. Pamiętaj, że w tym rozdziale opieramy się na Internet Explorerze Microsoftu, w którym standard DOM został najpełniej zaimplementowany i udostępniony przez JavaScript.
DOM W3C
W referencji DOM W3C powiedziano, że dokument XML ma być traktowany jako drzewo węzłów. Każdy fragment danych jest węzłem, elementy dzieci i tekst zawarty w elementach stają się podwęzłami. Traktowanie dokumentu XML jako drzewa jest rozwiązaniem dobrym (choć nie jedynym, o czym przekonamy się, kiedy przejdziemy do Javy), gdyż stosunkowo łatwo jest wskazać, które elementy zawarte są w których - element zawarty w innym jest jego podwęzłem. W modelu DOM wszystko, co znajduje się w dokumencie, staje się węzłem: elementy, atrybuty, tekst i tak dalej. Oto rodzaje węzłów przewidziane w specyfikacji DOM W3C:
element
atrybut
tekst
sekcja CDATA
odwołanie do encji
encja
instrukcja przetwarzania
komentarz
dokument
typ dokumentu
fragment dokumentu
notacja
Przyjrzyj się na przykład takiemu oto dokumentowi:
<?xml version="1.0" encoding="iso-8859-2"?>
<DOKUMENT>
<POZDROWIENIA>
Witaj w XML
<KOMUNIKAT>
</POZDROWIENIA>
Witaj w pokręconym świecie XML.
</KOMUNIKAT>
</DOKUMENT>
Mamy tu węzeł instrukcji przetwarzania i węzeł elementu głównego DOKUMENT. Węzeł DOKUMENT ma dwa podwęzły, POZDROWIENIA i KOMUNIKAT. Oba te węzły dzieci określane są jako bliźniacze. Zarówno węzeł POZDROWIENIA, jak i KOMUNIKAT mają po jednym podwęźle - są to węzły tekstowe zawierające dane tekstowe. W tym rozdziale będziemy dokumenty traktować właśnie jako takie drzewa węzłów; drzewo tego dokumentu pokazano na rysunku 5.1.
Rysunek 5.1. Dokument jako drzewo węzłów |
<DOKUMENT> < POZDROWIENIA > < KOMUNIKAT > Witaj w XML
Witaj w pokręconym |
DOKUMENT POZDROWIENIA KOMUNIKAT Witaj w XML
Witaj w pokręconym |
Każdy fragment danych traktowany jest jako węzeł. Używając metod zdefiniowanych w DOM W3C można poruszać się po poszczególnych gałęziach drzewa dokumentu - przykładem takiej metody jest nextChild powodująca przesunięcie się do następnego dziecka lub lastSibling powodująca przeniesienie do ostatniego węzła bliźniaczego danego węzła bieżącego. Taka praca z dokumentem wymaga nieco praktyki, dlatego właśnie temu zagadnieniu będzie poświęcony cały ten rozdział.
Istnieje szereg różnych poziomów (Level) DOM:
--> Level 0[Author:T] . Wprawdzie formalnie rzecz biorąc w DOM „poziom 0” nie istnieje, ale w ten właśnie sposób W3C określa wersję DOM zaimplementowaną we względnie wczesnych wersjach przeglądarek: Netscape Navigator 3.0 i Microsoft Internet Explorer 3.0.
Level 1. Taki właśnie poziom modelu DOM jest obecnie rekomendowany, na nim koncentrują się modele dokumentów HTML i XML. Dokumentację tego poziomu znajdziesz pod adresem www.w3.org/TR/REC-DOM-Level-1/.
Level 2. Ten poziom także ma już status --> rekomendacji[Author:T] W3C, jest on bardziej zaawansowany - zawiera między innymi obiektowy model arkuszy stylów. Obsługiwane jest także dołączanie informacji o stylach do dokumentu. Umożliwia pełną analizę dokumentu, zawiera wbudowany model zdarzeń i obsługuje przestrzenie nazw XML. Dokumentację tego poziomu znajdziesz pod adresem www.w3.org/TR/DOM-Level-2/.
Level 3. Ten poziom jest na razie w fazie planów, obejmować ma ładowanie i zapisywanie dokumentów, modeli zawartości (DTD i XML Schema), ma też obsługiwać walidację. Oprócz tego zawierać ma widoki dokumentu i formatowanie, podstawowe zdarzenia i grupy zdarzeń. Nie istnieje jeszcze dokumentacja dotycząca tego poziomu.
Praktycznie rzecz biorąc jedyną względnie kompletną implementacją DOM XML jest implementacja w Internet Explorerze w wersji 5 i nowszych. Dokumentacja DOM Microsoftu obecnie dostępna jest pod adresem http://msdn.microsoft.com/library/psdk/xmlsdk/xmld20ab.htm, ale strony tej firmy notorycznie są reorganizowane, więc być może będziesz musiał sam tej dokumentacji poszukać. Jeśli tak się stanie, wejdź po prostu na stronę http://msdn.microsoft.com i wyszukaj frazy „xml dom” (należy przyjąć, że adresom URL ze stron Microsoftu nie należy ufać dłużej niż przez dwa miesiące).
Jako że Internet Explorer dobrze obsługuje DOM Level 1, to tej wersji będziemy używać w tym rozdziale. Należy mieć nadzieję, że przełożenie tego na inną przeglądarkę zgodną ze specyfikacją W3C nie okaże się zmaganiem z augiaszowymi stajniami.
Obiekty DOM XML
Oto obiekty DOM W3C Level 1:
Obiekt |
Opis |
Document |
Cały dokument. |
DocumentFragment |
Fragment dokumentu. |
DocumentType |
Odwołanie do znacznika <!DOCTYPE>. |
EntityReference |
Odwołanie do encji. |
Element |
Element. |
Attr |
Atrybut. |
ProcessingInstruction |
Instrukcja przetwarzania. |
Comment |
Treść komentarza XML. |
Text |
Treść elementu lub wartość atrybutu. |
CDATAsection |
Sekcja CDATA. |
Entity |
Encja parsowana lub nieparsowana. |
Notation |
Notacja |
Node |
Węzeł drzewa. |
NodeList. |
Lista obiektów Node. Umożliwia realizację iteracji oraz operacje dostępu przez indeksy. |
NamedNodeMap |
Umożliwia iteracje i sięganie przez nazwę do zestawu atrybutów. |
Microsoft używa do tych obiektów innych nazw, a także dodaje własne obiekty. W szczególności zdefiniowano „obiekty podstawowe”, które stanowią fundament całego DOM XML. Obiektem najwyższego poziomu jest DOMDocument, jest to jedyny obiekt, który można stworzyć bezpośrednio - dostęp do wszystkich innych realizowany jest za jego pośrednictwem. Oto lista obiektów podstawowych Internet Explorera:
Obiekt |
Opis |
DOMDocument |
Węzeł główny drzewka DOM. |
XMLDOMNode |
Pojedynczy węzeł drzewa dokumentu. Zawiera informacje o typach danych, przestrzeniach nazw, DTD i schematach XML. |
XMLDOMNodeList |
Lista obiektów węzłów. Umożliwia realizację iteracji i dostęp przez indeksy. |
XMLDOMNamedNodeMap |
Umożliwia iteracje i dostęp do zestawu atrybutów przez nazwę. |
XMLDOMParseError |
Informacja o ostatnim błędzie. Zawiera numer błędu, numer wiersza, numer znaku oraz tekst opisowy. |
XMLHttpRequest |
Umożliwia komunikowanie się z serwerami HTTP. |
XTLRuntime |
Obsługuje metody, które można wywoływać z arkuszy stylów XSL. |
Oprócz obiektów podstawowych DOM XML Microsoftu zawiera także obiekty XML DOM, którymi posługuje się podczas pracy z dokumentami. Są to między innymi różne rodzaje węzłów, takie jak XMLDOMAttribute, XMLDOMCharacterData i XMLDOMElement:
Obiekt |
Opis |
XMLDOMAttribute |
Obiekt atrybutu. |
XMLDOMCDATASection |
Sekcja CDATA, której treść nie jest interpretowana. |
XMLDOMCharacterData |
Zawiera metody umożliwiające operacje na tekście. |
XMLDOMComment |
Podaje treść komentarza XML. |
XMLDOMDocumentFragment |
Niewielki obiekt wygodny do wstawiania fragmentów drzewka. |
XMLDOMDocumentType |
Informacje związane z deklaracją typu dokumentu. |
XMLDOMElement |
Obiekt elementu. |
XMLDOMEntity |
Oznacza parsowaną lub nieparsowaną encję dokumentu. |
XMLDOMEntityReference |
Węzeł odwołania do encji. |
XMLDOMImplementation |
Metody ogólne DOM. |
XMLDOMNotation |
Notacja (zadeklarowana w DTD lub w schemacie XML). |
XMLDOMProcessingInstruction |
Instrukcja przetwarzania. |
XMLDOMText |
Treść elementu lub wartość atrybutu. |
W tym rozdziale wykorzystamy wiele spośród tych obiektów. Zobaczysz, jak za pomocą DOM XML Microsoftu dokumenty XML parsować i wykorzystywać, a także jak obsługiwać zdarzenia podczas ładowania dokumentu. Zobaczysz też, jak na bieżąco modyfikować dokument XML.
Podana wyżej lista obiektów jest bardzo ważna, każdy z tych obiektów ma zdefiniowane przez W3C właściwości, metody i zdarzenia, wiele dodał także od siebie Microsoft (zatem te dodatki są niestandardowe). Jeśli mamy pracować w DOM XML, konieczne jest dobre zrozumienie znaczenia tych elementów. Teraz dokładniej omówimy najważniejsze obiekty, zaczniemy oczywiście od obiektu głównego - DOMDocument.
Obiekt DOMDocument
Obiekt DOMDocument to główny obiekt, z którym przyjdzie Ci pracować, reprezentuje on węzeł główny drzewka dokumentu. Jest to jedyny obiekt, do którego podczas pracy z DOM odwołujesz się bezpośrednio.
Dokumenty można w Internet Explorerze tworzyć na dwa sposoby: przy pomocy klasy Microsoft.XMLDOM i stosując wyspy danych XML. W przypadku tworzenia obiektu dokumentu za pomocą klasy Microsoft.XMLDOM jawnie ładuje się dokumentu za pomocą metody load:
function wczytajDokumentXML()
{
var xmldoc
xmldoc = newActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
.
.
.
Później zobaczysz, jak za pomocą znacznika HTML <XML> można stworzyć wyspę danych w Internet Explorerze i jak stosując właściwość XMLDocument tego elementu uzyskać dostęp do obiektu dokumentu:
<XML ID="spotkaniaXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function wczytajDokumentXML()
{
xmldoc = document.all("spotkaniaXML").XMLDocument
.
.
.
DOM XML i programy wielowątkowe
Istnieje też --> „wielowątkowa”[Author:T] wersja klasy Microsoft.XMLDOM, której można używać w programach wielowątkowych:
var xmldoc = new ActiveXObject("Microsoft.FreeThreadedXMLDOM")
Więcej informacji na ten temat znajdziesz na stronie Microsoftu http://msdn.microsoft.com/library/psdk/xmlsdk/xmld20ab.htm (pamiętaj o możliwości zmiany tego adresu).
Oto właściwości tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu; druga kolumna oznacza rodzaj właściwości: O=tylko do odczytu, OZ=do odczytu i zapisu):
Obiekt |
O/Z |
Opis |
async* |
OZ |
Czy dopuszczalne jest ładowanie asynchroniczne. |
attributes |
O |
Lista atrybutów węzła. |
baseName* |
O |
Nazwa bazy kwalifikowana przestrzenią nazw. |
childNodes |
O |
Lista węzłów zawierająca węzły dzieci, które mogą mieć własne dzieci. |
dataType* |
OZ |
Typ danych węzła. |
definition* |
O |
Definicja węzła w DTD lub schemacie. |
doctype |
O |
Typ węzła dokumentu - wskazuje DTD. |
documentElement |
OZ |
Element główny dokumentu. |
firstChild |
O |
Pierwsze dziecko bieżącego węzła. |
implementation |
O |
Obiekt XMLDOMImplementation danego dokumentu. |
lastChild |
O |
Ostatni węzeł dziecko węzła bieżącego. |
namespaceURI* |
O |
Adres URI przestrzeni nazw. |
nextSibling |
O |
Następny węzeł bliźniaczy węzła bieżącego. |
nodeName |
O |
Kwalifikowana nazwa elementu, atrybutu lub odwołania do encji. Dla innych rodzajów węzłów zawiera tekst stały. |
nodeType |
O |
Rodzaj węzła DOM XML. |
nodeTypedValue* |
OZ |
Wartość węzła. |
nodeTypeString* |
O |
Typ węzła w postaci napisu. |
nodeValue |
O |
Tekst węzła. |
ondataavailable* |
OZ |
Procedura obsługi zdarzenia ondataavailable. |
onreadystatechange* |
OZ |
Procedura obsługi zdarzenia, kiedy zmienia się wartość właściwości readyState. |
ontransformnode* |
OZ |
Procedura obsługi zdarzenia ontransformnode. |
ownerDocument |
O |
Węzeł główny dokumentu zawierającego węzeł bieżący. |
parentNode |
O |
Węzeł rodzic (tylko dla węzłów mających rodzica). |
parsed* |
O |
Ma wartość true, jeśli wszyscy potomkowie węzła zostali już przeanalizowani; w przeciwnym wypadku ma wartość false. |
parseError* |
O |
Obiekt XMLDOMParseError zawierający informacje o błędzie, jaki wystąpił ostatnio. |
prefix* |
O |
Przedrostek przestrzeni nazw. |
preserveWhiteSpace* |
OZ |
Jeśli podczas przetwarzania zachowane mają być białe znaki, ma wartość true. |
previousSibling |
O |
Poprzedni węzeł bliźniaczy węzła bieżącego. |
readyState* |
O |
Bieżący stan dokumentu XML. |
resolveExternals* |
OZ |
Czy definicje zewnętrzne mają być rozwijane podczas parsowania. |
specified* |
O |
Czy węzeł został podany jawnie, czy też wygenerowany na podstawie wartości domyślnej. |
text* |
OZ |
Zawartość tekstowa węzła i jego poddrzewek. |
url* |
O |
Kanoniczna postać adresu URL ostatnio ładowanego dokumentu XML. |
validateOnParse* |
OZ |
Czy parser ma przeprowadzić także walidację dokumentu. |
xml* |
O |
Reprezentacja węzła i jego potomków jako kodu XML. |
Oto metody tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu):
Metoda |
Opis |
abort* |
Przerywa ładowanie asynchroniczne. |
appendChild |
Dodaje dziecko jako ostatnie dziecko bieżącego węzła. |
cloneNode |
Zwraca nowy węzeł będący kopią węzła wskazanego. |
createAttribute |
Zwraca nowy atrybut o danej nazwie. |
createCDATASection |
Zwraca węzeł sekcji CDATA zawierającej przekazane dane. |
createComment |
Zwraca węzeł komentarza. |
createDocumentFragment |
Zwraca pusty obiekt DocumentFragment. |
createElement |
Zwraca element węzła o podanej nazwie. |
createEntityReference |
Zwraca obiekt EntityReference. |
createNode* |
Zwraca węzeł określonego typu, o danej nazwie i przestrzeni nazw. |
createProcessingInstruction |
Zwraca węzeł instrukcji przetwarzania. |
createTextNode |
Zwraca węzeł tekstowy zawierający przekazane dane. |
getElementsByTagName |
Tworzy kolekcję elementów o danej nazwie. |
hasChildNodes |
Zwraca true, jeśli węzeł ma dzieci. |
insertBefore |
Wstawia węzeł dziecko przed danym węzłem. |
load* |
Ładuje dokument XML spod danego adresu. |
loadXML* |
Ładuje dokument XML podany w przekazanym napisie. |
nodeFromID* |
Pobiera węzły, których atrybut ID pasuje do podanej wartości. |
removeChild |
Usuwa dany węzeł dziecko spośród listy dzieci. |
replaceChild |
Podmienia dany węzeł dziecko na nowy węzeł o podanych właściwościach. |
save* |
Zapisuje dokument XML pod podanym adresem. |
selectNodes* |
Stosuje podaną operację dopasowywania wzorca do kontekstu węzła, zwraca listę pasujących węzłów. |
selectSingleNode* |
Stosuje podaną operację dopasowywania wzorca do kontekstu węzła, zwraca pierwszy pasujący węzeł. |
transformNode* |
Przekształca węzeł i jego dzieci stosując podany arkusz stylów XSL. |
transformNodeToObject* |
Przekształca węzeł i jego dzieci na obiekt za pomocą danego arkusza stylów XSL. |
Oto zdarzenia tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu):
Zdarzenie |
Opis |
ondataavailable* |
Informuje, że dane dokumentu XML są już dostępne. |
onreadystatechange* |
Informuje o zmianie właściwości readyState. |
ontransformnode* |
Zachodzi przed zastosowaniem arkusza stylów do kolejnych węzłów źródłowego XML. |
Obiekt XMLDOMNode
Obiekt Microsoftu XMLDOMNode stanowi rozszerzenie podstawowego interfejsu aplikacji węzła DOM XML, gdyż dodaje typy danych, przestrzenie nazw, DTD i schematy. Podczas analizy drzewa dokumentu często będziemy tego obiektu odwoływali.
Oto właściwości tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu; druga kolumna oznacza rodzaj właściwości: O=tylko do odczytu, OZ=do odczytu i zapisu):
Obiekt |
O/Z |
Opis |
attributes |
O |
Lista atrybutów danego węzła. |
baseName* |
O |
Bazowa nazwa kwalifikowana przestrzenią nazw. |
childNodes |
O |
Lista węzłów zawierająca węzły dzieci węzła bieżącego. |
dataType* |
OZ |
Typ danych bieżącego węzła. |
definition* |
O |
Definicja węzła w DTD lub schemacie. |
firstChild |
O |
Pierwsze dziecko bieżącego węzła. |
lastChild |
O |
Ostatnie dziecko bieżącego węzła. |
namespaceURI* |
O |
Adres URI przestrzeni nazw. |
nextSibling |
O |
Następny węzeł bliźniaczy węzła bieżącego. |
nodeName |
O |
Kwalifikowana nazwa elementu, atrybutu lub odwołania się do encji, w przypadku innych typów węzłów napis. |
nodeType |
O |
Rodzaj węzła DOM XML. |
nodeTypedValue* |
OZ |
Wartość węzła. |
nodeTypeString* |
O |
Typ węzła w postaci napisu. |
nodeValue |
OZ |
Tekst związany z węzłem. |
ownerDocument |
O |
Element główny dokumentu. |
parentNode |
O |
Węzeł rodzic. |
parsed* |
O |
Ma wartość true, jeśli dany węzeł i wszyscy jego potomkowie byli parsowani, w przeciwnym wypadku false. |
prefix* |
O |
Przedrostek przestrzeni nazw. |
previousSibling |
O |
Poprzedni węzeł bliźniaczy węzła bieżącego. |
specified* |
OZ |
Czy wartość węzła podana została jawnie, czy określono ją na podstawie wartości domyślnej. |
text* |
OZ |
Tekstowa zawartość węzła i jego poddrzewek. |
xml* |
O |
Węzeł wraz ze swoimi potomkami w postaci kodu XML. |
Oto metody tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu):
Metoda |
Opis |
appendChild |
Dodaje nowe dziecko jako ostatnie dziecko danego węzła. |
cloneNode |
Tworzy nowy węzeł będący kopią bieżącego. |
hasChildNodes |
Zwraca wartość true, jeśli węzeł ma dzieci. |
insertBefore |
Wstawia węzeł dziecko przed węzłem danym. |
removeChild |
Usuwa dany węzeł dziecko. |
replaceChild |
Podmienia dany węzeł dziecko na inny nowy węzeł. |
selectNodes* |
Przeprowadza operację dopasowywania wzorca na kontekście węzła, zwraca listę pasujących węzłów. |
selectSingleNode* |
Przeprowadza operację dopasowywania wzorca na kontekście węzła, zwraca pierwszy pasujący węzeł. |
transformNode* |
Przekształca dany węzeł i jego dzieci za pomocą podanego arkusza stylów XSL. |
transformNodeToObject* |
Przekształca węzeł i jego dzieci przy pomocy podanego arkusza stylów XSL, zwraca wynik w postaci obiektu. |
Z obiektem tym nie są związane żadne zdarzenia.
Obiekt XMLDOMNodeList
Z obiektu XMLDOMNodeList korzysta się w celu obsługi listy węzłów. Listy węzłów są przydatne przede wszystkim dlatego, że każdy węzeł może mieć wiele węzłów dzieci i stosując listę możesz wszystkie dzieci przetwarzać jednocześnie.
W poniższym przykładzie ładujemy dokument i pobieramy do listy węzłów wszystkie elementy OSOBA, używamy metody getElementsByTagName:
function readXMLDocument()
{
var xmldoc, nodeList
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
nodeList = xmlDoc.getElementsByTagName("OSOBA")
.
.
.
Obiekt XMLDOMNodeList ma tylko jedną właściwość, length, która określa liczbę pozycji w kolekcji, jest to właściwość tylko do odczytu.
Oto metody tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu):
Metoda |
Opis |
item |
Umożliwia swobodny dostęp do węzłów kolekcji. |
nextNode* |
Wskazuje następny węzeł w kolekcji. |
reset* |
Powoduje przerwanie iteracji listy. |
Z obiektem tym nie są związane żadne zdarzenia.
Obiekt XMLDOMNamedNodeMap
DOM XML Microsoftu zawiera także obiekt XMLDOMNamedNodeMap do obsługi przestrzeni nazw.
Obiekt ten ma następujące właściwości (gwiazdką oznaczono rozszerzenia Microsoftu; druga kolumna oznacza rodzaj właściwości: O=tylko do odczytu, OZ=do odczytu i zapisu):
Obiekt |
O/Z |
Opis |
length |
O |
Podaje liczbę pozycji w kolekcji. |
item |
O |
Umożliwia dostęp swobodny do węzłów kolekcji. |
Oto metody tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu):
Metoda |
Opis |
getNamedItem |
Pobiera atrybut o podanej nazwie. |
getQualifiedItem* |
Pobiera atrybut o danej nazwie z podanej przestrzeni nazw. |
nextNode |
Pobiera następny węzeł. |
removeNamedItem |
Usuwa atrybut. |
removeQualifiedItem |
Usuwa atrybut o danej nazwie z podanej przestrzeni nazw. |
reset |
Powoduje przerwanie iteracji listy. |
setNamedItem |
Dodaje podany węzeł. |
Z obiektem tym nie są związane żadne zdarzenia.
Obiekt XMLDOMParseError
Microsoftowy obiekt XMLDOMParseError zawiera informacje dotyczące błędu parsowania, który wystąpił jako ostatni. Wśród tych informacji jest numer błędu, numer wiersza, pozycja znaku i opis tekstowy. Choć nie jest to oczywiste dla osób ładujących dokument XML do Internet Explorera, przeglądarka przeprowadza walidację względem załączonego DTD lub schematu XML - po prostu Explorer domyślnie nie wyświetla żadnych komunikatów dotyczących walidacji. Stosując jednak obiekt XMLDOMParseError można odczytać pełny raport z walidacji, czym zajmiemy się dalej w tym rozdziale.
Oto właściwości tego obiektu (druga kolumna oznacza rodzaj właściwości: O=tylko do odczytu, OZ=do odczytu i zapisu):
Obiekt |
O/Z |
Opis |
errorCode |
O |
Kod błędu parsowania, który ostatnio wystąpił. |
filepos |
O |
Położenie błędu w pliku. |
line |
O |
Numer wiersza zawierającego błąd. |
linepos |
O |
Położenie znaku w wierszu, w którym wystąpił błąd. |
reason |
O |
Przyczyna wystąpienia błędu. |
srcText |
O |
Pełny tekst wiersza z błędem. |
url |
O |
Adres URL dokumentu XML zawierającego błąd, który ostatnio wystąpił. |
Zwróć uwagę, że obiekt ten nie ma żadnych metod ani nie są z nim związane żadne zdarzenia, obiekt ten nie odpowiada żadnemu obiektowi należącemu do specyfikacji DOM W3C.
Obiekt XMLDOMAttribute
W DOM W3C, jak i w DOM Microsoftu obiekty atrybutów to obiekty węzłów (czyli są oparte na obiekcie node), nie są one jednak węzłem dzieckiem elementu i nie traktuje się ich jako części drzewa dokumentu. Atrybuty traktuje się jako właściwości elementów, z którymi są związane (oznacza to, że właściwości takie jak parentNode, previousSibling czy nextSibling dla atrybutów nie mają znaczenia). W tym rozdziale przyjrzymy się też, jak się atrybutów używa.
Oto właściwości tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu; druga kolumna oznacza rodzaj właściwości: O=tylko do odczytu, OZ=do odczytu i zapisu):
Obiekt |
O/Z |
Opis |
attributes |
O |
Lista atrybutów węzła. |
baseName* |
O |
Bazowa nazwa kwalifikowana przestrzenią nazw. |
childNodes |
O |
Lista węzłów zawierająca węzły dzieci. |
dataType* |
OZ |
Typ danych w węźle. |
definition* |
O |
Definicja węzła w DTD lub schemacie. |
firstChild |
O |
Pierwsze dziecko bieżącego węzła. |
lastChild |
O |
Ostatnie dziecko bieżącego węzła. |
name |
O |
Nazwa atrybutu. |
namespaceURI* |
O |
Adres URI przestrzeni nazw. |
nextSibling |
O |
Następny węzeł bliźniaczy węzła bieżącego. |
nodeName |
O |
Kwalifikowana nazwa elementu, atrybutu lub odwołania do encji, w innych przypadkach napis. |
nodeType |
O |
Rodzaj węzła XML DOM. |
nodeTypedValue* |
OZ |
Wartość węzła. |
nodeTypeString* |
O |
Typ węzła w postaci napisu. |
nodeValue |
OZ |
Tekst związany z węzłem. |
onwerDocument |
O |
Węzeł główny dokumentu. |
parentNode |
O |
Węzeł rodzic (tylko w przypadku węzłów mających rodzica). |
parsed* |
O |
Jeśli węzeł i wszyscy jego potomkowie byli już parsowani, ma wartość true. |
prefix* |
O |
Przedrostek przestrzeni nazw. |
previousSibling |
O |
Poprzedni węzeł bliźniaczy węzła bieżącego. |
specified |
O |
Wskazuje, czy wartość węzła (zwykle atrybutu) podana została jawnie, czy określono ją na podstawie wartości domyślnej. |
text |
OZ |
Tekstowa zawartość węzła i jego poddrzewka. |
value |
OZ |
Wartość atrybutu. |
xml |
O |
Węzeł i wszyscy jego potomkowie w postaci kodu XML. |
Oto metody tego obiektu:
Metoda |
Opis |
appendChild |
Dodaje nowe dziecko jako ostatnie dziecko danego węzła. |
cloneNode |
Zwraca nowy węzeł będący kopią węzła bieżącego. |
hasChildNodes |
Jeśli węzeł ma dzieci, ma wartość true. |
insertBefore |
Wstawia węzeł dziecko przed węzłem bieżącym. |
removeChild |
Usuwa dany węzeł dziecko z listy. |
replaceChild |
Podmienia dany węzeł dziecko na inny nowy węzeł. |
selectNodes |
Stosuje podaną operację dopasowania wzorca do kontekstu węzła, zwraca listę dopasowanych węzłów. |
selectSingleNode |
Stosuje podaną operację dopasowania wzorca do kontekstu węzła, zwraca pierwszy dopasowany węzeł. |
transformNode |
Przekształca węzeł i jego dzieci zgodnie z podanym arkuszem stylów XSL. |
transformNodeToObject |
Przekształca węzeł i jego dzieci zgodnie z podanym arkuszem stylów XSL, zwraca obiekty wynikowy. |
Z obiektem tym nie są związane żadne zdarzenia.
Obiekt XMLDOMElement
Obiekty XMLDOMElement reprezentują elementy i są zapewne najczęściej spotykanymi obiektami węzłów. Jako że atrybuty nie są traktowane jako węzły dzieci węzłów elementów, do pobierania atrybutów używa się specjalnych metod - na przykład getAttribute, która zwraca XMLDOMNameNodeMap zawierający wszystkie atrybuty elementu.
Oto właściwości tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu; druga kolumna oznacza rodzaj właściwości: O=tylko do odczytu, OZ=do odczytu i zapisu):
Obiekt |
O/Z |
Opis |
attributes |
O |
Lista atrybutów danego węzła. |
baseName* |
O |
Bazowa nazwa kwalifikowana przestrzenią nazw. |
childNodes |
O |
Lista węzłów zawierająca dzieci. |
dataType* |
OZ |
Typ danych węzła. |
definition* |
O |
Definicja węzła w DTD lub schemacie. |
firstChild |
O |
Pierwsze dziecko danego węzła. |
lastChild |
O |
Ostatnie dziecko danego węzła. |
namespaceURI* |
O |
Adres URI przestrzeni nazw. |
nextSibling |
O |
Następny węzeł bliźniaczy węzła bieżącego. |
nodeName |
O |
Kwalifikowana nazwa elementu, atrybutu lub odwołania do encji, w przypadku innych typów węzłów napis. |
nodeType |
O |
Określenie typu węzła DOM XML. |
nodeTypeString* |
O |
Typ węzła w postaci napisu. |
nodeValue |
OZ |
Tekst związany z węzłem. |
ownerDocument |
O |
Węzeł główny dokumentu. |
parentNode |
O |
Węzeł rodzic węzła bieżącego. |
parsed* |
O |
Jeśli węzeł i wszyscy jego potomkowie już byli parsowani, ma wartość true. |
prefix* |
O |
Przedrostek przestrzeni nazw. |
previousSibling |
O |
Poprzedni element bliźniaczy danego węzła. |
specified* |
O |
Podaje, czy wartość węzła określona została jawnie, czy określono ją na podstawie wartości domyślnej. |
tagName |
O |
Nazwa elementu. |
text* |
OZ |
Zawiera treść tekstu węzła i jego poddrzewek. |
xml* |
O |
Zawiera reprezentację kodu XML odpowiadającego węzłowi i wszystkim jego potomkom. |
Oto metody tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu):
Metoda |
Opis |
appendChild |
Dodaje nowe dziecko jako ostatnie dziecko węzła bieżącego. |
cloneNode |
Zwraca nowy węzeł będący kopią węzła bieżącego. |
getAttribute |
Pobiera wartość atrybutu o podanej nazwie. |
getAttributeNode |
Pobiera węzeł atrybutu o podanej nazwie. |
getElementsByTagName |
Zwraca listę wszystkich elementów potomków o podanej nazwie. |
hasChildNodes |
Jeśli węzeł ma dzieci, zwraca true. |
insertBefore |
Wstawia węzeł dziecko przed danym węzłem. |
normalize |
Normalizuje wszystkie elementy potomne łącząc dwa lub więcej kolejnych węzłów tekstowych w pojedynczy węzeł tekstowy. |
removeAttribute |
Usuwa lub przenosi atrybut o podanej nazwie. |
removeAttributeNode |
Usuwa dany atrybut z elementu. |
removeChild |
Usuwa dany węzeł dziecko. |
replaceChild |
Zamienia dany węzeł dziecko na podany nowy węzeł. |
selectNodes* |
Stosuje podaną operację dopasowania wzorca do kontekstu węzła, zwraca listę dopasowanych węzłów. |
selectSingleNode* |
Stosuje podaną operację dopasowania wzorca do kontekstu węzła, zwraca pierwszy dopasowany węzeł. |
setAttribute |
Ustawia wartość atrybutu o podanej nazwie. |
setAttributeNode |
Dodaje lub zmienia dany węzeł atrybutu na podany. |
transformNode* |
Przekształca dany węzeł i jego dzieci zgodnie z danym arkuszem stylów XSL. |
transformNodeToObject* |
Przekształca dany węzeł i jego dzieci zgodnie z podanym arkuszem stylów, zwraca obiekt powstały w wyniku tego przekształcenia. |
Z obiektem tym nie są związane żadne zdarzenia.
Obiekt XMLDOMText
Obiekt XMLDOMText zawiera tekstową zawartość elementu lub atrybutu. Jeśli w elemencie nie znajdują się żadne znaczniki, a tylko tekst, element zawierał będzie jeden tylko węzeł - węzeł tekstowy z całością danych znakowych (w przypadku elementów o zawartości mieszanej węzły tekstowe mogą mieć węzły bliźniacze elementów).
Podczas pierwszego udostępniania dokumentu w DOM XML cały tekst jest znormalizowany, co oznacza, że każdemu blokowi tekstu odpowiada jeden obiekt tekstu. Węzły tekstowe można tworzyć także tak, aby do siebie przylegały, choć nie będą one wczytane jako osobne przy następnym otwarciu dokumentu (warto zaznaczyć, że obiekt XMLDOMElement ma metodę normalize, który łączy przylegające do siebie węzły tekstowe w pojedynczy węzeł.
Oto właściwości tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu; druga kolumna oznacza rodzaj właściwości: O=tylko do odczytu, OZ=do odczytu i zapisu):
Obiekt |
O/Z |
Opis |
attributes |
O |
Lista atrybutów węzła. |
baseName* |
O |
Bazowa nazwa kwalifikowana przestrzenią nazw. |
childNodes |
O |
Lista węzłów zawierająca węzły dzieci. |
data |
OZ |
Dane węzła (faktyczna zawartość węzła zależy od jego rodzaju). |
dataType* |
OZ |
Rodzaj danych węzła. |
definition* |
O |
Definicja węzła w DTD lub schemacie. |
firstChild |
O |
Pierwsze dziecko węzła bieżącego. |
lastChild |
O |
Ostatnie dziecko węzła bieżącego. |
length |
O |
Długość danych w znakach. |
namespaceURI* |
O |
Adres URI przestrzeni nazw. |
nextSibling |
O |
Następny węzeł bliźniaczy węzła danego. |
nodeName |
O |
Kwalifikowana nazwa elementu, atrybutu lub odwołania do encji. w przypadku innych typów węzłów napis. |
nodeType |
O |
Typ węzła według DOM XML. |
nodeTypedValue* |
OZ |
Wartość węzła. |
nodeTypeString* |
O |
Typ węzła w postaci napisu. |
nodeValue |
OZ |
Tekst związany z węzłem. |
ownerDocument |
O |
Węzeł główny dokumentu. |
parentNode |
O |
Węzeł rodzic. |
parsed* |
O |
Jeśli węzeł i wszyscy jego potomkowie byli już parsowani, zawiera wartość true. |
prefix* |
O |
Przedrostek przestrzeni nazw. |
previousSibling |
O |
Poprzedni węzeł bliźniaczy węzła danego. |
specified |
O |
Informuje, czy wartość danego węzła podano jawnie, czy została ona określona na podstawie wartości domyślnej. |
text* |
OZ |
Tekstowa zawartość węzła i jego poddrzewka. |
xml* |
O |
Węzeł i jego potomkowie w postaci kodu XML. |
Oto metody tego obiektu (gwiazdką oznaczono rozszerzenia Microsoftu):
Metoda |
Opis |
appendChild |
Dodaje nowe dziecko jako ostatnie dziecko bieżącego węzła. |
appendData |
Dodaje podany napis do istniejących już danych. |
cloneNode |
Zwraca nowy węzeł będący kopią węzła bieżącego. |
deleteData |
Usuwa podany napis z danych. |
hasChildNodes |
Jeśli węzeł ma dzieci, zwraca true. |
insertBefore |
Przed wskazanym węzłem wstawia węzeł dziecko. |
insertData |
Wstawia podany napis na wskazanej pozycji w danych. |
removeChild |
Usuwa podany węzeł dziecko z listy dzieci. |
replaceChild |
Podmienia podany węzeł dziecko na nowy węzeł. |
selectNodes* |
--> Stosuje podaną operację dopasowania wzorca do kontekstu węzła, zwraca listę dopasowanych węzłów.[Author:T] |
selectSingleNode* |
--> Stosuje podaną operację dopasowania wzorca do kontekstu węzła, zwraca pierwszy dopasowany węzeł.[Author:T] |
specified* |
--> Określa, czy wartość danego węzła podano jawnie, czy też określono ją na podstawie wartości domyślnej.[Author:T] |
splitText |
Rozbija węzeł tekstowy na dwa węzły tekstowe. |
substringData |
Zwraca część napisu danych. |
transformNode* |
Przekształca dany węzeł i jego dzieci zgodnie z danym arkuszem stylów XSL. |
transformNodeToObject* |
Przekształca dany węzeł i jego dzieci zgodnie z podanym arkuszem stylów, zwraca obiekt powstały w wyniku tego przekształcenia. |
Z obiektem tym nie są związane żadne zdarzenia.
I tak oto zapoznaliśmy się z najważniejszymi obiektami modelu DOM XML Microsoftu. Teraz czas tę wiedzę wykorzystać, co zajmie nam już resztę tego rozdziału. Zaczniemy od samego początku, czyli od ładowania dokumentu XML.
Ładowanie dokumentów XML
Pierwszym krokiem jest załadowanie z kodu dokumentu XML do Internet Explorera i utworzenie obiektu dokumentu. Za pomocą tego obiektu będziemy w stanie do tego dokumentu dowolnie sięgać.
Jak już wspomniano wcześniej, dokument XML do Internet Explorera można załadować na dwa sposoby tak, aby móc z niego korzystać za pomocą JavaScriptu. Aby sprawdzić, jak to wszystko działa, użyjemy dokumentu spotkania.xml, w którym opisano spotkania w interesach wraz z osobami obecnymi i z datami:
<?xml version="1.0" encoding="iso-8859-2"?>
<SPOTKANIA>
<SPOTKANIE TYP="nieformalne">
<TYTUŁ>XML w praktycznych zastosowaniach</TYTUŁ>
<NUMER>2079</NUMER>
<TEMAT>XML</TEMAT>
<DATA>6/1/2002</DATA>
<OSOBY>
<OSOBA STATUS="obecna">
<IMIE>Edward</IMIE>
<NAZWISKO>Samson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="nieobecna">
<IMIE>Ernestyna</IMIE>
<NAZWISKO>Johnson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="obecna">
<IMIE>Betty</IMIE>
<NAZWISKO>Richardson</NAZWISKO>
</OSOBA>
</OSOBY>
</SPOTKANIE>
</SPOTKANIA>
Pierwsza metoda ładowania dokumentu XML do Internet Explorera to utworzenie obiektu document przy użyciu klasy Microsoft.XMLDOM.
Aby zobaczyć, jak to działa, utworzymy przykład odczytujący plik spotkania.xml i pobierający dane trzeciej osoby z dokumentu (Betty Richardson). Zaczynamy od utworzenia nowego obiektu dokumentu za pomocą operatora new:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
.
.
.
</HEAD>
</HTML>
Teraz możemy dokument spotkania.xml załadować:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
.
.
.
</HEAD>
</HTML>
Następnym krokiem będzie pobranie obiektu węzła odpowiadającego elementowi głównemu dokumentu, czyli SPOTKANIA. Użyjemy do tego metody documentElement:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
meetingsNode = xmldoc.documentElement
.
.
.
</HEAD>
</HTML>
Teraz już możemy dowolnie hasać po dokumencie stosując metody firstChild, nextChild, previousChild i lastChild, które umożliwiają dostęp do elementów dzieci, oraz metody firstSibling, nextSibling, previousSibling i lastSibling umożliwiające sięgnięcie do elementów na takim samym poziomie zagnieżdżenia (elementów bliźniaczych). Na przykład element SPOTKANIE jest pierwszym dzieckiem elementu głównego SPOTKANIA, więc do sięgnięcia do niego odpowiednia będzie metoda firstChild:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
meetingsNode = xmldoc.documentElement
meetingNode = meetingsNode.firstChild
.
.
.
</HEAD>
</HTML>
Chcemy wybrać trzeci element OSOBA z elementu OSOBY. OSOBY to ostatnie dziecko elementu SPOTKANIE, zatem możemy się doń tak oto odwołać:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
meetingsNode = xmldoc.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
.
.
.
</HEAD>
</HTML>
Potrzebna jest nam trzecia osoba z elementu OSOBY, czyli ostatnie dziecko tego elementu - użyjemy zatem jeszcze raz metody lastChild:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
meetingsNode = xmldoc.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
.
.
.
</HEAD>
</HTML>
W końcu należałoby sięgnąć do imienia i nazwiska wybranej osoby - skorzystamy z metod firstChild i nextSibling:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
meetingsNode = xmldoc.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
.
.
.
</HEAD>
</HTML>
Tak więc jesteśmy już przy tych elementach, o które nam chodziło. Jednak interesują nas węzły tekstowe znajdujące się wewnątrz węzłów elementów IMIĘ i NAZWISKO, zatem należy się dostać do pierwszych dzieci tych elementów, a żeby odczytać sam tekst, użyć należy właściwości nodeValue.
Aby wyświetlić imię i nazwisko wybranej osoby, wygenerujemy nieco dynamicznego kodu HTML - użyjemy elementu DIV i jego właściwości innerHTML (zawiera ona tekst elementu DIV):
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
meetingsNode = xmldoc.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
outputText = "Trzecia osoba: " +
first_nameNode.firstChild.nodeValue + ' ' +
last_nameNode.firstChild.nodeValue
messageDIV.innerHTML = outputText
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Odczytywanie wartości elementów XML
</H1>
<INPUT TYPE="BUTTON" VALUE="Pobierz nazwisko trzeciej osoby"
ONCLICK="readXMLDocument()">
<P>
<DIV ID="messageDIV"></DIV>
</CENTER>
</BODY>
</HTML>
Dodaliśmy jeszcze przycisk, który uruchomi naszą funkcję readXMLDocument, a ta funkcja odczyta dokument i wyświetli żądane informacje.
Na rysunku 5.2 pokazano tę stronę w działaniu. Kiedy użytkownik klika przycisk, wczytywany jest dokument spotkania.xml, jest parsowany, odczytywane i wyświetlane są dane o trzeciej osobie - całkiem nieźle jak na początek.
Rysunek 5.2. Odczyt elementu XML w Internet Explorerze |
|
Użycie wysp danych XML
W Internet Explorerze 5 możesz też do włączenia danych XML do stron HTML użyć wysp danych XML. Explorer 5 obsługuje znacznik <XML> (nie należący do standardu HTML), który pozwala po prostu umieścić wewnątrz cały dokument XML:
<XML ID="pozdrowienia">
<DOKUMENT>
<POZDROWIENIA>Witamy XML!</POZDROWIENIA>
</DOKUMENT>
</XML>
Znacznik <XML> ma pewne atrybuty, o których warto wspomnieć:
Atrybut |
Opis |
ID |
Identyfikator, według którego do znacznika <XML> można się odwoływać w kodzie. Wartością jest napis ASCII. |
NS |
Adres URI przestrzeni nazw XML używanej we wstawianym dokumencie XML. |
PREFIX |
Przedrostek przestrzeni nazw treści XML. Wartością jest napis ASCII. |
SRC |
Jeśli używany jest zewnętrzny dokument XML, podaje się tu jego adres URI. |
Kiedy używasz elementu XML, w kodzie odwołujesz się do niego stosując identyfikator ID. Aby sięgnąć do elementu, można użyć kolekcji all przekazując identyfikator elementu, w powyższym przykładzie będzie to document.all("pozdrowienia"). Aby pobrać obiekt dokumentu odpowiadający tak wczytanemu dokumentowi XML, można użyć właściwości XMLDocument. Oto jak należy przekształcić poprzedni przykład, aby zamiast obiektu Microsoft.XMLDOM użyć wysp danych:
<HTML>
<HEAD>
<TITLE>
Użycie wysp danych XML do odczytu wartości elementów
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
xmldoc = document.all("meetingsXML").XMLDocument
meetingsNode = xmldoc.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
outputText = "Trzecia osoba: " +
first_nameNode.firstChild.nodeValue + ' ' +
last_nameNode.firstChild.nodeValue
messageDIV.innerHTML = outputText
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Użycie wysp danych XML do odczytu wartości elementów
</H1>
<INPUT TYPE="BUTTON" VALUE="Pobierz nazwisko trzeciej osoby"
ONCLICK="readXMLDocument()">
<P>
<DIV ID="messageDIV"></DIV>
</CENTER>
</BODY>
</HTML>
Spójrz na rysunek 5.3 - ten przykład działa tak samo, jak poprzedni.
Rysunek 5.3. Użycie wysp danych XML w Internet Explorerze |
|
W ostatnim przykładzie użyliśmy zewnętrznego dokumentu XML, spotkania.xml, do jego odczytania użyliśmy atrybutu SRC znacznika <XML>. Można jednak w elemencie XML zamknąć także cały dokument:
<HTML>
<HEAD>
<TITLE>
Użycie wysp danych XML do odczytu wartości elementów
</TITLE>
<XML ID="meetingsXML">
<?xml version="1.0" encoding="iso-8859-2"?>
<SPOTKANIA>
<SPOTKANIE TYP="nieformalne">
<TYTUŁ>XML w praktycznych zastosowaniach</TYTUŁ>
<NUMER>2079</NUMER>
<TEMAT>XML</TEMAT>
<DATA>6/1/2002</DATA>
<OSOBY>
<OSOBA STATUS="obecna">
<IMIE>Edward</IMIE>
<NAZWISKO>Samson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="nieobecna">
<IMIE>Ernestyna</IMIE>
<NAZWISKO>Johnson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="obecna">
<IMIE>Betty</IMIE>
<NAZWISKO>Richardson</NAZWISKO>
</OSOBA>
</OSOBY>
</SPOTKANIE>
</SPOTKANIA>
</XML>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
xmldoc = document.all("meetingsXML").XMLDocument
meetingsNode = xmldoc.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
outputText = "Trzecia osoba: " +
first_nameNode.firstChild.nodeValue + ' ' +
last_nameNode.firstChild.nodeValue
messageDIV.innerHTML = outputText
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Użycie wysp danych XML do odczytu wartości elementów
</H1>
<INPUT TYPE="BUTTON" VALUE="Pobierz nazwisko trzeciej osoby"
ONCLICK="readXMLDocument()">
<P>
<DIV ID="messageDIV"></DIV>
</CENTER>
</BODY>
</HTML>
Jak dotąd do pobrania obiektu dokumentu używaliśmy właściwości XMLDocument obiektu odpowiadającego wyspie danych XML, można jednak użyć też bezpośrednio właściwości documentElement wyspy danych:
<HTML>
<HEAD>
<TITLE>
Użycie wysp danych XML do odczytu wartości elementów
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
meetingsNode = meetingsXML.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
.
.
.
</HTML>
Pobieranie elementów według nazwy
Jak na razie używaliśmy metod nawigacji po dokumencie takich, jak nextSibling czy nextChild. Można jednak do konkretnych elementów odwoływać się przez ich nazwę. Oto przykład; użyjemy metody getElementsByTagName obiektu document, aby uzyskać listę wszystkich obiektów elementów o danej nazwie. Będziemy szukać konkretnie elementów IMIĘ i NAZWISKO, więc użyjemy następującego kodu:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function loadDocument()
{
var xmldoc, listNodesFirstName, listNodesLastName
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
listNodesFirstName = xmldoc.getElementsByTagName("IMIĘ")
listNodesLastName = xmldoc.getElementsByTagName("NAZWISKO")
.
.
.
</HTML>
Tak jak wszystkie listy węzłów, listy listNodesFirstName i listNodesLastName indeksuje się zaczynając od 0, zatem trzeci element będzie miał numer 2, więc odwoływać się do niego będziemy listNodesLastName.item(2) (pamiętaj, że musimy znaleźć pierwsze dzieci węzłów elementów IMIĘ i NAZWISKO, które są węzłami tekstowymi wywoływanymi metodą firstChild).
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości elementów XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function loadDocument()
{
var xmldoc, listNodesFirstName, listNodesLastName
var outputText
xmldoc = new ActiveXObject("Microsoft.XMLDOM")
xmldoc.load("spotkania.xml")
listNodesFirstName = xmldoc.getElementsByTagName("IMIĘ")
listNodesLastName = xmldoc.getElementsByTagName("NAZWISKO")
outputText = "Trzecia osoba: " +
listNodesFirstName.item(2).firstChild.nodeValue + ' ' +
listNodesLastName.item(2).firstChild.nodeValue
messageDIV.innerHTML = outputText
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Odczytywanie wartości elementów XML
</H1>
<INPUT TYPE="BUTTON" VALUE="Pobierz nazwisko trzeciej osoby"
ONCLICK="loadDocument()">
<P>
<DIV ID="messageDIV"></DIV>
</CENTER>
</BODY>
</HTML>
Już nieco wiemy o użyciu XML, jesteśmy w stanie dokumenty XML wczytywać na różne sposoby i sięgać do poszczególnych elementów w dokumencie. Teraz czas przejść krok dalej - zamiast sięgać do zawartości tekstowej elementów odczytywać ich atrybuty.
Pobieranie wartości atrybutów
Aby zobaczyć, jak odczytywać wartości atrybutów dokumentów XML, przykładowo odczytywać będziemy wartość atrybutu STATUS trzeciej osoby z dokumentu spotkania.xml:
<?xml version="1.0" encoding="iso-8859-2"?>
<SPOTKANIA>
<SPOTKANIE TYP="nieformalne">
<TYTUŁ>XML w praktycznych zastosowaniach</TYTUŁ>
<NUMER>2079</NUMER>
<TEMAT>XML</TEMAT>
<DATA>6/1/2002</DATA>
<OSOBY>
<OSOBA STATUS="obecna">
<IMIE>Edward</IMIE>
<NAZWISKO>Samson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="nieobecna">
<IMIE>Ernestyna</IMIE>
<NAZWISKO>Johnson</NAZWISKO>
</OSOBA>
<OSOBA STATUS="obecna">
<IMIE>Betty</IMIE>
<NAZWISKO>Richardson</NAZWISKO>
</OSOBA>
</OSOBY>
</SPOTKANIE>
</SPOTKANIA>
Jak się odczytuje wartości atrybutów? Zaczynamy od pozyskania obiektu nazwanej mapy węzłów z atrybutami interesującego nas węzła. W tym przypadku interesuje nas trzeci element OSOBA, mapę jego węzłów pobieramy następująco:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości atrybutów z dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
var attributes
xmldoc = document.all("meetingsXML").XMLDocument
meetingsNode = meetingsXML.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
attributes = personNode.attributes
.
.
.
</HTML>
Teraz stosując do tak uzyskanej mapy metodę getNamedItem możemy pobrać wartość atrybutu STATUS:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości atrybutów z dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
var attributes, attendancePerson
xmldoc = document.all("meetingsXML").XMLDocument
meetingsNode = meetingsXML.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
attributes = personNode.attributes
attendancePerson = attributes.getNamedItem("STATUS")
.
.
.
</HTML>
Teraz mamy już węzeł odpowiadający atrybutowi STATUS, wartość atrybutu pobrać możemy stosując właściwość value (węzły atrybutów nie mają wewnętrznych węzłów tekstowych):
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości atrybutów z dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
var attributes, attendancePerson
xmldoc = document.all("meetingsXML").XMLDocument
meetingsNode = meetingsXML.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
attributes = personNode.attributes
attendancePerson = attributes.getNamedItem("STATUS")
outputText = "Trzecia osoba: " +
first_nameNode.firstChild.nodeValue + ' ' +
last_nameNode.firstChild.nodeValue +
" - " + attendancePerson.value
messageDIV.innerHTML = outputText
.
.
.
</HTML>
I to już wszystko, oto kompletna strona HTML:
<HTML>
<HEAD>
<TITLE>
Odczytywanie wartości atrybutów z dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function readXMLDocument()
{
var xmldoc, meetingsNode, meetingNode, peopleNode
var personNode, first_nameNode, last_nameNode, outputText
var attributes, attendancePerson
xmldoc = document.all("meetingsXML").XMLDocument
meetingsNode = meetingsXML.documentElement
meetingNode = meetingsNode.firstChild
peopleNode = meetingNode.lastChild
personNode = peopleNode.lastChild
first_nameNode = personNode.firstChild
last_nameNode = first_nameNode.nextSibling
attributes = personNode.attributes
attendancePerson = attributes.getNamedItem("STATUS")
outputText = "Trzecia osoba: " +
first_nameNode.firstChild.nodeValue + ' ' +
last_nameNode.firstChild.nodeValue +
" - " + attendancePerson.value
messageDIV.innerHTML = outputText
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Odczytywanie atrybutów z dokumentów XML
</H1>
<INPUT TYPE="BUTTON" VALUE="Pobierz informacje o trzeciej osobie"
ONCLICK="readXMLDocument()">
<P>
<DIV ID="messageDIV"></DIV>
</CENTER>
</BODY>
</HTML>
Na rysunku 5.4 pokazano wyniki - trzecia osoba była na spotkaniu obecna.
Rysunek 5.4. Odczytywanie wartości atrybutów w Internet Explorerze |
|
Parsowanie dokumentów XML w kodzie
Jak dotąd wybieraliśmy z dokumentu różne konkretne elementy, można jednak dokumenty obsługiwać także inaczej. Można na przykład dokument parsować, czyli odczytywać go i interpretować, cały dokument na raz. W ramach przykładu przetworzymy cały dokument spotkania.xml i wyświetlimy wszystkie jego węzły na stronie HTML.
W celu obsługi dokumentu utworzymy funkcję iterateChildren, która odczyta i wyświetli wszystkie dzieci danego węzła. Tak jak w większości innych parserów, jest to funkcja rekurencyjna, czyli taka, która sama się wywołuje dla kolejnych dzieci przetwarzanego węzła. Aby pobrać nazwę węzła, używamy właściwości nodeName węzła. W celu parsowania całego dokumentu wystarczy naszej funkcji przekazać węzeł główny całego dokumentu, a przetworzone zostanie całe drzewo i wyświetlone zostaną wszystkie węzły:
<HTML>
<HEAD>
<TITLE>
Parsowanie dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function parseDocument()
{
documentXML = document.all("meetingsXML").XMLDocument
resultsDIV.innerHTML = iterateChildren(documentXML, "")
}
.
.
.
Zwróć uwagę, że dodatkowo funkcji iterateChildren przekazano pusty napis (""). Parametru tego używamy do robienia odpowiednich wcięć poszczególnych poziomów elementów, dzięki czemu widać będzie, które elementy są w których zagnieżdżane. Zaczynamy od utworzenia nowego napisu składającego się z bieżącego wcięcia (zaczynamy od ciągu pustego - brak wcięcia, później użyjemy odpowiedniej liczby spacji), nazwy bieżącego węzła i elementu <BR>, dzięki któremu przeglądarka przesunie się do następnego wiersza:
<HTML>
<HEAD>
<TITLE>
Parsowanie dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function parseDocument()
{
documentXML = document.all("meetingsXML").XMLDocument
resultsDIV.innerHTML = iterateChildren(documentXML, "")
}
function iterateChildren(theNode, indentSpacing)
{
var text = indentSpacing + theNode.nodeName + "<BR>"
.
.
.
return text
}
</SCRIPT>
</HEAD>
.
.
.
Dzieci bieżącego węzła możemy odczytać korzystając z właściwości childNodes, która zawiera listę węzłów dzieci węzła bieżącego. Liczbę dzieci można określić sprawdzając długość tej listy - właściwość length; jeśli jakieś dzieci są, wywołujemy iterateChildren dla wszystkich węzłów dzieci (zwróć uwagę na to, że następny poziom węzłów otrzymuje większe wcięcie - dodatkowe cztery spacje nierozdzielające dostępne jako odwołanie do encji HTML ):
<HTML>
<HEAD>
<TITLE>
Parsowanie dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function parseDocument()
{
documentXML = document.all("meetingsXML").XMLDocument
resultsDIV.innerHTML = iterateChildren(documentXML, "")
}
function iterateChildren(theNode, indentSpacing)
{
var text = indentSpacing + theNode.nodeName + "<BR>"
if (theNode.childNodes.length > 0) {
for (var loopIndex = 0; loopIndex <
theNode.childNodes.length; loopIndex++) {
text += iterateChildren(theNode.childNodes(loopIndex),
indentSpacing + " ")
}
}
return text
}
</SCRIPT>
</HEAD>
.
.
.
I to już właściwie wszystko, oto gotowa strona sieciowa:
<HTML>
<HEAD>
<TITLE>
Parsowanie dokumentu XML
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function parseDocument()
{
documentXML = document.all("meetingsXML").XMLDocument
resultsDIV.innerHTML = iterateChildren(documentXML, "")
}
function iterateChildren(theNode, indentSpacing)
{
var text = indentSpacing + theNode.nodeName + "<BR>"
if (theNode.childNodes.length > 0) {
for (var loopIndex = 0; loopIndex <
theNode.childNodes.length; loopIndex++) {
text += iterateChildren(theNode.childNodes(loopIndex),
indentSpacing + " ")
}
}
return text
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Parsowanie dokumentu XML
</H1>
</CENTER>
<CENTER>
<INPUT TYPE="BUTTON" VALUE="Parsowanie i wyświetlenie dokumentu"
ONCLICK="parseDocument()">
</CENTER>
<DIV ID="resultsDIV"></DIV>
</BODY>
</HTML>
Kiedy klikniesz znajdujący się na stronie przycisk, odczytany zostanie plik spotkania.xml i wyświetlona zostanie jego struktura, jak to pokazano na rysunku 5.5. Pokazano wszystkie węzły z odpowiednimi wcięciami. Zwróć uwagę na dodatkowe „metanazwy” wstawione przez Internet Explorera do węzłów dokumentu i tekstowych: #document oraz #text.
Rysunek 5.5. Parsowanie dokumentu w Internet Explorerze |
|
Parsowanie dokumentu XML w celu wyświetlenia typu i zawartości węzła
Kod z poprzedniego przykładu wyliczał nazwy wszystkich węzłów dokumentu spotkania.xml. Można jednak zrobić jeszcze więcej - można użyć właściwości nodeValue do wypisania wartości poszczególnych węzłów i tym się zajmiemy w tym punkcie. Sprawdzając właściwość nodeType można też odczytać typy poszczególnych węzłów - oto dopuszczalne wartości:
Wartość |
Opis |
1 |
element |
2 |
atrybut |
3 |
tekst |
4 |
sekcja CDATA |
5 |
odwołanie do encji |
6 |
encja |
7 |
instrukcja przetwarzania |
8 |
komentarz |
9 |
dokument |
10 |
typ dokumentu |
11 |
fragment dokumentu |
12 |
notacja |
Oto jak się określa rodzaj danego węzła przy pomocy instrukcji JavaScriptu switch, którą poznaliśmy w poprzednim rozdziale:
<HTML>
<HEAD>
<TITLE>
Parsowanie dokumentu XML, wyświetlanie typów i zawartości węzłów
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function parseDocument()
{
documentXML = document.all("meetingsXML").XMLDocument
resultsDIV.innerHTML = iterateChildren(documentXML, "")
}
function iterateChildren(theNode, indentSpacing)
{
var typeData
switch (theNode.nodeType) {
case 1:
typeData = "element"
break
case 2:
typeData = "atrybut"
break
case 3:
typeData = "tekst"
break
case 4:
typeData = "sekcja CDATA"
break
case 5:
typeData = "odwołanie do encji"
break
case 6:
typeData = "encja"
break
case 7:
typeData = "instrukcja przetwarzania"
break
case 8:
typeData = "komentarz"
break
case 9:
typeData = "dokument"
break
case 10:
typeData = "typ dokumentu"
break
case 11:
typeData = "fragment dokumentu"
break
case 12:
typeData = "notacja"
break
}
.
.
.
Jeśli węzeł ma niepustą wartość (sprawdza się to porównując nodeValue z wartością null), to wartość tę można wyświetlić:
<HTML>
<HEAD>
<TITLE>
Parsowanie dokumentu XML, wyświetlanie typów i zawartości węzłów
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function parseDocument()
{
documentXML = document.all("meetingsXML").XMLDocument
resultsDIV.innerHTML = iterateChildren(documentXML, "")
}
function iterateChildren(theNode, indentSpacing)
{
var typeData
switch (theNode.nodeType) {
case 1:
typeData = "element"
break
case 2:
typeData = "atrybut"
break
case 3:
typeData = "tekst"
break
case 4:
typeData = "sekcja CDATA"
break
case 5:
typeData = "odwołanie do encji"
break
case 6:
typeData = "encja"
break
case 7:
typeData = "instrukcja przetwarzania"
break
case 8:
typeData = "komentarz"
break
case 9:
typeData = "dokument"
break
case 10:
typeData = "typ dokumentu"
break
case 11:
typeData = "fragment dokumentu"
break
case 12:
typeData = "notacja"
break
}
var text = indentSpacing + theNode.nodeName + "<BR>"
if (theNode.nodeValue != null) {
text = indentSpacing + theNode.nodeName
+ " = " + theNode.nodeValue
+ " (typ węzła: " + typeData
+ ")<BR>"
}
else {
text = indentSpacing + theNode.nodeName
+ " (Typ węzła: " + typeData
+ ")<BR>"
}
if (theNode.childNodes.length > 0) {
for (var loopIndex = 0; loopIndex <
theNode.childNodes.length; loopIndex++) {
text += iterateChildren(theNode.childNodes(loopIndex),
indentSpacing + " ")
}
}
return text
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Parsowanie dokumentu XML, wyświetlanie typów i zawartości węzłów
</H1>
</CENTER>
<CENTER>
<INPUT TYPE="BUTTON" VALUE="Parsowanie dokumentu, opisanie węzłów"
ONCLICK="parseDocument()">
</CENTER>
<DIV ID="resultsDIV"></DIV>
</BODY>
</HTML>
I to już wszystko - wyniki pokazano na rysunku 5.6. Pokazany jest cały dokument, a w nim typy wszystkich węzłów. Jeśli tylko któryś węzeł ma wartość, to wartość ta jest wyświetlana.
Rysunek 5.6. Użycie JavaScriptu do wyświetlania zawartości elementów i ich typu |
|
W przykładzie tym pokazano wszystkie elementy dokumentu, ale przecież niektóre z nich mają jeszcze atrybuty i teraz czas się nimi zająć.
Parsowanie dokumentu XML w celu wyświetlenia wartości atrybutów
Do atrybutów każdego elementu można dostać się stosując właściwość attributes. Nazwy atrybutów i ich wartości odczytać można za pomocą właściwości name i value obiektów atrybutów, zresztą właściwości value używaliśmy już wcześniej w tym rozdziale. Warto też pamiętać, że z uwagi na to, że atrybuty same też są węzłami, można też użyć ich właściwości nodeName i nodeValue; zaraz zobaczysz, jak to działa.
Tym razem zmodyfikujemy nieco poprzedni przykład dodając analizę w pętli także atrybutów i ich wyświetlanie (pamiętaj, że właściwości name i value można używać wymiennie z nodeName i nodeValue).
<HTML>
<HEAD>
<TITLE>
Parsowanie dokumentu XML, wyświetlanie typów i zawartości węzłów
</TITLE>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
function parseDocument()
{
documentXML = document.all("meetingsXML").XMLDocument
resultsDIV.innerHTML = iterateChildren(documentXML, "")
}
function iterateChildren(theNode, indentSpacing)
{
var typeData
switch (theNode.nodeType) {
case 1:
typeData = "element"
break
case 2:
typeData = "atrybut"
break
case 3:
typeData = "tekst"
break
case 4:
typeData = "sekcja CDATA"
break
case 5:
typeData = "odwołanie do encji"
break
case 6:
typeData = "encja"
break
case 7:
typeData = "instrukcja przetwarzania"
break
case 8:
typeData = "komentarz"
break
case 9:
typeData = "dokument"
break
case 10:
typeData = "typ dokumentu"
break
case 11:
typeData = "fragment dokumentu"
break
case 12:
typeData = "notacja"
break
}
var text = indentSpacing + theNode.nodeName + "<BR>"
if (theNode.nodeValue != null) {
text = indentSpacing + theNode.nodeName
+ " = " + theNode.nodeValue
+ " (typ węzła: " + typeData
+ ")"
}
else {
text = indentSpacing + theNode.nodeName
+ " (Typ węzła: " + typeData
+ ")"
}
if (theNode.attributes != null) {
if (theNode.attributes.length > 0) {
for (var loopIndex = 0; loopIndex <
theNode.attributes.length; loopIndex++) {
text += " (Atrybut: " +
theNode.attributes(loopIndex).nodeName +
" = \"" +
theNode.attributes(loopIndex).nodeValue
+ "\")"
}
}
}
text += "<BR>"
if (theNode.childNodes.length > 0) {
for (var loopIndex = 0; loopIndex <
theNode.childNodes.length; loopIndex++) {
text += iterateChildren(theNode.childNodes(loopIndex),
indentSpacing + " ")
}
}
return text
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Parsowanie dokumentu XML, wyświetlanie typów i zawartości węzłów
</H1>
</CENTER>
<CENTER>
<INPUT TYPE="BUTTON" VALUE="Parsowanie dokumentu, opisanie węzłów"
ONCLICK="parseDocument()">
</CENTER>
<DIV ID="resultsDIV"></DIV>
</BODY>
</HTML>
Wyniki pokazano na rysunku 5.7 - pokazane są zarówno elementy, jak i atrybuty.
Rysunek 5.7. Prezentacja w Internet Explorerze elementów i atrybutów |
|
Obsługa zdarzeń występujących podczas ładowania dokumentów
Internet Explorer umożliwia także śledzenie postępów ładowania dokumentu XML do przeglądarki. Można użyć między innymi zdarzeń onreadystatechange oraz ondataavailable. Właściwość readyState zdarzenia onreadystatechange informuje o bieżącym stanie dokumentu. Oto przykład pokazujący, jak to działa:
<HTML>
<HEAD>
<TITLE>
Obsługa zdarzeń ładowania dokumentu
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
var xmldoc
function loadDocument()
{
xmldoc = new ActiveXObject("microsoft.XMLDOM")
xmldoc.ondataavailable = dataAvailableHandler
xmldoc.onreadystatechange = stateChangeHandler
xmldoc.load('spotkania.xml')
}
function dataAvailableHandler()
{
messageDIV.innerHTML += "Stan: dane niedostępne.<BR>"
}
function stateChangeHandler()
{
switch (xmldoc.readyState)
{
case 1:
messageDIV.innerHTML +=
"Stan: dane nie zainicjalizowane.<BR>"
break
case 2:
messageDIV.innerHTML += "Stan: ładowanie danych.<BR>"
break
case 3:
messageDIV.innerHTML += "Stan: dane załadowane.<BR>"
break
case 4:
messageDIV.innerHTML +=
"Stan: zakończono ładowanie danych.<BR>"
if (xmldoc.parseError.errorCode != 0) {
messageDIV.innerHTML += "Stan: błąd.<BR>"
}
else {
messageDIV.innerHTML +=
"Stan: dane załadowano poprawnie.<BR>"
}
break
}
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Obsługa zdarzeń ładowania dokumentu
</H1>
</CENTER>
<CENTER>
<INPUT TYPE="BUTTON" VALUE="Załaduj dokument"
ONCLICK="loadDocument()">
</CENTER>
<DIV ID="messageDIV"></DIV>
</BODY>
</HTML>
Wynikiem jest strona pokazana na rysunku 5.8 - widać kolejne etapy ładowania dokumentu na stronę.
Rysunek 5.8. Monitorowanie zdarzeń ładowania dokumentu XML do Internet Explorera |
|
Walidacja dokumentów XML w Internet Explorerze
Domyślnie Internet Explorer podczas ładowania dokumentu XML automatycznie go waliduje, ale jeśli nie sprawdzisz ustawień obiektu parseError, błędów walidacji nie zobaczysz.
Włączanie i wyłączanie walidacji
Walidację dokumentu można włączać i wyłączać stosując właściwość validateOnParse obiektu document; jej wartość domyślna to true.
Oto przykład: ładujemy dokument XML error.xml. Dokument ten nie daje się walidować, gdyż element IMIĘNAZWISKO zadeklarowano jako zawierający jedynie element IMIĘ:
<?xml version="1.0" encoding="iso-8859-2" standalone="yes"?>
<!DOCTYPE DOKUMENT [
<!ELEMENT DOKUMENT (KLIENT)*>
<!ELEMENT KLIENT (IMIĘNAZWISKO,DATA,ZAMÓWIENIA)>
<!ELEMENT IMIĘNAZWISKO (IMIĘ)>
<!ELEMENT NAZWISKO (#PCDATA)>
<!ELEMENT IMIĘ (#PCDATA)>
<!ELEMENT DATA (#PCDATA)>
<!ELEMENT ZAMÓWIENIA (POZYCJA)*>
<!ELEMENT POZYCJA (PRODUKT,ILOŚĆ,CENA)>
<!ELEMENT PRODUKT (#PCDATA)>
<!ELEMENT ILOŚĆ (#PCDATA)>
<!ELEMENT CENA (#PCDATA)>
]>
<DOKUMENT>
<KLIENT>
<IMIĘNAZWISKO>
<NAZWISKO>Smith</NAZWISKO>
<IMIĘ>Sam</IMIĘ>
</IMIĘNAZWISKO>
<DATA>15 paĽdziernika 2001</DATA>
<ZAMÓWIENIA>
<POZYCJA>
<PRODUKT>Pomidory</PRODUKT>
<ILOŚĆ>8</ILOŚĆ>
<CENA>5zł</CENA>
</POZYCJA>
<POZYCJA>
<PRODUKT>Pomarańcze</PRODUKT>
<ILOŚĆ>24</ILOŚĆ>
<CENA>9.98zł</CENA>
</POZYCJA>
</ZAMÓWIENIA>
</KLIENT>
</DOKUMENT>
Oto strona, która odczytuje i sprawdza dokument - do analizy przyczyny błędu używamy właściwości errorCode, url, line, linepos, errorString i reason obiektu parseError:
<HTML>
<HEAD>
<TITLE>
Walidacja dokumentów
</TITLE>
<SCRIPT LANGUAGE="JavaScript">
var xmldoc
function loadDocument()
{
xmldoc = new ActiveXObject("microsoft.XMLDOM")
xmldoc.onreadystatechange = stateChangeHandler
xmldoc.ondataavailable = dataAvailableHandler
xmldoc.load('error.xml')
}
function dataAvailableHandler()
{
messageDIV.innerHTML += "Stan: dane dostępne.<BR>"
}
function stateChangeHandler()
{
if(xmldoc.readyState == 4) {
var errorString = xmldoc.parseError.srcText
errorString =
xmldoc.parseError.srcText.replace(/\</g, "<")
errorString = errorString.replace(/\>/g, ">")
if (xmldoc.parseError.errorCode != 0) {
messageDIV.innerHTML = "Problem z " +
xmldoc.parseError.url +
" wiersz " + xmldoc.parseError.line +
" pozycja " +xmldoc.parseError.linepos +
":<BR>Źródło błędu: " + errorString +
"<BR>" + xmldoc.parseError.reason +
"<BR>" + "Błąd: " +
xmldoc.parseError.errorCode
}
else {
messageDIV.innerHTML =
"Stan: załadowany dokument jest poprawny.<BR>"
}
}
}
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<H1>
Walidacja dokumentów
</H1>
</CENTER>
<DIV ID="messageDIV"></DIV>
<CENTER>
<INPUT TYPE="BUTTON" VALUE="Załadowanie dokumentu"
ONCLICK="loadDocument()">
</CENTER>
</BODY>
</HTML>
Na rysunku 5.9 pokazano wynik - zgłoszenie błędu walidacji.
Rysunek 5.9. Walidacja dokumentów w Internet Explorerze |
|
Być może zauważyłeś, że właściwość errorString zawiera fragment tekstu XML, który spowodował błąd. Problem jest z tekstem <NAZWISKO>Smith</NAZWISKO>, gdyż przeglądarka spróbuje zinterpretować występujące w nim znaczniki. Aby tego uniknąć, użyliśmy metody replace obiektu String do zamiany znaków < na < i > na > (metodzie replace przekazuje się wyrażenie regularne; zmiana < na < wymaga użycia wyrażenia /\</g; zmiana > na > wymaga użycia wyrażenia /\>/g).
Skrypty obsługi elementów XML
Internet Explorer udostępnia ograniczoną obsługę elementów XML. Można na przykład elementowi xlink z XHTML dodać atrybut onclick (standard XLinks będziemy omawiali później, w rozdziale 10).
<?xml version="1.0" encoding="iso-8859-2"?>
<?xml-stylesheet TYPE="text/css" href="xlink.css"?>
--> <html>[Author:T]
<head>
</head>
<body>
Czy chcesz zajrzeć do <xlink xml:link="simple"
inline="false" href="http://www.w3c.org"
onclick="location.href='http://www.w3c.org'">W3C</xlink>?
</body>
</html>
W arkuszu stylów xlink.css można nakazać, aby elementy xlink były wyświetlane na niebiesko i podkreślane, jak zwykłe łącza hipertekstowe; możemy także zmienić kształt kursora znajdującego się nad takim łączem na dłoń:
xlink {color: #0000FF; text-decoration: underline; cursor: hand}
Wyniki pokazano na rysunku 5.10: kiedy użytkownik kliknie element xlink, Internet Explorer uruchomi kod z atrybutu onclick. W pokazanym przykładzie załadowana zostanie strona http://www.w3c.org. Jak widać, w Explorerze można wiązać instrukcje z elementami XML - wystarczy dodać atrybuty zdarzeń, takie jak onclick.
Rysunek 5.10. Tworzenie „hiperłącza” w dokumencie XML w Internet Explorerze |
|
Edycja dokumentów XML w Internet Explorerze
W Internet Explorerze można zmieniać treść dokumentu XML. Używa się do tego metod takich, jak createElement, insertBefore, createTextNode i appendChild.
W ramach przykładu zmienimy dokument spotkania.xml wstawiając nowy element, PRZEWODNICZĄCY:
<?xml version="1.0" encoding="iso-8859-2"?>
<SPOTKANIA>
<SPOTKANIE TYP="nieformalne">
<PRZEWODNICZĄCY>Ted Bond</PRZEWODNICZĄCY>
<TYTUŁ>XML w praktycznych zastosowaniach</TYTUŁ>
<NUMER>2079</NUMER>
<TEMAT>XML</TEMAT>
<DATA>6/1/2002</DATA>
<OSOBY>
<OSOBA STATUS="obecna">
<IMIE>Edward</IMIE>
<NAZWISKO>Samson</NAZWISKO>
</OSOBA>
.
.
.
Zaczniemy od utworzenia nowego węzła odpowiadającego elementowi PRZEWODNICZĄCY i wstawienia go do dokumentu za pomocą metody insertBefore:
<HTML>
<HEAD>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function alterDocument()
{
var xmldoc, rootNode, meetingsNode, meetingNode
var createdNode, createdTextNode
xmldoc = document.all.meetingsXML
rootNode = xmldoc.documentElement
meetingsNode = rootNode.firstChild
meetingNode = meetingsNode.firstChild
createdNode = xmldoc.createElement("PRZEWODNICZĄCY")
createdNode = meetingsNode.insertBefore(createdNode, meetingNode)
.
.
.
Teraz wewnątrz nowego elementu utworzymy węzeł tekstowy. Węzeł ten zawierał będzie tekst Ted Bond, utworzymy go stosując metodę createTextNode, następnie nasz nowy element wstawimy metodą appendChild:
<HTML>
<HEAD>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function alterDocument()
{
var xmldoc, rootNode, meetingsNode, meetingNode
var createdNode, createdTextNode
xmldoc = document.all.meetingsXML
rootNode = xmldoc.documentElement
meetingsNode = rootNode.firstChild
meetingNode = meetingsNode.firstChild
createdNode = xmldoc.createElement("PRZEWODNICZĄCY")
createdNode = meetingsNode.insertBefore(createdNode, meetingsNode)
createdTextNode = xmldoc.createTextNode("Ted Bond")
createNode.appendChild(createdTextNode)
.
.
.
Dokument już zmodyfikowaliśmy, jednak nowe treści istnieją jedynie wewnątrz obiektu xmldoc. Jak wynik wyświetlić w przeglądarce? Obiekt DOMDocument ma metodę save, która umożliwia zapis dokumentu w nowym pliku, na przykład xmldoc.save("nowy.xml"). Metody tej nie można jednak użyć bez zmiany ustawień bezpieczeństwa Internet Explorera - domyślnie przeglądarce nie wolno zapisywać żadnych plików na lokalnym komputerze.
Zrobimy to inaczej. Treść dokumentu zapiszemy w ukrytej kontrolce formularza HTML (ukryta kontrolka po prostu zawiera tekst niewidoczny dla użytkownika), następnie dane wyślemy z formularza do skryptu ASP (Active Server Pages) znajdującego się na serwerze. Skrypt zwróci treść dokumentu z powrotem do przeglądarki, która go wyświetli. Poniżej pokazano skrypt ASP, echo.asp, w którym ustawiono typ MIME dokumentu text/xml, dodano instrukcję przetwarzania <?xml?> i przekazano dokument zwrotnie do Explorera (skrypty ASP przekraczają w zasadzie zakres tej książki, ale parę słów o nich powiemy w rozdziale 12).
<%@ LANGUAGE="VBSCRIPT" %>
<%
Response.Content.Type = "text/xml"
Response.Write "<?xml version=" & Chr(34) &
"1.0" & Chr(34) & "encoding=\"iso-8859-2\"?>" & Chr(13) & Chr(10)
Response.Write Request("data")
%>
Na moim komputerze działa serwer ASP, więc dokument XML wysłany zostanie pod adres URI http://default.db/echo.asp. Użyjemy metody submit formularza (która działa dokładnie tak, jakby użytkownik kliknął przycisk formularza SUBMIT) wywoływanej po załadowaniu dokumentu XML do ukrytej kontrolki:
<HTML>
<HEAD>
<XML ID="meetingsXML" SRC="spotkania.xml"></XML>
<SCRIPT LANGUAGE="JavaScript">
<!--
function alterDocument()
{
var xmldoc, rootNode, meetingsNode, meetingNode
var createdNode, createdTextNode
xmldoc = document.all.meetingsXML
rootNode = xmldoc.documentElement
meetingsNode = rootNode.firstChild
meetingNode = meetingsNode.firstChild
createdNode = xmldoc.createElement("PRZEWODNICZĄCY")
createdNode = meetingsNode.insertBefore(createdNode, meetingNode)
createdTextNode = xmldoc.createTextNode("Ted Bond")
createdNode.appendChild(createdTextNode)
document.all.data.value = meetingsXML.documentElement.xml
document.form1.submit()
}
//-->
</SCRIPT>
</HEAD>
<BODY>
<CENTER>
<FORM NAME="form1" ACTION="http://default/db/echo.asp" METHOD="POST">
<INPUT TYPE="HIDDEN" NAME="data">
<INPUT TYPE="BUTTON" VALUE="Modyfikacja dokumentu"
onclick="alterDocument()">
</FORM>
</CENTER>
</BODY>
</HTML>
Kiedy teraz użytkownik kliknie przycisk Modyfikacja dokumentu, dokument XML zostanie zmodyfikowany i wysłany na serwer. Wtedy skrypt ASP zwróci przeglądarce dokument XML, a przeglądarka ten dokument wyświetli - pokazano to na rysunku 5.11. Na rysunku widać nowy element, PRZEWODNICZĄCY.
Rysunek 5.11. Zmiana dokumentu XML w Internet Explorerze |
|
W tym rozdziale użyliśmy JavaScriptu do parsowania i obsługi dokumentów XML. W następnym rozdziale użyjemy JavaScriptu do potraktowania danych XML jako obiektów baz danych.
24 Część I ♦ Podstawy obsługi systemu WhizBang (Nagłówek strony)
Rozdział 1 ♦ Pierwsze kroki (Nagłówek strony)
24 C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r05-01.doc
C:\Moje dokumenty\Wojtek Romowicz\Książki\XML Vademecum profesjonalisty\r05-01.doc 1