XML pro web aneb od teorie k praxi, 12.díl

V dnešním dílu se budeme zabývat elegantním načtením XML dokumentu čistě pomocí skriptování. Připraven je i bonus, který vám pomůže obejít jednu málo známou chybu projevující se při práci s DOM XML dokumentem v IE.

Načtení XML dokumentu v Mozille - DOM

V normě DOM Level 2 Core byla přidána možnost vytvoření nového DOM XML dokumentu pomocí metody createDocument() objektu implementation. V současné době lze tímto způsobem vytvářet DOM XML dokument pouze v Mozille, která má ze všech prohlížečů zdaleka nejlepší implementaci DOM. Vytvoření nového DOM XML dokumentu je záležitostí jednho řádku skriptu.

var xmlDoc = document.implementation.createDocument(``, ``, null);

Metoda createDocument() má tři parametry - popořadě jsou to string namespaceURI (identifikátor jmenného prostoru, kterým je URI), string qalifiedName (kvalifikované jméno kořenového elementu dokumentu, tj. jméno, které může obsahovat předponu jmenného prostoru) a objekt doctype. Proměnná xmlDoc nyní obsahuje DOM reprezentaci XML dokumentu, který jsme však vytvořili úplně prázdný - neobsahuje ani kořenový element, ani deklaraci typu dokumentu. Tento minimalistický DOM dokument se však nejlépe hodí k načtení XML z externího zdroje. Nyní si ukážeme další dva kroky, které nás dovedou až k cíli, kterým je načtený XML dokument.

xmlDoc.onload = zpracujXMLdokument;
xmlDoc.load(`cesta/k/xml/dokumentu.xml`);

Nejprve zaregistrujeme ovladač události load, která nastane v okamžiku dokončení načtení XML dokumentu. V našem případě se jedná o funkci s názorným názvem zpracujXMLdokument() - může se jednat např. o výpis dat z XML do HTML stránky, jehož příklad jsme si uváděli minule, ale také se samozřejmě může jednat o jakoukoliv jinou funkci, kterou potřebujeme spustit bezprostředně po načtení XML souboru.

Druhým krokem je samotné načtení dokumentu, které zajišťuje metoda load() aplikovaná na samotný DOM XML dokument. Metoda load() byla zařazena do normy DOM Level 3 Load and Save. Jediným parametrem metody je relativní či absolutní URL XML dokumentu, který potřebujeme načíst. Je však potřeba si dát pozor na to, aby XML dokument pocházel ze stejné domény, jako "mateřská" HTML stránka, v opačném případě prohlížeč z důvodu bezpečnostních restrikcí načtení XML dokumentu neprovede.

Vytváření DOM XML dokumentu v prohlížeči

DOM XML dokument vytvořený metodou createDocument() nemusí být určen jen pro načtení externího XML dokumentu. Je možné jej použít jako základ pro vytvoření samostatného DOM XML dokumentu - všechny možnosti pro vytváření, přidávání, procházení či mazání nodů, které nám poskytuje DOM rozhraní, lze aplikovat i na tento "neviditelný" dokument. V přemýšlivých hlavách z řad čtenářů se nyní jistě objeví logická otázka - a k čemu se takový "neviditelný" XML dokument hodí? Byla by to opravdu spíše jen hračka bez užitku, kdyby neexistovaly techniky, kterak tento XML dokument "zhmotnit" - představte si například Javascript/DOM aplikaci, která místo klasického souboru GET/POST proměnných z formuláře odesílá na server již hotový XML dokument...není tato představa lákavá? Pokud si osvojíte pokročilé techniky práce s XML v moderních prohlížečích, o kterých bude postupně řeč v dalších dílech tohoto seriálu, pak vám jistě nebude realizace této představy dělat velké problémy.

Jak by vypadalo vytváření XML dokumentu "od píky"? V první řadě by bylo nutné vložit kořenový element - toho bychom dosáhli uvedením jména kořenového elementu v druhém parametru metody createDocument(), ale stejný efekt by mělo vytvoření kořenového elementu samostatně a vložení do dokumentu:

var root = xmlDoc.createElement(`korenovy-element`);
xmlDoc.appendChild(root);

A jak je to s objektem doctype? Ten lze vytvořit za pomoci metody createDocumentType() objektu implementation. Metoda má 3 parametry - qualifiedName (kvalifikované jméno kořenového elementu), publicId (veřejný identifikátor) a systemId (systémový identifikátor).

var doctype = document.implementation.createDocumentType(`root-element`, ``, `doctype.dtd`);

Načtení XML dokumentu v MSIE - ActiveX

