referát
Transkript
referát
Zpracovávání XML v prohlížečích Jakub Jelínek, Jiří Matějka SWI117 Technologie vývoje webových aplikací 25. června 2009 Obsah 1 Úvod.................................................................................................................................................2 2 Podpora pro XPath v Javascriptu.....................................................................................................3 2.1 Třída XPathEvaluator...............................................................................................................3 2.2 Metoda evaluate().....................................................................................................................3 2.2.1 Parametry metody evaluate()............................................................................................3 2.2.2 Návratová hodnota funkce evaluate()...............................................................................4 2.3 Rozhraní XPathResult...............................................................................................................4 2.3.1 Výsledek jako množina uzlů.............................................................................................5 2.4 Podpora.....................................................................................................................................5 2.5 XPath v Internet Exploreru.......................................................................................................6 2.6 Knihovny..................................................................................................................................6 3 Parsing a serializace XML................................................................................................................7 3.1 Načtení (parsing) XML.............................................................................................................7 3.2 Uložení (serializace) XML.......................................................................................................7 4 E4X...................................................................................................................................................9 4.1 Implementace............................................................................................................................9 4.2 Vytvoření XML objektu...........................................................................................................9 4.3 Práce s XML objektem...........................................................................................................10 4.4 Seznamy XML uzlů................................................................................................................10 4.5 Predikáty.................................................................................................................................10 4.6 Editace XML...........................................................................................................................11 4.7 Spolupráce DOM a E4X.........................................................................................................11 5 Zdroje.............................................................................................................................................12 5.1 Podpora pro XPath v Javascriptu............................................................................................12 5.2 Parsing a serializace XML......................................................................................................12 5.3 E4X.........................................................................................................................................12 1 Úvod V tomto referátu si předvedeme některé prostředky, které internetové prohlížeče poskytují pro práci s XML. Bude to jednak rozhraní prohlížečů, které umožňuje provádět XPath dotazy nad DOM stromem dokumentu, potom možnosti pro serializaci a deserializaci XML dat a také obzvláště jednoduchý a účinný zápis pro vytváření XML dat zvaný E4X. Ve všech případech se pro přístup k danému API využívá JavaScriptu. Všechny zde probírané technologie jsou založeny na standardech konsorcia W3C, které jsou v prohlížečích více či méně podporovány. V případě, že podpora chybí, uvádíme také JavaScriptové knihovny, které danou funkčnost poskytují. 2 Podpora pro XPath v Javascriptu Konsorciem W3C byl vydán v roce 2004 dokument „Document Object Model XPath“ jako W3C Working Group Notes. Tento dokument popisuje mapování modelu dotazovacího jazyka XPath 1.0 na Document Object Model. 2.1 Třída XPathEvaluator Pro podporu XPath v Javascriptu jsou k dispozici třídy XPathEvaluator a XPathResult. Objekt typu XPathEvaluator může být vytvořen buď explicitně zavoláním konstruktoru XPathEvaluator(), nebo může být použit objekt document, který dědí od třídy XPathEvaluator. Hlavní metoda pro provedení dotazu je metoda evaluate, která vrací výsledek jako objekt XPathResult. Příklad 2.1 //get first div var result = document.evaluate("//div", document.documentElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); alert("First div is " + result.singleNodeValue.id); 2.2 Metoda evaluate() Metoda evaluate hraje důležitou roli, proto si podrobně probereme nejprve její parametry a následně také návratovou hodnotu. 2.2.1 Parametry metody evaluate() Nyní si ukážeme, jaké parametry má metoda evaluate. Tato metoda má pět parametrů: evaluate(xpathExpression, contextNode, namespaceResolver, resultType, result) 1. xpathExpression – vlastní XPath dotaz 2. contextNode – kontextový uzel, vzhledem ke kterému je XPath dotaz prováděn, typicky je to document.documentElement. 3. namespaceResolver – funkce, kterou si podle potřeby volá funkce evaluate. Tato funkce dostane za parametr jmenný prostor který je zmíněn v xpathExpression a vrátí jeho URI. Na místě této funkce je možno použít: • • • objekt XPathEvaluator.createNSResolver. Tato možnost by se měla použít ve většině případů, potřebný objekt je vytvořen automaticky. null, například pro HTML, kde nejsou použity jmenné prostory. vlastní funkce. 4. resultType – hodnota konstanty definované ve třídě XPathResult. Bude diskutováno podrobněji v následující kapitole. 5. result – do tohoto parametru je možno zadat již existující objekt XPathResult, v tom případě se použije se pro výsledek a nebude se alokovat nový. Pokud zadáme null, vytvoří se nový objekt XpathResult. 2.2.2 Návratová hodnota funkce evaluate() Návratová hodnota je vždy typu XPathResult, který však zapouzdřuje několik možných návratových typů – číslo, řetězec, boolean, jeden uzel, kolekci uzlů reprezentovanou iterátorem, nebo kolekci uzlů - „snímek“ („snapshot“). Rozdíl mezi iterátorem a snímkem je v tom, že pokud po obdržení výsledku z funkce evaluate dojde ke změně uzlů v dokumentu takové, že by to změnilo výsledek dotazu, výsledek s iterátorem se zneplatní. Výsledek ve tvaru snímku je neměnný. Parametrem resultType funkce evaluate můžeme říci, jakého typu výsledek požadujeme. Jsou to konstanty ze třídy XpathResult. 2.3 Rozhraní XPathResult Následuje výčet metod a následně konstant obsažených v rozhraní XPathResult. boolean booleanValue boolean invalidIteratorState double numberValue int resultType Node,null singleNodeValue int snapshotLength string stringValue Node,null iterateNext() Node snapshotItem(int index) ANY_TYPE ANY_UNORDERED_NODE_TYPE BOOLEAN_TYPE FIRST_ORDERED_NODE_TYPE NUMBER_TYPE ORDERED_NODE_ITERATOR_TYPE ORDERED_NODE_SNAPSHOT_TYPE STRING_TYPE UNORDERED_NODE_ITERATOR_TYPE UNORDERED_NODE_SNAPSHOT_TYPE ANY_TYPE vrátí datový typ, který je přirozeným výsledkem XPath dotazu. Později můžeme zjistit jaký datový typ byl vrácen – je ve vlastnosti resultType objektu XPathResult. Podle typu výsledku použjeme vlastnost numberValue, stringValue, booleanValue objektu XPathResult. Příklad 2.2 var count = document.evaluate('count(//p)', document, null, XPathResult.ANY_TYPE, null); alert('This document contains ' + count.numberValue + ' paragraph elements' ); Protože daný dotaz vrací číslo, je třeba hodnotu získat z vlastnosti numberValue. NUMBER_TYPE, STRING_TYPE, BOOLEAN_TYPE vrací elementární typy. Hodnotu výsledku obdržíme z vlastností numberValue, stringValue, booleanValue objektu XPathResult. 2.3.1 Výsledek jako množina uzlů V následujícím textu uvedeme metody pro získání výsledku jako množiny uzlů. Rozlišují se dva druhy takovýchto výsledků – uspořádané a neuspořádané. Pokud si vyžádáme uspořádanou množinu, je ve výsledku zachováno stejné pořadí jako v dokumentu. V opačném případě nebude výsledek v žádném zaručeném pořadí. Iterátory. Je-li po funkci požadován typ *_NODE_ITERATOR_TYPE, vrátí iterátor, který se použije voláním metody iterateNext. Je to pro případy, kdy výsledkem XPath dotazu je množina uzlů. Tato metoda vrací další uzel. Pokud už se všechny uzly prošly, vrátí null. Příklad 2.3 var iterator = document.evaluate('//phoneNumber', documentNode, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null ); try { var thisNode = iterator.iterateNext(); while (thisNode) { alert( thisNode.textContent ); thisNode = iterator.iterateNext(); } } catch (e) { dump( 'Error: Document tree modified during iteration ' + e ); } Na příkladu je vidět použití iterátoru včetně případu, že je dokument změněn během iterování tak, že by to změnilo výsledek dotazu. V takovém případě je vyhozena výjimka NS_ERROR_DOM_INVALID_STATE_ERR. Snapshoty. Snapshot reprezentuje také množinu uzlů, ale neměnnou, tedy následné úpravy uzlů v dokumentu nezmění snapshot. Proto se k snapshotu přistupuje jako k poli o známé délce – vlastností snapshotLength a metodou snapshotItem. Jednotlivé uzly. Pro dotazy, které vrací potenciálně množinu uzlů, můžeme říci, že chceme vrátit pouze jediný uzel. Určí se to konstantami FIRST_ORDERED_NODE_TYPE, která vrací první uzel výsledku, a ANY_UNORDERED_NODE_TYPE, která vrací jeden neurčený uzel. Uzel vyzvedneme z vlastnosti singleNodeValue. 2.4 Podpora Specifikaci DOM XPath podporují v určité míře prohlížeče Firefox, Opera, Safari (Webkit), Chrome. Všechny podporují minimálně funkci evaluate na objektu document. Internet Explorer standard nepodporuje, o práci s XPath v něm je věnován následující odstavec. Na příkladu pro parametr ANY_TYPE výše byly s úspěchem otestovány prohlížeče Firefox 3, Opera 9.6, Chrome 1. Test neprošel u prohlížečů Internet Explorer 6 a 7. Prohlížeče podporující XPath umožní dotazování jak nad XML, tak i HTML. Lze se také dotazovat nad dokumentem získaným asynchronně pomocí třídy XMLHttpRequest. 2.5 XPath v Internet Exploreru Internet Explorer nepodporuje standard DOM XPath, ale je možno použít knihovnu MSXML od Microsoftu. Příklad 2.4 xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.load("books.xml"); xmlDoc.selectNodes("//book"); Knihovna obsahuje dvě funkce: 1. selectSingleNode, která vrací jediný uzel, a 2. selectNodes, která vrací množinu uzlů. Tato knihovna umožňuje jen práci s well-formed XML dokumenty, což HTML obecně není (např. neuzavírá značky). 2.6 Knihovny Pro prohlížeče, které XPath nepodporují, nebo nepodporují zcela (Safari), jsou k dispozici JavaScriptové knihovny. • LlamaLab (nejrychlejší)- http://llamalab.com/js/xpath/ • Google AJAXSLT - http://goog-ajaxslt.sourceforge.net/ • Cybozu Javascript XPath - http://coderepos.org/share/wiki/JavaScript-XPath 3 Parsing a serializace XML Často potřebujeme načíst XML dokument do paměti a reprezentovat jej jako stromovou strukturu, jak je definována technologií DOM. Cílem této kapitoly je ukázat objekty pro převod řetězce nebo souboru do DOM struktury (parsing) a obráceně (serializace). Vzhledem k tomu, že použití v Internet Exploreru je mírně liší, budeme uvádět vždy variantu pro IE a pro ostatní prohlížeče. 3.1 Načtení (parsing) XML Pro načtení XML uvedeme celkem čtyři způsoby – načtení ze souboru/z řetězce, načtení v/mimo IE. Příklad 3.1 /*** Načtení ze souboru - Internet Exprorer (včetně verze 8) ***/ xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.load("file.xml"); /*** Načtení ze souboru – ostatní prohlížeče ***/ xmlDoc = document.implementation.createDocument("","",null); xmlDoc.async = false; xmlDoc.load("file.xml"); /*** Načtení z řetězce - Internet Exprorer (včetně verze 8) ***/ xmlDoc = new ActiveXObject("Microsoft.XMLDOM"); xmlDoc.async = false; xmlDoc.loadXML("<root>...</root>"); /*** Načtení z řetězce - ostatní prohlížeče ***/ parser = new DOMParser(); xmlDoc = parser.parseFromString("<root>...</root>","text/xml"); Platí tedy, že v IE používáme ActiveX objekt Microsoft.XMLDOM, přičemž metodou load načítáme soubory a metodou loadXML načítáme řetězec. V ostatních prohlížečích používáme pro načtení z řetězce objekt DOMParser a jeho metodu parseFromString. Pokud použijeme v metodě load relativní cestu k souboru, vyhodnotí se vzhledem k umístění stránky, na které je volající JavaScript. 3.2 Uložení (serializace) XML Pro uložení do souboru definuje rozhraní XML dokumentu metodu save, která ovšem není určena pro použití v prohlížečích (skutečně nefunguje, testováno na Mozilla Firefox 3, IE7). To má své rozumné vysvětlení při pohledu na možné bezpečnostní rizika. Uložit XML jako řetězec lze pomocí XMLSerializer a jeho metody serializeToString. Internet Explorer místo toho nabízí vlastnost xml, která obsahuje textovou reprezentaci dokumentu. Příklad 3.2 //Uložení do souboru – v prohížečích nefunguje!! objXMLDoc.save("C:\Temp\newAlbums.xml") //Uložení do řetězce – mimo IE var serializer = new XMLSerializer(); var xmlText = serializer.serializeToString(objXMLDoc); //Uložení do řetězce – pouze Internet Explorer var xmlText = objXMLDoc.xml; Následující příklad ukazuje, jak je možné sestavit funkci, která bude převádět XML do řetězce nezávisle na prohlížeči, ve kterém bude spuštěna: Příklad 3.3 function xml2Str(xmlNode) { try { // Gecko-based browsers, Safari, Opera. return (new XMLSerializer()).serializeToString(xmlNode); } catch (e) { try { // Internet Explorer. return xmlNode.xml; } catch (e) { // Strange Browser ?? alert('Xmlserializer not supported'); } } return false; } 4 E4X Pro pochopení toho, co je E4X, udělejme nejprve krátkou terminologickou odbočku. Jazyk, který známe pod názvem JavaScript má oficiální název ECMAScript, přičemž zkratka ECMA znamená European Computer Manufacturers Association, což je organizace, která tento standard vytvořila. Pokud tedy nyní řekneme, že E4X znamená "ECMAScript For XML", budeme tím rozumět rozšíření JavaScriptu pro práci s XML. Standard E4X můžeme najít pod označením ECMA-357 např. na adrese http://www.ecmainternational.org/publications/files/ECMA-ST/Ecma-357.pdf, jde o dokument s rozsahem přibližně 100 stran. Jeho první verze byla publikována v červnu 2004, druhá verze v prosinci 2005. Při použití E4X se zachází s XML podobně jako s primitivními typy, přestože samotné XML je objektem. Před uvedením E4X bylo možné zpracovávat XML na objektové úrovni, např. pomocí technologie DOM (Document Object Model). 4.1 Implementace Standard E4X je podporován prohlížečem Mozilla Firefox od verze 1.5. Internet Explorer zřejmě nikdy tento standard podporovat nebude, je však možné použít knihovnu, která E4X poskytuje, ke stažení je např. na http://sourceforge.net/projects/iee4x/. 4.2 Vytvoření XML objektu Existují dva základní způsoby, jak získat objekt reprezentující XML. 1. Přiřazení do proměnné (jako to děláme s primitivními typy). 2. Použití konstruktoru třídy XML s řetězcovým parametrem obsahujícím XML. Oba způsoby je možné vidět na následujícím příkladě. Příklad 4.1 var way_one = <my first='e4x'><some other='tag'>Here</some></my>; var way_two = new XML("<my second='e4x'>Also here</my>"); Při použití prvního způsobu máme možnost vkládat hodnoty jiných proměnných do výsledného XML. Stačí zapsat požadovanou proměnnou do složených závorek. V případě, že chceme doplnit atribut, nemusíme již uvádět uvozovky, budou doplněny automaticky. Viz příklad 3.2: Příklad 4.2 var var var var attr = 42; text = "Hallo world"; foo = <foo rand='27' />; embedded = <say repeat={attr}>{text}{foo}</say>; Jen poznamenejme, že pokud chceme pro hodnotu atributu použít více než jednu proměnnou, nelze psát např. repeat='{a}{b}', ale je potřeba napsat repeat={a+b}, kde místo a+b může být libovolný JavaScriptový výraz. Pro zápis složených závorek do XML lze použít buď znakové entity { a } pro '{' a '}', nebo je možné použít malý trik – nejprve složenou závorku uložit do řetězcové proměnné a následně vložit do xml tuto proměnnou: var zavorka = "{"; var xml = <xml>{zalorka}</xml>; //výstupem je <xml>{</xml} 4.3 Práce s XML objektem Pokud již máme vytvořený objekt reprezentující XML, můžeme s tím začít pracovat. K potomkům daného uzlu přistupujeme pomocí tečkové notace (operátor tečka byl pro tento účel přetížen). Stejně tak můžeme použít hranaté závorky. Příklad 4.3 var person = <person> <name>Bob Smith</name> <likes> <os since='1986'>Linux</os> <browser>Firefox</browser> <language>JavaScript</language> <language>Python</language> </likes> </person>; alert(person.name); alert(person['name']); alert(person.likes.browser); alert(person['likes'].browser); alert(person.likes.os.@since); // // // // // Bob Smith Bob Smith Firefox Firefox 1986 Pro přístup k atributu je použit prefix @. Jednotlivé elementy XML poskytují užitečné metody, jejich význam nejlépe vynikne na příkladě: Příklad 4.4 alert(person.name.text()) var xml = person.name.toXMLString(); var personCopy = person.copy(); var child = person.child(1); var child = person[1]; // // // // // Textový obsah (bez XML značek) Řetězec obsahující XML Hluboká kopie Druhý element v <person> Druhý element v <person> 4.4 Seznamy XML uzlů Pokud výraz zadaný pomocí tečkové notace odpovídá více uzlům, je jeho hodnotou seznam XML uzlů. Pomocí metody length() můžeme zjistit, kolik prvků seznam obsahuje. Je také možné iterovat přes jednotlivé prvky seznamu nebo do seznamu přidávat nové prvky pomocí operátoru +=. Příklad 4.5 alert(person.likes.language.length()); alert(person.likes.*.length()); // Počet elementů <language> - 2 // Počet všech elementů – 4 for(var i = 0; i < person.likes.language.length(); i++) {//Před JavaScriptem 1.6 alert(person.language[i].toString()); } for each (var lang in person.likes.language) { //Od JavaScriptu 1.6 alert(lang); } person.likes += <language>Ruby</language>; //Přidání nového oblíbeného jazyka var empty = <></>; //Vytvoření prázdného seznamu 4.5 Predikáty Pro vyhledávání a filtrování je možné použít predikáty podobně, jak je známe z XPath. Predikát zapisujeme do kulatých závorek, můžeme v něm používat i vlastní JavaScriptové funkce. Přiklad 4.6 var people = <people> <person> <name>Bob</name> <age>32</age> </person> <person> <name>Joe</name> <age>46</age> </person> </people>; function over40(i) { return i > 40; } alert(people.person.(name == "Joe").age); //Věk člověka se jménem Joe alert(people.person.(over40(parseInt(age))).name); //Jméno člověka nad 40 4.6 Editace XML Pomocí E4X můžeme nejen procházet XML dokument, ale také ho upravovat. Pro editaci nebo vložení se používá přiřazení, pro mazání se používá operátor delete. Pokud nastavíme hodnotu atributu, který v XML ještě není, vytvoří se nový. Příklad 4.7 person.name = "Jakub Jelínek"; person.likes.os.@since = 2004; person.likes.os.@new_attribute = 'foo'; person.likes.*[2] += <foo/>; //Vloží za třetího syna elementu <likes> person.likes += <foo/>; //Vloží jako posledního syna elementu <likes> delete delete delete delete order.customer.address; order.customer.@id; order.item[0].price[0]; order.item; // // // // Smaže Smaže Smaže Smaže element <address> atribut ID první element <price> v prvním <item> všechny elementy <item> 4.7 Spolupráce DOM a E4X Někdy nastane situace, že bychom potřebovali pomocí E4X zpracovat nějaké XML a potom jeden nebo více uzlů přidat do DOM struktury (např. do právě zobrazovaného dokumentu). Standard E4X uvádí ve svém dodatku doporučení, že by mohla existovat metoda domNode(), která by převedla E4X uzel na odpovídající DOM uzel. Obdobně je doporučena metoda domNodeList(). Přes tato doporučení nejsou tyto metody implementovány v prohlížečích (Mozilla Firefox 3, IE8). Pokud je tedy potřeba vložit E4X uzel do DOM stromu, je potřeba to udělat „ručně“. Příklad metody, která toto udělá, lze najít na http://ecmanaut.blogspot.com/2006/03/e4x-and-dom.html. „Ruční“ vložení E4X uzlu do DOM stromu spočívá v několika krocích. Nejprve se E4X uzel převede na řetězec voláním metody toXMLString(), následně se tento řetězec naparsuje pomocí třídy DOMParser, čímž vznikne DOM uzel, který vložíme pomocí metody appendChild(). Pro převedení DOM uzlu na E4X objekt se postupuje podobně. Nejprve se převede DOM uzel na řetězec (např. za použití metody xml2Str uvedené v příkladu 3.3). Tento řetězec se pak použije v konstruktoru třídy XML. 5 Zdroje 5.1 Podpora pro XPath v Javascriptu • Document Object Model XPath, W3C Working Group Notes, http://www.w3.org/TR/DOMLevel-3-XPath/xpath.html • Introduction to using XPath in JavaScript, Mozilla Developer Center, https://developer.mozilla.org/en/Introduction_to_using_XPath_in_JavaScript • Professional Javascript for Developers, Wrox, Nicholas C. Zakas, http://www.wrox.com/WileyCDA/Section/XPath-Support-in-Browsers-Page-2.id291861.html • XPath examples, W3C Schools, http://www.w3schools.com/XPath/xpath_examples.asp • JavaScript XPath Implementation Benchmark, http://www.llamalab.com/js/xpath/benchmark.html 5.2 Parsing a serializace XML • DOM Parser Tutorial, W3C Schools, http://www.w3schools.com/Dom/dom_parser.asp • XML DOM Tutorial, W3C Schools, http://www.w3schools.com/DOM/default.asp 5.3 E4X • E4X Tutorial, W3C Schools, http://www.w3schools.com/e4x/default.asp • ECMAScript for XML, Wikipedia, http://en.wikipedia.org/wiki/ECMAScript_for_XML • Processing XML with E4X, Mozilla Developer Center, https://developer.mozilla.org/index.php? title=En/Core_JavaScript_1.5_Guide/Processing_XML_with_E4X • Standard ECMA-357, ECMA International, http://www.ecma-international.org/publications/ files/ECMA-ST/Ecma-357.pdf