Obsah
Z předchozího popisu je patrné, že RAINBOW je již poměrně komplikovaný systém, při jehož implementaci se musíme vypořádat s řadou praktických úkolů. Musíme uchovávat zdrojové webové stránky a z nich získané znalosti, zajistit komunikaci různých programových komponent a prezentaci informací uživateli. Abychom nemuseli používat příliš rozdílné nástroje a formáty, rozhodli jsme se v maximální možné míře využít jazyk XML a návazné technologie. Zároveň jsem chtěl ověřit, na co všechno lze XML použít, a jaké jsou jeho limity zejména při rychlosti zpracování.
XML (eXtensible Markup Language) [6] je jednoduchý značkovací jazyk, který umožňuje uchování dat téměř libovolného typu. V odvozených formátech založených na XML můžeme používat vlastní značky a s jejich pomocí zachytit význam a vztah mezi jednotlivými informacemi (viz např. [24]). Syntaxe však vždy vychází z jazyka XML, a proto můžeme používat již existující standardní knihovny pro zpracování XML dokumentů. To nám může ušetřit spoustu práce.
Kromě toho je nad XML vystaveno mnoho dalších užitečných jazyků, které lze v aplikaci využít. Hlavní výhoda spočívá v tom, že se používají známé technologie a že i pro tyto jazyky jsou k dispozici již existující knihovny. V následujícím přehledu se podíváme na některé XML jazyky a technologie, které úzce navazují na XML, a posoudíme možnost jejich využití v RAINBOW.
Popisovat na tomto místě syntaxi XML by bylo asi zbytečné. Připomeňme si tedy jen, že XML dokument se skládá z pojmenovaných elementů. Každý element přitom může obsahovat text a další vnořené elementy. XML dokument si tak lze představit jako hierarchickou stromovou strukturu. Tato datová struktura je velmi oblíbená a lze do ní uložit v podstatě libovolné informace. Každý element může mít u sebe přítomných ještě několik atributů, což jsou uspořádané dvojice obsahující jméno atributu a jeho hodnotu.
Z teoretického hlediska je pro XML velmi důležitý pojem tzv. infosetu – informační množiny (XML Information Set) [10]. Z historických důvodů popisuje standard jazyka XML [6] přímo syntaxi jazyka, nezabývá se datovým modelem, který XML dokumenty používají. Tento přístup sice umožnil celkem rychlé přijetí XML a jeho širokou podporu v aplikacích, na druhou stranu poněkud kompikuje vývoj dalších standardů navazujících na XML, zejména programátorských rozhraní (API) pro čtení XML dokumentů a dotazovacích jazyků.
Infoset definuje abstraktní datový model pro XML dokumenty. Model přitom vychází ze stromové struktury, kde má každý uzel definovány vlastnosti popisující jeho typ a další navázané uzly (tj. vnořené elementy, atributy apod.). Na rozdíl od samotného standardu XML již infoset neoperuje s jednotlivými znaky v souboru, ale s elementy, atributy, textovým obsahem elementů apod. Je tedy o jednu úroveň abstrakce výše než samotný standard XML, který přesně popisuje syntaxi XML pomocí EBNF.[2]
Pokud potřebujeme do XML ukládat nějaký druh informací, vytvoříme si pro tento účel obvykle vlastní značkovací jazyk, vlastní sadu značek. Rozhodneme se tedy, jak se budou jednotlivé elementy jmenovat a jak mohou být navzájem kombinovány. Tuto definici můžeme zapsat i formálně pomocí nějakého jazyka pro popis schématu dokumentu jako jsou DTD, XML schémata (XML Schema) nebo Relax NG.
Problém ovšem nastane, chceme-li v jednom dokumentu použít více sad značek – může dojít například ke konfliktu názvů elementů apod. Tento problém řeší jmenné prostory [7]. Jedná se o samostatný standard, který velmi úzce doplňuje samostný standard XML. Dokonce se plánuje, že v dalším vydání standardu XML bude vše shrnuto v jednom dokumentu.
Jmenné prostory fungují na jednoduchém principu. Každý element a atribut může být přiřazen ke jmennému prostoru, který je identifikován URI adresou. Pro zkrácení zápisu se pak v XML dokumentu deklarují pro použité jmenné prostory krátké prefixy, které se používají pro přiřazení elementu nebo atributu do určitého jmenného prostoru. Z následující ukázky je patrné, jak se zápis zkrátí, neboť poměrně dlouhé URI je v dokumentu uvedeno jen jednou.
<a:x xmlns:a="urn:x-pokus:a" xmlns:b="urn:x-pokus:b"> <a:y>Obsah elementu Y ve jmenném prostoru urn:x-pokus:a</a:y> <b:y>Obsah elementu Y ve jmenném prostoru urn:x-pokus:b</b:y> </a:x>
XML nám sice umožňuje libovolné pojmenování elementů, ale pro většinu praktických aplikací není přílišná volnost žádoucí. Pro každou třídu XML dokumentů proto můžeme pomocí speciálního jazyka přesně formálně definovat, jaké elementy lze v dokumentu použít, jaké mohou mít atributy a obsah. Těmto jazykům se říká jazyky pro definování schématu dokumentu.
Historicky nejstarším a nejznámější je bezesporu definice typu dokumentu – DTD (Document Type Definition), která vznikla již pro jazyk SGML a byla převzata i do XML.
DTD pro současné aplikace v mnoha ohledech nedostačují. Jejich asi největším problémem je špatná podpora jmenných prostorů a datových typů. Postupem času proto vznikly i další jazyky pro popis schématu, které nedostatky DTD odstraňují. Nejpoužívanější jsou dnes XML schémata [14], která jsou standardem W3C. Jedná se o jazyk postavený na definici datových typů, který nabízí mnoho funkcí – včetně definovaní vlastních datových typů, referenční integrity a integritních omezení. Problém XML schémat je v tom, že se jedná o poměrně složitý standard, kde jde jednu věc dělat mnoha různými způsoby. Nicméně velké IT firmy včetně Microsoftu XML schémata podporují (Microsoft na nich ostatně založil kompletní práci s relačními daty v .NET Frameworku).
Alternativou k XML schématům je jazyk Relax NG [8], který je podobně jako DTD postaven na definici gramatiky a pro většinu použití je tedy mnohem jednodušší než XML schémata. Lze v něm navíc určit i datové typy. V současné době probíhá standardizační proces na půdě organizace ISO [18].
Pokud máme k dokumentu schéma, můžeme během čtení kontrolovat, zda dokument schématu vyhovuje. Provádíme pak tzv. validaci. Výhodou tohoto přístupu je především zjednodušení aplikací – ty již nemusí kontrolovat tolik chybových stavů ve vstupních datech, mnoho chyb odhalí již validace.
Validace přináší ještě jeden důležitý koncept, který využívají především dotazovací jazyky nad XML. Ke každému XML dokumentu existuje jeho abstraktní reprezentace v podobě infosetu. Pokud máme k dokumentu schéma, můžeme podle něj jednotlivým uzlům infosetu přiřadit datové typy – získáme tak tzv. PSVI (Post-Schema Validation Infoset) – otypovaný infoset. V dokumentu již nejsou všechna data chápána jako textové řetězce, ale jako konkrétní datové typy – čísla, datumy, řetězce, měnové údaje apod. Nad PSVI již můžeme budovat dotazovací jazyk, který dokáže jednoduše provádět operace jako řazení či výpočty agregačních funkcí, jež jsou závislé na datovém typu zpracovávaných údajů.
Pokud chceme s XML dokumenty pracovat v nějaké aplikaci, nemusíme si sami psát analyzátor XML, ale může využít některý z mnoha již existujících parserů. Parser[3] je program nebo programátorská knihovna, jež čte XML dokument ze souboru (nebo z jiného zdroje – např. z webového serveru přes HTTP protokol) a stará se o nízkoúrovňovou syntaktickou analýzu XML dokumentu – za menšítkem (<) očekává název elementu, extrahuje hodnotu atributu uzavřeného v uvozovkách nebo apostrofech apod. Přes programátorské rozhraní (API) pak parser nabízí abstraktní model XML dokumentu – infoset.
Samotný XML dokument resp. jeho infoset nám může být nabízen několika způsoby a historicky se proto vyvinulo několik různých API, které se hodí pro různé aplikace.
První parsery nabízely rozhraní řízené událostmi. Parser postupně četl XML dokument a volal naše funkce pro obsluhu důležitých událostí, jako začátek a konec elementu, textový obsah elementu apod. Funkci byly navíc předány další důležité parametry – například název elementu, seznam atributů apod.
Událostmi řízené zpracování XML dokumentu má dvě velké výhody – je rychlé a má malé paměťové nároky. V aplikacích, kde je hlavní důraz kladen na rychlost, se proto tento přístup používá nejčastěji. Nevýhodou je naopak nutnost zpracovat XML dokument během jednoho sekvenčního průchodu. Zejména začínající programátoři mají s touto technikou problémy, neboť důležité informace si programátor musí pamatovat ve vlastních stavových proměnných apod.
Asi nejznámější rozhraní používající událostmi řízený přístup je SAX (Simple API for XML) [31]. Toto rozhraní vzniklo velmi rychle jako výsledek společného úsilí několika vývojářů e-mailové konference xml-dev. Původně byl SAX navržen pro Javu, ale existují jeho implementace pro mnoho dalších jazyků. V současné době se již používá novější verze rozhraní SAX2, která podporuje jmenné prostory a některé další užitečné vlastnosti.
Pro práci programátora je mnohem pohodlnější, když může kdykoliv přistupovat k libovolné části XML dokumentu. Aby to bylo možné, je nutné načíst celý dokument do vhodné paměťové struktury. XML dokumenty a jejich strukturu lze velmi přirozeně modelovat pomocí stromu. Nejznámější rozhraní, které pracuje se stromovou reprezentací dokumentu, je DOM (Document Object Model) [19]. Toto rozhraní vytvořilo W3C konsorcium a je zcela nezávislé na použitém jazyku. XML dokument je zpřístupněn pomocí objektů, které zastupují jednotlivé důležité prvky – elementy, atributy, textový obsah, komentáře apod. Každý objekt odpovídá jednomu uzlu ve stromu XML dokumentu a nabízí metody pro zjištění svého typu a hodnoty, svých dětí a rodičů.
Strom dokumentu můžeme procházet libovolně a opakovaně. Díky tomu je zpracování XML dokumentu velmi jednoduché. Zaplatíme za to nižší rychlostí a velkou paměťovou náročností. Při načítání XML dokumentu do paměti musíme počítat s tím, že dokument v paměti zabere v závislosti na použité implementaci dvakrát až desetkrát více prostoru než v souboru. U souborů s hodně elementy a atributy je navíc načtení dokumentu dost pomalé, protože se pro každý element a atribut vytváří v paměti objekt.
Na rozdíl od rozhraní SAX sloužícího pouze pro čtení XML dokumentů, umožňuje DOM s reprezentací XML dokumentu v paměti manipulovat, dokonce můžeme vytvořit nový XML dokument přímo v paměti. Je poněkud zarážející, že současná verze DOMu nenabízí standardní metody pro načtení a uložení XML dokumentu, takže každý parser je musí řešit po svém. Tento nedostatek odstraňuje až právě připravovaná verze DOM3.
Rozhraní DOM má za sebou poměrně dlouhou historii sahající do poloviny 90. let minulého století. O DOM se poprvé hovořilo v souvislosti s JavaScriptem a jazykem HTML. JavaScript mohl přes rozhraní DOM pracovat s důležitými informacemi na stránce zobrazené ve webovém prohlížeči – přístupné byly např. obrázky, formuláře a rámy. Další rozvoj DOM vyústil až v dynamické HTML, které umožňuje vytvářet skutečně interaktivní stránky. Velkým problémem však byla (a bohužel stáje ještě trochu je) nekompatibilita DOM rozhraní v jednotlivých prohlížečích. W3C konsorcium proto toto rozhraní standardizovalo a vznikl tak DOM1, který ve skutečnosti obsahuje dvě velmi odlišná rozhraní. Jedno pro práci s HTML dokumenty a druhé pro zpracování XML – tzv. XML Core. Tato část rozhraní je pak podporována DOM XML parsery. Další verze rozhraní DOM2 přinesla zejména podporu jmenných prostorů. Navíc byla přidána další rozhraní, která umožnila mj. snazší průchod stromem dokumentu. Do té doby bylo nutné pro průchod stromem využívat nestandardní třídy (tzv. treewalkery) nebo si psát vlastní kód, který obvykle rekurzivně procházel strom.
DOM a SAX poskytují velmi komplexní podporu pro čtení XML dokumentů. Postupem času se však ukázalo, že pro typické úlohy je jejich použití zbytečně komplikované. Během necelých posledních dvou let se proto stále častěji objevují nová rozhraní nebo rozšíření těch stávajících, která mají jeden společný cíl – usnadnit programátorům práci s XML dokumenty. Autoři těchto nových přístupů mají na mysli zejména zkrácení doby nutné na naučení práce s novým rozhraním a na zkrácení délky kódu nutného pro provedení určité operace (což je ekvivalentní se zkrácením doby vývoje aplikace).
Po počátečním nadšení z rozhraní DOM většina vývojářů zjistí, že je poměrně pracné napsat kód, který zpracuje určité specifické části dokumentu. Přišlo se proto s možností položit nad DOM stromem jednoduchý dotaz, který vybere jen určité uzly stromu – tedy určité elementy, atributy či textové uzly. Jasným kandidátem na takový dotazovací jazyk je XPath (XML Path Language), který se používá v mnoha dalších XML standardech (XSLT, XML schémata, XPointer aj.). XPath umožňuje zadávat jednoduché dotazy, podobné cestě v adresářové struktuře disku, které vybírají části ze struktury XML dokumentu.
Zjednodušení se dočkaly i parsery, které pracují nad XML dokumentem sekvenčně. O parserech podporujících rozhraní SAX se někdy říká, že jsou to tzv. push parsery – tlačí do aplikace proud událostí odpovídající jednotlivým prvkům XML dokumentu. Tento na událostech postavený přístup není všem programátorům vlastní, a tak vznikly pull parsery. Mají všechny přednosti událostmi řízených parserů – rychlost a paměťovou nenáročnost – a navíc se s nimi velmi jednoduše pracuje. Programátor si podle potřeby říká o další a další části dokumentu a parser mu je postupně předává, dokud nedorazí na konec dokumentu.
Pro potřeby systému RAINBOW musíme načítat webové stránky a ty pak analyzovat různými metodami. Pro úspěšnou analýzu dokumentu potřebujeme znát i strukturu webových stránek. To by teoreticky neměl být problém, protože HTML stránky by měly odpovídat standardu SGML [23] a pro jejich snadné čtení by tedy mělo jít využít SGML parser, který nám zpřístupní i informace o struktuře dokumentu.
Většina SGML parserů je ovšem pro naše účely příliš těžkopádná a navíc většina současných webových stránek standardu HTML (a tím pádem ani SGML) nevyhovuje, protože obsahuje spoustu syntaktických chyb. Poměrně snadno však můžeme pomocí programu HTML-Tidy odstranit ze stávajících HTML stránek syntaktické chyby a převést je do formátu XML. Tím získáme dokumenty, které půjde snadno číst pomocí velkého množství dostupných XML parserů a navíc budeme mít zpřístupněnou strukturu dokumentů.
Tento přístup – převod HTML stránek do XML – se nám vyplatí i z dlouhodobějšího hlediska, protože se na webu začínají postupně objevovat stránky, které jsou zapsány přímo v XML nebo v XHTML, což je nástupce jazyka HTML založený na XML syntaxi. Tím, že analytické moduly budou již od počátku připraveny na zpracování XML, nebude v budoucnu problém se zpracováním nové generace webu založené na XML.
[2] Extended Backus-Naur Form (EBNF) je často používaný způsob zápisu bezkontextové gramatiky.
[3] Správně bych měl používat pojem „parser XML“, protože pojem parser obecně označuje libovolný syntaktický analyzátor, ne jen ten specializovaný na XML. Pro snazší čitelnost textu přívlastek XML neuvádím.