Sova v síti - 2/11 - vydáno 10.12.2002 Dobrý den, je zde jedenácté letošní číslo Sovy v síti :-) OBSAH + Úvodník + DOM - Procházení dokumentů (Od kořenu k listům) ÚVODNÍK Naprostá zaneprázdněnost má i ostatních autorů způsobila, že se dnes setkáváte s emailovou Sovou po téměř dvouměsíční odmlce. Snad jste alespoň zatím načerpali hodně vědomostí z weblogu http://www.sovavsiti.cz/weblog/ který se nám daří s Martinem Koptou aktualizovat prakticky denně. ... V dnešním čísle najdete jediný, zato však rozsáhlý článek Romana Pichlíka o DOM (dokcument object model). Věřím, že se vám bude hodit a Romanovi se omlouvám za to, že jeho článek musel tak dlouho čekat na vydání. ... Nedostatek času také způsobil, že jsme ještě neuzavřeli soutěž na nový design stránek Sovy v síti. Návrhů se sice sešlo dost, i odborná porota se k nim již vyjádřila (všem porotcům děkuji), ale přesto s vyhlášením výsledků zatím váhám. Soudy porotců jsou totiž velmi nejednoznačné. O vyhodnocení se proto ještě poradíme tento pátek na Sově v Nuslích. ... Vida, tím se dostávám ke slavnostnímu ohlášení třetí Sovy v Nuslích. Služebně starším čtenářům není třeba vysvětlovat, o co se jedná a vy novější vězte, že jde o neformální setkání autorů, čtenářů a příznivců Sovy v síti, které se již tradičně koná jednou za čtvrt roku v nuselské restauraci Na Květnici (Praha). Tentokrát bylo naplánováno na páteční večer 13.12.2002 a chcete-li se zúčastnit, pošlete laskavě registrační email na adresu mailto:sovavnuslich-reminder@garcon.cz Email může být prázdný, ale můžete nám do něj napsat i libovolný vzkaz. Po odeslání obdržíte automatickou odpověď s podrobnějšími informacemi o místě a času konání. ... A teď se již pusťte do DOM. ... Krásný den vám přeje, Marek Prokop ~~~reklama~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Společnost PROKOP software a vydavatel Sovy v síti Marek Prokop nabízejí odborné posouzení a doporučení úprav vašich stránek Více informací: http://www.prokopsw.cz/online/rozbor_stranek.html ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~reklama~~~ DOM - PROCHÁZENÍ DOKUMENTŮ (OD KOŘENU K LISTŮM) Roman Pichlík K sepsání tohoto článku, mě dovedla moje skleróza. Ne nebojte se tak vážné to není, hned vám to vysvětlím. Určitě se vám stává, že potřebujete pracovat s nějakým konkrétním elementem (prvkem) nebo kolekcí prvků, na tom by nebylo nic tak divného. Problém nastane ve chvíli, kdy vybíráme použití té správné metody pro získání konkrétního elementu. Na výběr je celkem velké množství metod, bohužel, z velké časti platformově závislých dle specifické DHTML implementace. Dnes si proto ukážeme metody definované v DOM (Data Object Model) Level 2. Toto rozhraní implementují následující prohlížeče IE 5.0+,Opera 6.05 a prohlížeče postavené na jádru Gecko, např. Mozilla 1.0,Netscape 6.0+ atd. To jsou ty nejznámější. Tabulku kompatibility s DOM jednotlivých prohlížečů najdete na http://www.xs4all.nl/~ppk/js/version5.html Existují v podstatě dva základní přístupy. + element jsme schopni blíže určit, ať už pomocí jeho ID nebo jeho jména(tagu) + element nejsme schopni blíže určit, nebo hledáme celou množinu elementů Pokud tedy můžeme element blíže určit, poskytuje nám rozhraní DOM tyto metody: + Document.getElementById() + Document.getElementsByTagName() + Document.getElementsByTagNameNS() Nyní si můžeme metody popsat, abychom věděli, jaké jsou vstupní parametry a hlavně jejich návratové hodnoty. == Document.getElementById() == Popis: Element Document.getElementByID(String elementID) Metoda vyhledá v dokumentu uzel typu Element, jehož atribut id je roven argumentu elementID. Provede jeho přetypování na objekt Element a ten se vrací. Pokud, žádný takový element neexistuje, vrací metoda hodnotu null. Pokud se v objektovém modelu nachází více jak jeden element se shodným id, může metoda vrátit + jakýkoliv element z kolekce elementů, jež mají stejné id, + nebo hodnotu null. Otestoval jsem na Mozille 1.0, Netscape 7.0, IE 5,0 a Opera 6.05 a všechny vracely vždy první element z kolekce elementů. Je třeba si uvědomit, že DOM je obecné API pro práci s objektovým modelem dat, používá se proto i na prací s XML daty jako takovými. Daná implementace DOMu v aplikaci musí poznat, že se skutečně jedna o prvek Id. Tuto informaci přečte z DTD XML dat, kde je atribut typu ID. Pokud DTD z nějakého důvodu chybí, vrací metoda hodnotu null. Příklad použití: function getElById(stringId){ // získaní konkrétního elementu, kde id=stringId element = document.getElementById(stringId); // otestujeme jestli byl nalezen if (element == null){ alert("Nenalezen element s hodnotou id="+stringId) }else{ alert("Nalezen element s hodnotou id="+stringId); // s konkretnim elementem pak můžeme naložit jak je libo element.style.backgroundColor = "aqua"; } } == Document.getElementsByTagName() == Popis: Node[] Document.getElementsByTagName(String tagname) Metoda vyhledá v dokumentu všechny uzly typu element jejichž název bude totožný s atributem tagName. Tyto elementy vrátí jako pole objektu typu Node. Pokud se v dokumentu nenachází ani jeden odpovídající element, má pole nulovou délku. K této metodě je třeba dodat, že je implementována i objektem Element. To můžeme využít v kombinaci s getElemenById(). Příklad použití (na dokumentu): function do_getElByTagName(stringTag){ // získáme pole všech uzlu, kde nazev tagu=stringTag poleElementu = document.getElementsByTagName(stringTag); alert("Počet nalezených elementů "+stringTag+" "+poleElementu.length); // takoveto pole můžeme projít a dostat se tak na konkrétní element for(foo = 0;foo < poleElementu.length; foo++){ // elementu můžeme přiřadit třeba CSS vlastnost pro barvu pozadí poleElementu[foo].style.backgroundColor="aqua"; } } Příklad použití (na elementu): function el_getElByTagName(stringId,stringTag){ //ziskame opet konkretni element element = document.getElementById(stringId); //pokud žadný takový neexistuje ukončíme funkci if (element == null){ alert("Nenalezen element s hodnotou id="+stringId); return; } // pokud ano, získáme pole uzlů, kde budou všechny elementy // uvnitř daného elementu poleElementu = element.getElementsByTagName(stringTag); // vypíšeme jejich počet a jméno rodičovského elementu alert("Počet nalezených elementů "+poleElementu.length+" uvnitr elementu "+stringTag+" s hodnotou id="+stringId); for(foo = 0;foo < poleElementu.length; foo++){ // Mužeme vzít panáčky jednotlivě a trochu je obarvit poleElementu[foo].style.backgroundColor="aqua"; } } Jako poslední jsem si nechal metodu == Document.getElementsByTagNameNS() == Popis: Node[] Document.getElementsByTagNameNS(String namespaceURI,String localName) Tato metoda se funkčně nijak neliší od předchozí metody avšak přidává argument namespaceURI, který se používá pro identifikaci jmenného prostoru elementu. Použitelnost této metody je tak omezena pouze na XML dokumenty s definici jmenných prostorů. Neměli bychom však zapomenout na zpětnou kompatibilitu se staršími prohlížeči. Pro IE 4.0 můžeme použít jako náhradu document.getElementByid(id) metodu document.all.item(id) nebo document.all[id]. Jako náhradu za document.getElementsByTagName(tagname) použijeme document.all.tags(tagname). NN4 se svého času vydal vlastní cestou a použil hladiny (layer), což je atypické rozšíření. K jednotlivým hladinám můžeme přistoupit pomocí pole layer avšak dokument pro práci s nimi musí být uzpůsoben. Nejedná se tedy o věc standardní a nemá cenu se jí dále zabývat. Tímto výčet metod, kdy jsem schopni blíže určit daný element končí. Někdy ovšem nastane situace, kdy o struktuře dokumentu nevíme nic nebo nás ani jeho struktura nezajímá. V takovém případě můžeme objektový strom procházet od kořenů k jednotlivým listům, bez jakéhokoliv zkoumání. Než si ukážeme, jak na to je třeba si uvědomit, že v objektovém modelu je každá jednotlivá část (element, text, entita, procesní instrukce, atd.) reprezentována objektem. Aby bylo možné procházet celý strom a pracovat s ním, musí každý objekt implementovat rozhraní Node, které definuje jeho základní metody (firstChild, nextSibling, appendChild, removeChild, atd.). Každý objekt musí ještě implementovat další specifické rozhraní (Element, Text, Komentář, atd.), které definuje další metody typické pro konkrétní typ uzlu. Rozhraní node tedy implementuje tyto metody (první slovo označuje návratový typ metody): + NamedNodeMap attributes() + Node[] childNodes + Node firstChild + Node lastChild + Node nextSibling + Node parentNode + Node previousSibling + String localName + String namespaceURI + String nodeName + unsigned short nodeType + String nodeValue + Document ownerDocument + String prefix Nebudu vás trápit popisem co jednotlivá metoda děla -- pokud vás to opravdu zajímá, koukněte se přímo do specifikace: http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html My ostatní se podíváme na pár příkladů. Co byste řekli na průchod celým objektovým modelem s výpisem všech elementů na čtyři řádky. Může být: function viewDOM(uzel){ if (uzel==null)return; if(uzel.nodeType==1)alert(uzel.nodeName); viewDOM(uzel.firstChild); viewDOM(uzel.nextSibling); } Jak jednoduché. Nyní si funkci trochu popíšeme. Suma sumárum je to klasická rekurze (funkce volá sebe samu). Celý princip je založen na prostém faktu, že metody firstChild (vrací první dítě aktuálního uzlu) a nextSibling (vrací dalšího sourozence aktuálního uzlu) vracejí hodnotu null, pokud takový uzel neexistuje. No, a pak je to jednoduché -- vždy se otestuje jestli má uzel dítě. Pokud ne (firstChild vrací null), tedy první podmínka, která je vtom případě true, ukončí další průchod směrem dolů, tj. uzel nemá děti je třeba se kouknout na jeho sourozence (pokud neexistuje uzel=null) a pořád dokola dokud se neprobubláme zpátky k nejvyššímu elementu. Ještě nám zbyla řádka kde používáme metodu nodeType. Vrací typ uzlu (element, text, komentář, atd.). Pokud víme (já to vím a vy si typy uzlu můžete dohledat na konci článku), že 1=uzel typu element, použijeme metodu nodeName, která vrátí název elementu(tagu). Vstupním argumentem funkce je uzel, od kterého se má začít. Ukážeme si ještě jedno řešení: function viewDOM(uzel){ var foo; for(foo = 0;foo0){ viewDOM(uzel[foo].childNodes); } } } Tato metoda je taktéž rekurzivní. Rozdíl od prvního příkladu je vtom, že procházíme pouze děti aktuálního uzlu. Pro zjištění jestli má uzel děti použijeme metodu childNodes (vrací pole všech dětí aktuálního uzlu). Pokud uzel nemá děti je délka pole nula. Pak stačí otestovat jestli má uzel děti a pokud ano, zavolá sebe samu s polem dětských uzlu. Tuto metodu můžeme použít i v případech, kdy chceme pouze všechny dětí určitého uzlu aniž by nás zajímali jeho sousedé. Při volání: viewDOM(document.getElementsByTagName('head')) Budou vráceny všechny elementy uvnitř elementu HEAD. Narozdíl od prvního příkladu, kdy dostaneme i elementy, které jsou sourozenci elementu HEAD -- povětšinou tedy element BODY a jeho děti. Ještě malý rozdíl mezi oběma metodami: + první pracuje s konkrétním uzlem + druhá vždy s konkrétním polem dětí (cyklus for) Špatná zpráva nakonec pro uživatele jinak skvělého prohlížeče Opera. Opera ani ve verzi 6.05 neimplementuje rozhraní Node. A to je pro dnešek vše přátelé. Vlastně ne, co jsem to psal o té skleróze ještě tabulka typů uzlů, která se vám bude v praxi hodit. konstanta nodeType nodeName nodeValue 1 ELEMENT_NODE název elementu null 2 ATTRIBUTE_NODE název atributu hodnota atributu 3 TEXT_NODE #text text uzlu 4 CDATA_SECTION_NODE #cdata-section text uzlu 5 ENTITY_REFERENCE_NODE odkaz. entity null 6 ENTITY_NODE název entity null 7 PROCESING_INSTRUCTION_NODE cíl proc.instrukce hodnota targetu 8 COMMENT_NODE #comment null 9 DOCUMENT_NODE #document null 10 DOCUMENT_TYPE_NODE #nazev typu dok. null 11 DOCUMENT_FRAGMENT_NODE #document-fragment null 12 NOTATION_NODE název notace null Konstanty jsem zde uvedl schválně. Šlo by totiž testovat typ uzlu proti Node.ELEMENT_NODE (vrátí 1), ale podporují ho pouze gecko-like prohlížeče. Zdroje: Flanagan David:JavaScript kompletní průvodce, Computer Press 2002 http://www.w3.org/DOM/ http://www.w3.org/TR/2000/REC-DOM-Level-2-Core-20001113/core.html ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Denně aktualizované novinky, odkazy na články, zajímavé stránky: Weblog Sovy v síti -- http://www.sovavsiti.cz/weblog/ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A to je pro dnešek vše. Příště se snad dočkáte již dlouho plánovaného článku o velikosti písma a určitě i něčeho dalšího. Zatím se mějte krásně. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Nechcete, nebo naopak chcete dostávat Sovu v síti? Odběr lze odhlásit odesláním zprávy na unsubscribe@sovavsiti.cz. Přihlásit se lze odesláním zprávy na subscribe@sovavsiti.cz, nebo formulářem na adrese http://www.sovavsiti.cz/. Chcete nám cokoli sdělit? Uvítáme vaše náměty, připomínky, kritiku, atd. na adrese mailto:redakce@sovavsiti.cz. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Není-li v konkrétním případě uvedeno jinak, je autorem všech publikovaných textů Marek Prokop. Tento ezin, nebo jeho libovolnou část můžete volně šířit dále, pokud současně uvedete zdroj následujícím způsobem: _________________________________________________________________ Sova v síti -- (c) 2002 Marek Prokop -- http://www.sovavsiti.cz/