Vytvoření objektu DOM XML dokumentu a jeho načtení z externího zdroje umožňuje samozřejmě i Microsoft Internet Explorer od verze 5.0. Nevystačíme si však se standardním DOM rozhraním, jehož implementace v MSIE není na potřebné úrovni. Místo toho je potřeba vytvořit ActiveX objekt pomocí proprietální syntaxe. Samotnou práci s DOM XML dokumentem má na starosti MSXML parser, který se ovšem ve spojení s prohlížečem Microsoft Internet Explorer vyskytuje v několika verzích. Ukážeme si zápis, který funguje od nejnižší možné verze MSXML parseru, která byla distribuována s IE 5.0.

Objekt typu DOM XML dokument, analogický s tím, který jsme pomocí DOM metody createDocument() vytvářeli v Mozille, vznikne díky následujícímu kódu:

var xmlDoc = new ActiveXObject(`Microsoft.XMLDOM`);

Nyní existují dvě možnosti, které ošetřují načtení XML dokumentu. První je nastavení vlastnosti async na hodnotu false - tato vlastnost určuje, jestli je provedeno asynchronní načtení XML dokumentu, nebo nikoliv. Výchozí hodnotou je true - tato hodnota říká, že načítání XML dokumentu nijak neovlivní další běh skriptu, který nečeká, až se XML dokument kompletně načte. Nastavení na false má za následek pozdržení běhu skriptu až do té doby, než se XML dokument načte. Bezprostředně pak můžeme bez problému volat funkci, která zpracovává XML dokument, jak ukazuje následující kód.

xmlDoc.async = false;
xmlDoc.load(`cesta/k/xml/dokumentu.xml`);
zpracujXMLdokument();

Samotné načtení dokumentu zajišťuje názvem, funkcí i parametrem identická metoda load() stejně, jako v Mozille. Pokud je stažení XML dokumentu asynchronní, zřejmě budeme potřebovat obslužnou funkci zpracovávající XML dokument spouštět až po úplném načtení dokumentu. Bohužel v IE nemůžeme asociovat ovladač s událostí load, jelikož objekt DOM XML dokumentu ji nezná. Tento objekt však v IE disponuje vlastností readyState, jejíž hodnotou je vždy aktuální stav načtení XML DOM dokumentu reprezentovaný číslem od 1 do 4:

  1. LOADING - probíhá načítání souboru z externího zdroje
  2. LOADED - načtení souboru bylo dokončeno, probíhá parsování dat, ale zatím není ani částečně přístupná DOM reprezentace
  3. INTERACTIVE - některá data byla již rozparsována, DOM reprezentace je částečně přístupná, v každém případě však jen pro čtení
  4. COMPLETED - dokument byl kompletně načten a rozparsován, je plně k dispozici

K readyState se váže vlastnost onreadystatechange, pomocí které můžeme připojit ovladač události, která nastane při změně stavu načtení. A právě tyto dvě vlastnosti využijeme pro indikaci načtení XML dokumentu. Idea je postavena na odchytávání každé změny stavu načtení - přitom testujeme aktuální hodnotu readyState a pokud je tato hodnota 4 (COMPLETED), lze zavolat zpracovávací funkci.

xmlDoc.onreadystatechange = stateControl
xmlDoc.load(`cesta/k/xml/dokumentu.xml`);

function stateControl() {
	if(xmlDoc.readyState==4) zpracujXMLdokument();
}

Hrátky s readyState mohou být samozřejmě i propracovanější - při každé změně stavu načtení můžete například měnit "čekací" informaci (obrázek, animaci...), což může vypadat velice efektně. U drobných XML dokumentů, které asi budete chtít načítat nejčastěji, se zřejmě ale bez podobných efektů obejdete (přece jen, tyto rychlé změny stavu by si uživatelé asi moc neužili :-).

Bonus - jak obejít chybu vlastnosti childNodes v IE

Nyní už tedy víte, jak načíst XML dokument v IE 5+ a Mozille. Při práci s XML dokumentem pomocí DOM rozhraní můžete občas narazit na chybu, která se vyskytuje v některých verzích IE 5 (s největší pravděpodobností se jedná o chybu určité verze MSXML parseru). Chyba se projevuje "zkolabováním" skriptu při práci s kolekcí childNodes (tato vlastnost vrací všechny dětské nody určitého elementu). I když element obsahuje dětské uzly, childNodes vrátí null. Jako přídavek k dnešnímu dílu vám ukážu způsob, jak tuto nepříjemnou chybu obejít.

