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 &#x7B; a &#x7D; 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