Celý problém řeší funkce, kterou jsem nazval getXMLchildNodes(). Funkce má 2 parametry - XMLnode, jehož kolekci childNodes potřebujeme získat, a logickou proměnnou isColl. Tato proměnná nabývá hodnoty:

  • true, pokud výsledný objekt bude třídy collection (analogie k rozhraní NodeList) s metodami item() a vlastností length
  • false, pokud se bude jednat o pole (tj. prvky můžeme volat pomocí indexu a stejně tak máme k dispozici vlastnost length).

Zde je kompletní kód.

function getXMLchildNodes(XMLnode, isColl) {
	if(XMLnode.childNodes) {
		return XMLnode.childNodes;
	} else {
		var aktChild = XMLnode.firstChild;
		var XMLchildNodes = new Array();
		
		while(aktChild) {
			XMLchildNodes[XMLchildNodes.length] = aktChild;
			aktChild = aktChild.nextSibling;
		}
		
		if(isColl) XMLchildNodes = new collection(XMLchildNodes);
		return XMLchildNodes;
	}
}

function collection(XMLchildNodes) {
	this.XMLchildNodes = XMLchildNodes;
	this.length = XMLchildNodes.length;
	this.item = item;
}

function item(i) {
	return this.XMLchildNodes[i];
}

Funkce nejprve otestuje, jestli vlastnost childNodes nevrací null - pokud ano, vrátí správný výsledek vlastnosti childNodes, pokud nikoliv, sestaví kolekci dětských uzlů jiným způsobem. Nejdříve vyhledá první dítě uzlu (firstChild) a poté cyklem while prochází další sourozence, než dojde na konec. Poté vrátí (dle hodnoty indikátoru isColl) buď vytvořený objekt třídy collection, nebo prosté pole dětských uzlů.

Použití funkce je jednoduché. Kdykoliv potřebujete bezpečně najít dětské uzly určitého elementu v DOM XML dokumentu, místo vlastnosti childNodes použijete funkci getXMLchildNodes(). Předáte jí objekt příslušného elementu a true/false v závislosti na způsobu, jakým jste zvyklí pracovat s kolekcí childNodes. Pokud k ní vždy přistupujete jako k poli (pomocí indexů), uveďte false, pokud používáte (v souladu se standardem DOM) metodu item(), použijte true. Podívejte se na konkrétní ukázky použití ve skriptu:

Původní kód:

var deti = elem.childNodes;
var treti_dite = deti.item(2);

Bezpečný kód:

var deti = getXMLchildNodes(elem, true);
var treti_dite = deti.item(2);

Tolik tedy o načtení XML dokumentu pomocí kombinace Javascript/DOM(/ActiveX). Přístě opět pokročíme a ukážeme si možné způsoby interakce DOM XML dokumentu s "prostředím". Díky tomu budeme schopni řádově zvýšit inteligenci našich Javascriptových aplikací založených na XML.

Diskuze (3) Další článek: Další nabídka ADSL od SkyNetu

Témata článku: Software, Microsoft, Programování, Internet Explorer, Určitý objekt, Nejnižší třída, Nepříjemná vlastnost, Dokončené dílo, Stejný efekt, Kompletní kód, IE 10, Root, IE 11, XML, Teorie, Element, Pre, Doma, První dítě, Code, Item


Určitě si přečtěte

Sex a rozmnožování při mezihvězdné cestě: Kolik lidí je potřeba pro let k Proximě Centauri?

Sex a rozmnožování při mezihvězdné cestě: Kolik lidí je potřeba pro let k Proximě Centauri?

** Vědci spočítali, jak velká by musela být posádka pro vícegenerační let k nejbližší hvězdné soustavě ** Proxima Centauri se nachází 4,3 světelných let od nás ** Za současných technologií bychom k ní letěli 6300 let

Petr Kubala | 58

eObčanka: Jak a proč si zřídit elektronický občanský průkaz s čipem

eObčanka: Jak a proč si zřídit elektronický občanský průkaz s čipem

** Občanka s čipem už je standardně vydávaným osobním dokladem v Česku ** Umožní využívat Portál občana a funkce elektronické státní správy ** Pokud ji chcete naplno využívat, musíte si čip aktivovat

David Polesný | 114

Osudová havárie Concordu: Před 18 lety přišel konec nadzvukových dopravních letadel

Osudová havárie Concordu: Před 18 lety přišel konec nadzvukových dopravních letadel

** Concorde byl nejrychlejším dopravním letadlem ** Atlantik dokázal přeletět za cca 3 až 3,5 hodiny ** Před osmnácti lety tragická havárie provoz těchto letadel prakticky ukončila

David Polesný, Jiří Černý | 38


Aktuální číslo časopisu Computer

Jak mobily určují svoji polohu?

Velký test notebooků pro studenty

Nejlepší reproduktory na párty

Služby a aplikace pro výuku angličtiny