1 České vysoké učení technické v Praze Fakulta elektrotechnická ČVUT FEL katedra počítačů Diplomová práce Rozšiřitelný editor XML dokumentů Tomáš Divi...
České vysoké učení technické v Praze Fakulta elektrotechnická
ˇ VUT FEL katedra pocˇı´tacˇu˚ C
Diplomová práce
Rozšiřitelný editor XML dokumentů Tomáš Diviš
Vedoucí práce: Ing. Martin Kačer
Studijní program: Elektrotechnika a informatika dobíhající magisterský Obor: Informatika a výpočetní technika leden 2007
ii
iii
Poděkování Děkuji svým rodičům za podporu v celém průběhu mého studia. Dále děkuji mému vedoucímu diplomové práce Ing. Martinu Kačerovi za pomoc a nápady pro mou práci.
iv
v
Prohlášení Prohlašuji, že jsem svou diplomovou práci vypracoval samostatně a použil jsem pouze podklady uvedené v přiloženém seznamu. Nemám závažný důvod proti užití tohoto školního díla ve smyslu §60 Zákona č. 121/2000 Sb., o právu autorském, o právech souvisejících s právem autorským a o změněa některých zákonů (autorský zákon).
Abstract This work presents a program for editing XML files. In the first part XML schemes are analyzed, namely DTD schemes, W3C XML schemes and Relax NG schemes. The second part presents a program for editing XML files, which uses XML schema to assist users while creating and editing XML. Strengths of this program are extensibility, portability and usage of alternative XML syntax, which is simpler to create and more human friendly. Main features of the program are auto-completion and automatic validation against XML schema.
vii
Abstrakt Tato práce pojednává o tvorbě speciálního editoru XML souborů. První část se věnuje XML schématům, konkrétně DTD schématům, W3C XML schématům a Relax NG schématům. Druhá část prezentuje program pro editaci XML souborů, který využívá možnosti XML schématu pro ulehčení práce při vytváření a editaci XML. Přednostmi programu jsou rozšířitelnost, multiplatformnost a použití alternativní syntaxe XML, která je pro člověka lépe čitelná. Program podporuje vlastnosti jako jsou automatické dokončování a automatická kontrola validace oproti XML schématu během psaní dokumentu.
1 Úvod Formát XML je textový formát, který je v dnešní době hojně používán. Jeho použití je velmi různorodé, od ukládání dat všeho druhu až po psaní textových dokumentů jako jsou internetové stránky. K jeho přednostem patří rozšířitelnost, jasně specifikované standardy a tím pádem také možnost zpracování na téměř jakékoliv platformě. Základními prvky jazyka XML jsou elementy, které se skládají z počáteční a koncové značky a obsahu mezi nimi. Počáteční značka dále může obsahovat atributy. Rozšířitelnost jazyka spočívá v tom, že si každý může vytvořit své vlastní elementy a atributy. Ale aby mohl být takový dokument automaticky zpracován dalším programem, musí být zřejmá struktura takto zaznamenaných dat, tj. jaké elementy a atributy dotyčný použil, jak se do sebe mohou vnořovat apod. Z toho důvodu vznikla tzv. XML schémata, která popisují strukturu takto zaznamenaných dat. XML schéma je tedy jakýmsi předpisem, který říká, jaká data jsou v XML dokumentu přípustná a v jaké struktuře mohou být zapsána. Programy potom mohou pomocí XML schématu ověřit, zda konkrétní dokument odpovídá tomuto schématu a tedy zda je možné bez problémů tento dokument zpracovat. Struktuře definované XML schématem se také někdy říká XML aplikace. Nejznámějšími XML aplikacemi jsou např. XHTML pro tvorbu webových stránek nebo DocBook pro psaní technické dokumentace. V jednom dokumentu můžeme používat i více XML aplikací. Např. do dokumentu napsaného v DocBooku můžeme vkládat SVG (XML aplikace popisující vektorovou grafiku), nebo MathML (popisuje matematické vzorce). Doposud jsme mluvili o programech, které používají XML pro ukládání a výměnu dat. Se zdrojovým kódem XML dokumentů však přicházejí do styku i lidé. Ačkoli je XML textový formát, pro člověka je až příliš „upovídanýÿ a také hůře čitelný. Proto pro textové dokumenty vznikají různé grafické editory typu WYSIWYG („What you see is what you getÿ česky „co vidíš, to dostanešÿ), kde je uživatel odstíněn od zdrojového XML kódu. Avšak člověk často potřebuje měnit či vytvářet i zdrojový kód datových XML souborů. Příkladem mohou být stále se rozmáhající konfigurační XML soubory pro různé programy v unixovém světě. Oproti klasickým textovým souborům mají XML soubory výhodu v jednodušším zpracování programem, avšak unixový administrátoři z nich nebývají moc nadšeni, právě protože jsou většinou hůře čitelné a náročnější na vytváření. Z toho důvodu i zde prezentovaný editor XML souborů používá speciální alternativní syntaxi, která je stručnější a lépe čitelná pro člověka. Základními rysy jsou používání méně speciálních znaků, vypuštění koncové značky a s tím související odsazování bloků. Další věcí, která může člověku usnadnit editaci XML dokumentu, je použití tzv. automatického dokončování. To je umožněno XML schématem, které XML editor načte a podle struktury v něm obsažené může uživateli napovídat, jaké elementy a atributy v daném místě může dokument obsahovat, a případně dokončovat jejich názvy. Velmi užitečnou vlastností XML editoru může být také automatická validace (ověření správnosti) podle XML schématu za běhu. Uživatel je tedy během editování upozorněn na nesprávnost vytvářeného dokumentu (například podtržením), tudíž je téměř nemožné, aby vytvořil nevalidní dokument.
2
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
2 Popis problému, specifikace cíle V dnešní době se často používá textového formátu XML k výměně různorodých dat. XML je používáno kvůli své jednoduchosti a jasné specifikaci, která umožňuje jednoduché zpracování dat softwarovými nástroji. XML tedy nejčastěji používají počítačové programy. Často však nastávají situace, kdy je člověk nucen k editaci zdrojového kódu XML. Nejčastějším příkladem je vytváření dokumentů jako jsou XHTML. Další příklad, který v dnešní době nastává stále častěji, je editace konfiguračních souborů k programům, která nahrazuje tradiční textové konfigurační soubory známé například z unixových systémů. Pro unixové administrátory (ale i obyčejné uživatele používající takový program), je editace takovýchto souborů náročná s porovnáním editace obyčejného textového souboru. Je to z důvodů přílišné upovídanosti XML (například nutnost psát dvakrát jméno elementu v počáteční a koncové značce), a používání relativně velkého množství speciálních znaků, které se nepíšou snadno a na některých národních klávesnicích se ani nevyskytují. Právě především pro účely editace konfiguračních souborů v XML jsem se rozhodl vytvořit editor, který by uživatelům tuto práci co nejvíce usnadnil. Nicméně předpokládám možnost použití i pro jiné účely, především datově orientované XML dokumenty. Budu se tedy specializovat spíše na tyto typy dokumentů a nikoliv směrem k textově orientovaným dokumentům jako např. XHTML.
2.1
Funkce editorů zdrojového kódu XML
Pro usnadnění editace textových souborů, které odpovídají nějaké předem známé gramatice, se nejčastěji používá zvýraznění syntaxe. To rozdělí text do určitých částí podle významu a tyto části barevně odliší. Uživateli tak zvýší čitelnost a orientaci v kódu. Např. ve zvýrazněné syntaxi pro XML uživatel na první pohled rozezná značky a atributy XML od textového obsahu těchto značek. Dalším prvkem, který je užitečný pro práci se zdrojovým kódem XML, je zkontrolování, zda je dokument správně formulovaný (well-formed). Takový dokument vyhovuje gramatice specifikované ve standardu XML a je proto zaručené, že jej mohou programy zpracovat (nejedná se zde však o strukturu dat, ta může být stále chybná). Významné ulehčení práce uživateli může být dosaženo pomocí XML schémat. Je jim věnována celá kapitola 3. Zjednodušeně řečeno, XML schéma obsahuje předpis struktury, v jaké se data v dokumentu vytvořeném podle tohoto schématu mohou vyskytovat. Jedná se např. o to, jaké elementy a atributy může dokument obsahovat a jak je lze do sebe vnořovat. Tyto informace lze použít právě k ulehčení práce uživateli editoru zdrojového kódu XML. Je možné, aby editor pomocí aktuálního stavu dokumentu a struktuře načtené z XML schématu napovídal uživateli, jaké prvky je možno použít v místě editace. To lze rozšířit o tzv. automatické dokončování (auto-completion), což znamená, že rozepsané jméno elementu nebo atributu může být dokončeno pomocí výběru z těchto prvků. Samozřejmostí je potom ověření správnosti (validace) dokumentu oproti načtenému schématu. Ideální je, aby toto editor dělal průběžně během editace a dal zřejmým způsobem uživateli najevo případné odchýlení od schématu (například podtrhnutím místa, kde vznikla chyba). Použití XML schématu pro možnosti automatického dokončovaní a validace je velmi efektivní, ale pokud uživatel edituje jeden druh dokumentu velmi často, uvítá i další možnosti. Proto je vhodné, pokud je editor rozšířitelný pomocí různých maker a dalších modulů. Velmi netradičním ulehčením uživatelům editoru zdrojového kódu XML může být použití
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE
3
alternativní syntaxe XML, jako je např. SOX (Simple Outline XML) [3] nebo SLiP [9]. Takové alternativní syntaxe snižují množství psaného textu a speciálních symbolů, tudíž se zdrojový kód snáze vytváří. Zároveň se také člověk v takovémto textu daleko lépe orientuje, což je neméně důležité. Co by dle mého názoru editoru jakéhokoliv zdrojového textu nemělo chybět, je možnost efektivního používání klávesnice. Vzhledem k tomu, že při psaní textu má uživatel ruce na klávesnici, je pro něj zdržení přesouvat ruce z klávesnice na myš a zpět. Proto by editor měl mít systém klávesových zkratek, který se pokud možno dá přizpůsobit zvyklostem uživatele. Pro uživatele píšící všemi deseti může být nepříjemné i přesouvání ruky ze základní pozice na kurzorové klávesy. Editor by proto měl umožnit uživateli namapovat i základní navigační akce jako jsou posuny kurzoru na klávesové zkratky, čímž se toto přesouvání minimalizuje.
2.2
Další požadavky
Vzhledem k tomu, že XML je, jak již bylo řečeno, používáno na mnoha platformách, i editor by měl mít tu možnost a potenciál se uplatnit na více platformách. Sice vývoj multiplatformních aplikací bývá často náročnější, než vývoj pro jednu konkrétní, ale v tomto případě to dle mého názoru bude užitečné. I programy používající XML konfigurační soubory často bývají k dispozici pod více platformami. Jak s multiplatformností, tak s požadavkem na rozšířitelnost pomocí modulů souvisí použití některého z interpretovaných jazyků. Jsou dvě možnosti, jak provést začlenění takového jazyka. První možnost je napsat program v normálním kompilovaném jazyce a udělat navázání interpretovaného jazyka na tyto funkce. Druhá možnost je psát program přímo v takovém jazyce a případně využít již hotových knihoven kompilovaných jazyků (např. z důvodů rychlosti či odladěnosti takovýchto knihoven). Takový jazyk však musí podporovat možnost využívání knihoven napsaných v kompilovaných jazycích. S rozšířitelností také souvisí otevřenost takového programu. Proto by měl být program licencovaný pod open source licencí. Potom při veřejném vydání může vzniknout komunita, která editor dále vylepšuje a vytváří nové funkce, či vylepšuje stávájící.
2.3
Shrnutí požadavků
Bude se jednat o XML editor se zaměřením na datové XML dokumenty, jako například konfigurační soubory k programům. Shrnutí požadavků napsaných v předchozích dvou kapitolách: • Zvýrazněná syntaxe • Kontrola, zda je XML dokument správně formulovaný (s grafickým znázorněním chyby) • Automatické dokončování (auto-completion) XML tagů a atributů dle XML schématu • Validace oproti XML schématu (s grafickým znázorněním chyby) • Použití alternativní XML syntaxe (pro člověka čitelnější a jednodušší) • Rozšířitelnost v podobě modulů • Systém klávesových zkratek • Multiplatformnost
4
KAPITOLA 2. POPIS PROBLÉMU, SPECIFIKACE CÍLE • Open source licence • Interpretovaný jazyk (alespoň pro moduly)
KAPITOLA 3. XML SCHÉMATA
5
3 XML Schémata 3.1 3.1.1
Stručný úvod do XML Původ XML
Původ značkovacích jazyků (jedním z nich je i XML) sahá zhruba k začátkům 70. let. Jeden z prvních značkovacích jazyků byl GML (Generalized Markup Language), který se zrodil ve firmě IBM. Důvodem jeho vzniku byla potřeba označkovat části textu nejen pro určení jejich vzhledu, ale i jejich významu [8]. Princip jazyka GML se osvědčil, a proto v 80. letech vznikly nové značkovací jazyky. Přirozeně se objevila potřeba standardizace, a proto společným snažením několika sdružení vznikl standard SGML (Standard Generalized Markup Language). Obecnost jazyka SGML byla veliká, šlo vytvářet vlastní jazyky (soubory značek) definované pomocí jazyka DTD (Document Type Definition). Asi nejznámější z nich je HTML. Postupem času se zjistilo, že jazyk SGML je příliš komplexní a že se mnohé jeho části vůbec nevyužívají. Potřeba jednoduchého značkovacího jazyka vyústila vznikem nového jazyka, kterým je právě XML. Ten tvoří podmnožina jazyka SGML, která byla nejčastěji používána. XML se velmi rychle rozšířilo, protože díky své jednoduchosti je pro něj snadné implementovat parser a vývoj aplikací je tak levnější.
3.1.2
Syntaxe XML dokumentu
Základním prvkem XML dokumentu jsou elementy. Každý element má počáteční a koncovou značku (značce se někdy také říká „tagÿ), která se skládá ze speciálních znaků a jména elementu. Počáteční značka je uvozena znakem „<ÿa končí znakem „>ÿ. Koncová značka je uvozena dojicí znaků „ÿ a končí znakem „>ÿ. Výjimkou je prázdný element, který může být zapsán jednou značkou uvozenou znakem „<ÿa končící znaky „/>ÿ. Následující příklad znázorňuje klasický zápis elementu i zápis prázdného elementu jednou značkou. <element1>obsah <prazdny1> <prazdny2/> Dále element může obsahovat atributy. Ty jsou od jména elementu (a mezi sebou) odděleny mezerou. Za jménem atributu je znak „=ÿ a v uvozovkách příslušná hodnota atributu. Element s dvěma atributy může vypadat např. takto: <element2 atribut1="hod1" atribut2="hod2">obsah Obsahem elementu pak může být text nebo opět další elementy. Vzniká tak hierarchická struktura. V textovém obsahu se dále mohou vyskytovat tzv. entity. Ty se nejčastěji používají pro zápis speciálních znaků. Entita je uvozena znakem „&ÿ a je ukončena znakem „;ÿ. Mezi těmito znaky se nachází buď jméno entity nebo číselná hodnota zapsaná za znakem „#ÿ. Číselná hodnota může být zapsána i hexadecimálně, v takovém případě je před ní uvedeno písmeno „xÿ. Následují příklady všech zápisů:
Následující entity představují stejný znak (menší než):
6
KAPITOLA 3. XML SCHÉMATA
< < <
Pokud je tento příklad zpracován např. jako XHTML odstavec, na výsledné webové stránce se objeví místo entit znak „<ÿ.
3.1.3
Well-formed XML dokument
Aby se dal dokument zpracovat, musí splňovat několik pravidel. Potom se o dokumentu dá prohlásit, že je well-formed. Pravidla jsou následující [12]: 1. Dokument musí mít právě jeden kořenový element. 2. Každý element musí být uzavřený. 3. Elementy musí být správně vnořovány (nesmí se křížit). 4. Všechny hodnoty atributů musejí být uzavřeny v uvozovkách. 5. Jména elementů a atributů jsou case-sensitive (citlivá na malá a velká písmena).
3.1.4
K čemu je XML schéma dobré
Jednou z důležitých vlastností, proč je XML formát používán, je jeho snadná možnost rozšíření o další tagy a atributy. Na druhou stranu si potřebujeme data uložená v XML mezi sebou vyměňovat, a proto je nutné, aby druhá strana datům rozuměla. Je tedy zapotřebí nějakým způsobem specifikovat, jak ona data budou vypadat. K tomu souží právě XML schémata. XML schémata tedy jednoznačně specifikují, jakým způsobem může XML dokument vypadat, např. jaké konkrétní atributy může mít daný element, kolikrát se může opakovat, jaké elementy je možné do něj vnořovat apod. Tím specifikujeme strukturu, kterou potom budou očekávat např. programy pro zpracování takového XML souboru. Program, který zpracovává daný XML soubor, nejdříve provede validaci tohoto souboru oproti danému XML schématu a pokud není dokument validní, může ho odmítnout. To může velmi usnadnit práci programátorům, kteří potom nemusí provádět kontroly pro každý vstupní údaj z XML dokumentu. Tím se můžou výrazně snížit náklady na vývoj takového softwaru.
3.1.5
Validita
Pokud XML dokument splňuje formát předepsaný daným schématem, říkáme že je validní. Před tím, než můžeme provádět validitu, samozřejmě musí být XML dokument správně formulován (viz. 3.1.3). Během vývoje XML se uchytilo několik typů schémat. O nich budou následující podkapitoly. Nejstarší z nich je DTD schéma, které je součástí samotné specifikace XML. Novější a mocnější pak W3C XML schéma, které je doporučením organizace W3C. Nejnovějším je pak velmi mocné a elegantní schéma Relax NG.
KAPITOLA 3. XML SCHÉMATA
3.2
7
DTD schéma
DTD schéma je nejstarší schéma a v dnešní době už v mnohém nedostačuje, přesto se stále ještě často používá, pro svou jednoduchost a dobrou podporu v softwaru. Jeho největším nedostatkem je asi to, že nepodporuje datové typy a jmenné prostory. Zvláštní je také to, že ač se jedná o XML schéma, samotné DTD není v XML formátu.
3.2.1
Elementy a atributy
DTD schéma zachycuje hierarchickou strukturu vnořování elementů a jejich atributů. Ty jsou obsaženy ve značkách uvozených znaky „ÿ. Elementy se deklarují značkou ELEMENT, která obsahuje jméno elementu a co daný element může nebo musí obsahovat: Obsah elementu nejčastěji obsahuje element nebo seznam elementů, které může obsahovat. Seznam elementů se uvádí v kulatých závorkách. Pokud chceme vyjádřit to, že daný element obsahuje už pouze text, tak zde uvedeme slovo #PCDATA. Obsah elementu také může obsahovat slovoEMPTY, které značí, že element musí být prázdný, nebo naopak ANY, které znamená, že daný element může obsahovat jakýkoliv element nebo i text. Slovo ANY se však používá zřídka, protože moc uvolňuje strukturu dokumentu. Příklady: Seznam elementů, které daný element může obsahovat, může být buď oddělen znakem „,ÿ nebo „|ÿ. V prvním případě říkáme, že se dané elementy musí vyskytovat v pořadí, v jakém jsou zapsány. V druhém, že se v daném elementu může vyskytovat pouze jeden z těchto elementů. Příklady: Prvnímu příkladu pak odpovídá pouze následující příklad (z pohledu elementu html, o obsah ostatních nyní nejde): obsah obsah Druhému příkladu pak odpovídá jeden z následujících: <pohlavi> <muz/> <pohlavi>
8
KAPITOLA 3. XML SCHÉMATA
Dále v seznamu můžeme udat i počet opakování elementů pomocí speciálních znaků za daným elementem. Pokud za elementem žádný znak neuvedeme, znamená to, že se může vyskytovat právě jednou. Pokud uvedeme „?ÿ, jedná se o element nepovinný, tedy může se vyskytovat maximálně jedenkrát nebo se nemusí vyskytovat vůbec. Pokud chceme specifikovat, že se daný element musí vyskytovat alespoň jednou, ale může se opakovat přidáme za něj znak „+ÿ. A nakonec pro nepovinný element, který se může opakovat použijeme znak „*ÿ. Příklady: Prvnímu příkladu pak odpovídá kterýkoliv z následujících: <jmeno>Jan Novak <jmeno>Jan Novak <email>[email protected] <jmeno>Jan Novak <email>[email protected] <email>[email protected] <email>[email protected]
V DTD bohužel není možné specifikovat konkrétní počet položek, musíme tedy vypsat daný počet elementů ručně. V případě, že chceme specifikovat rozsah, uvedeme minimální počet bez speciálního znaku a zbytek do maximálního znaku se znakem „+ÿ, tedy pro 2-3 elementy kapitola uvedeme (kapitola, kapitola, kapitola?). Naštěstí tato situace v praxi nenastává moc často. Pokud chceme specifikovat, že daný element obsahuje text, ve kterém zároveň mohou být některé další atributy (tzv. smíšený obsah), můžeme to provést takto: Tomu vyhovuje např: <par> Toto je <strong>odstavec se smíšeným obsahem Atributy v DTD specifikujeme pro daný element ve značce ATTLIST, kde je uvedeno jméno elementu, jméno atributu, typ atributu, a standardní hodnota nebo také zda je atribut povinný apod.:
KAPITOLA 3. XML SCHÉMATA
9
Pomocí jedné značky ATTLIST můžeme pro jeden element definovat i několik atributů. Typy atributů mohou být CDATA, NMTOKEN, NMTOKENS, ID, IDREF, IDREFS, ENTITY, ENTITIES, výčet. Typ CDATA umožňuje udat libovolný textový řetězec. NMTOKEN umožňuje zadat slovo skládající se z písmen, číslic a několika dalších znaků. NMTOKENS znamená několik slov oddělených mezerou. Typ ID udává identifikátor, na který se poté můžeme odkazovat pomocí IDREF a v případě, že chceme ukazovat na více identifikátorů, uvedeme IDREFS. Ty poté budou odděleny opět mezerou. Typy ENTITY, ENTITIES se dnes již prakticky nepoužívají, souvisí s vlastnostmi, které byly do XML převzaty ze SGML, ale v praxi se neujaly. Výčtem specifikujeme množinu možných hodnot, uvádí se do kulatých závorek, kde jsou jednotlivé hodnoty odděleny znakem „|ÿ. Dále ve značce ATTLIST můžeme definovat standardní hodnotu, kterou uvozujeme dvojitými uvozovkami. Pokud před standardní hodnotu napíšeme slovo #FIXED, znamená to, že atribut může mít pouze tuto hodnotu. Mohou se zde vyskytovat i slůvka #REQUIRED a #IMPLIED. První znamená, že je atribut povinný, druhý naopak nepovinný. Příklad: Tomu vyhovuje např:
3.2.2
Připojení DTD k dokumentu
DTD schéma se připojuje k dokumentu pomocí značky DOCTYPE. DTD můžeme připojit buď přímo do dokumentu nebo ho uložit do samostatného souboru a v dokumentu se na něj pouze odkázat. První případ může vypadat např. takto: ]> Škoda FavoritGLX
10
KAPITOLA 3. XML SCHÉMATA
Druhá metoda je praktičtější, protože není třeba do každého dokumentu kopírovat celé schéma. Zápis může vypadat takto: Škoda FavoritGLX Tyto možnosti můžeme i kombinovat: ]> Škoda FavoritGLX
3.3
W3C XML schéma
W3C XML schéma (dále už jen WXS) je mnohem mocnější schémový jazyk, který je doporučením dnes velmi důležité organizace W3C Consortium. Musím zde upozornit na možnou záměnu terminologie – někdy je W3C XML schéma uváděno pouze pod jménem „XML schémaÿ. V tomto dokumentu pod pojmem „XML schémaÿ mám na mysli XML schéma jakéhokoliv typu (např. DTD, RelaxNG nebo W3C XML schéma). WXS podporuje jmenné prostory a datové typy. WXS je už také XML aplikací, tzn. zapsané schéma je také XML dokument. Nevýhodou je poměrně složitá a dlouhá specifikace. Základem WXS jsou datové typy. Ty mohou být jednoduché nebo komplexní. Jednoduchý typ se skládá pouze z jedné hodnoty, jako např. číslo, řetězec nebo datum. Komplexní datový typ je typ, který se skládá z dalších atributů a elementů. Pro názornost hned uvedeme příklad, který zachycuje schéma pro zápis informací o automobilu, u kterého nás zajímá jeho značka, typ, rok výroby a hmotnost. Automobil dále bude mít atribut id. V příkladu se vyskytují jmenné prostory (prefixy u jmen elementů oddělené dvojtečkou). Jmenným prostorům se budeme věnovat dále. <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="vuz"> <xs:complexType> <xs:sequence> <xs:element name="znacka" type="xs:string"/> <xs:element name="typ" type="xs:string"/> <xs:element name="vyrobeno" type="xs:gYear"/> <xs:element name="hmotnost" type="xs:decimal"/> <xs:attribute name="id" type="xs:integer"/>
KAPITOLA 3. XML SCHÉMATA
11
Zde vidíme, že obsah elementu vuz je komplexní typ, jelikož se skládá z několika jiných elementů a jednoho atributu. Vnitřní elementy a atribut jsou naopak jednoduché typy.
3.3.1
Jednoduché datové typy
XML schéma běžně zachycuje vlastnosti objektů které se vyjadřují číselně, řetězcem apod. Proto má WXS definováno mnoho jednoduchých typů jako jsou celá a desetiná čísla, řetězce, logické hodnoty, datum, čas a mnohé další. Jejich hierarchii zobrazuje obr. 3.1. Velká síla WXS spočívá v možnosti si z těchto základních typů odvodit svoje vlastní datové typy. Nejčastěji se nový typ odvozuje pomocí restrikce, kde zúžíme obor hodnot bázového typu pomocí integritních omezení. Dále můžeme nové typy odvodit vytvořením seznamu nebo sjednocením existujících typů. Restrikcí číselných typů můžeme omezovat přípustné hodnoty zdola pomocí elementů minInclusive a minExclusive, shora pak pomocí maxInclusive a maxExclusive. První možnost znamená, že specifikovaná hranice do intervalu patří, druhá naopak že nepatří. <xs:simpleType name="tydenvroce"> <xs:restriction base="xs:decimal"> <xs:minInclusive value="1"/> <xs:maxExclusive value="52"/> <xs:fractionDigits value="0"/> Takto definovaný typ pak jednoduše použijeme takto: <xs:element name="tydenvroce" type="tydenvroce"/> Dále můžeme restrikci uplatnit nad řetězci. Zde to bývá typicky omezení délky atributy minLength a maxLength, např.: <xs:simpleType name="znackaType"> <xs:restriction base="xs:string"> <xs:minLength value="1"/> <xs:maxLength value="20"/> Můžeme taktéž vyjmenovat množinu přípustných hodnot pomocí výčtového typu: <xs:simpleType name="znackaType"> <xs:restriction base="xs:string"> <xs:enumeration value="Škoda"/> <xs:enumeration value="Ford"/> <xs:enumeration value="Lamborghini"/>
12
KAPITOLA 3. XML SCHÉMATA
Obrázek 3.1: Hierarchie datových typů WXS (převzato z [11])
KAPITOLA 3. XML SCHÉMATA
13
Silným nástrojem pro omezování řetězců jsou regulární výrazy, které umožňují zapsat vzor, jemuž musí daná hodnota odpovídat. Příkladem budiž poštovní směrovací číslo, které se skládá ze tří dekadických čísel, mezery a dvou dekadických čísel. <xs:simpleType name="PSCType"> <xs:restriction base="xs:string"> <xs:pattern value="\d{3} \d{2}"/> Element, který nemá žádný obsah, lze chápat jako element, který obsahuje prázdný řetězec. Ale podobně jako v relačních databázích je i v datech zapsaných v XML potřeba nedefinovaná hodnota NULL. To, že element může mít nedefinovanou hodnotu, vyjádříme ve WXS atributem nillable nastaveným na hodnotu true a poté danému (prázdnému) elementu v XML dokumentu nastavíme atribut xsi:nil také na hodnotu true. <xs:element name="datum" nillable="true" type="xs:date"/> Často také potřebujeme objekty jednoznačně definovat nějakou unikátní hodnotou - klíčem, jako v relačních databázích. Aby se prováděla kontrola jedinečnosti klíčového atributu, je potřeba přidat integritní omezení typu key nebo unique, přičemž druhé zmiňované se liší od prvního tím, že pokud se daný atribut nevyskytuje, validátor neohlásí chybu. Toto integritní omezení je třeba umístit do definice elementu, který v sobě obsahuje elementy, které chceme jednoznačně identifikovat. Pro definici klíčů se používá dotazovací jazyk XPath. Na následujícím příkladě vidíme zápis takového případu a také XML vyhovující tomuto zápisu. <xs:element name="vozy"> <xs:complexType> <xs:sequence> <xs:element ref="vuz" maxOccurs="unbounded"/> <xs:unique name="id_je_unikatni"> <xs:selector xpath="vuz"/> <xs:field xpath="@id" /> Další věc převzatá z relačních databází je referenční integrita. Také ve WXS můžeme definovat klíč a na něj ukazující cizí klíč. To se dělá pomocí integritního omezení keyref, kde definujeme pomocí atributu refer, na jaký klíč se daný cizí klíč odkazuje.
14
3.3.2
KAPITOLA 3. XML SCHÉMATA
Komplexní datové typy
Modelování struktury dokumentu se dělá pomocí komplexních datových typů. Jak jsme již uvedli, komplexní typ se může skládat z dalších elementů a atributů. U elementů zde můžeme určit, zda jsou povinné nebo volitelné, kolikrát se mohou opakovat a také pořadí elementů, ve kterém se mohou v dokumentu vyskytnout. Atributy se v definici komplexního typu musí vyskytovat až na konci, a lze specifikovat, zda jsou povinné či volitelné. Uvnitř elementu complexType můžeme specifikovat pořadí elementů pomocí elementu sequence. Uvedené elementy se potom musí vyskytovat v přesně daném pořadí, jak jsou uvedeny. Pokud chceme, aby pořadí elementů bylo libovolné, specifikujeme to pomocí elementu all. Poslední možností je element choice, který říká, že se může vyskytnout právě jeden z uvedených elementů. Tyto elementy můžeme do sebe téměř libovolně vnořovat (až na výjimky, které by způsobily nejednoznačnost): <xs:element name="clanek"> <xs:complexType> <xs:sequence> <xs:element name="nazev" type="xs:string"/> <xs:element name="autor" type="xs:string" minOccurs="0" maxOccurs="unbounded"/> <xs:choice minOccurs="1" maxOccurs="unbounded"> <xs:element name="odstavec" type="xs:string"/> <xs:element name="obrazek" type="xs:base64Binary"/> Tomu potom vyhovuje následující příklad: Reliktní záření v dnešním vesmíruJakub NováčekJaroslav Novotný Z reliktního záření je možné vyvodit, jak vypadal vesmír 384 tisíc let po velkém třesku. Na tomto příkladu vidíme vnoření elementu choice do elementu sequence. Pomocí vyjádření počtu opakování atributy minOccurs a maxOccurs vyjadřujeme počet opakování. Hodnota unbounded označuje že se daný element může opakovat v libovolném počtu. Elementem all říkáme, že se v něm obsažené elementy mohou vyskytovat v libovolném pořadí. Aby model nebyl příliš složitý je zde povolen počet opakování elementů pouze v rozmezí 0 až 1. Element all může být použit pouze přímo uvnitř komplexního typu. Tato omezení se pak musejí obcházet např. skupinou elementů sequence, které vyjadřují všechny možné kombinace elementů. Podobně jako v DTD umožňuje WXS definovat smíšený obsah, tj. když je text na stejné úrovni kombinován s dalšími elementy. Ve WXS toho docílíme přidáním atributu mixed s hodnotou true do elementu complexType. Ale smíšený obsah ve WXS funguje trochu jinak. V DTD
KAPITOLA 3. XML SCHÉMATA
15
jsme definovali, že text a elementy na stejné úrovní se libovolně kombinovat. Ve WXS pomocí atributu mixed s hodnotou true specifikujeme, že se text může objevit kdekoliv mezi obsaženými elementy. Takže smíšený obsah ve smyslu, jak jej známe z DTD, se musí definovat pomocí elementu choice, který má libovolný počet výskytů: <xs:element name="odstavec"> <xs:complexType mixed="true"> <xs:choice minOccurs="0" maxOccurs="unbounded"> <xs:element name="pojem" type="xs:string"/> <xs:element name="odkaz"> <xs:complexType> <xs:simpleContent> <xs:extension base="xs:string"> <xs:attribute name="url" type="xs:anyURI" use="required"/> Čemuž vyhovuje např. následující příklad: Vesmír se skládá ze 73% z <pojem>temné energie. O ní se můžete více dočíst na stránkách mudrce Prokopa Diviše. Zde je také vidět, jak se musí obcházet situace, kdy chceme definovat element, který už neobsahuje žádné další elementy, ale obsahuje atribut. Musíme tedy definovat komplexní typ, obsahující rozšíření jednoduchého typu s hodnotou typu řetězec o atribut url. Také je zde vidět vyjádření povinnosti atributu atributem use s hodnotou required. Hodnota optional naopak značí, že atribut je nepovinný. U atributů můžeme také určit standardní hodnotu pomocí atributu default.
3.3.3
Normalizace hodnot
Při validaci validační program nejprve udělá tzv. normalizaci hodnot. Tato operace nejprve nahradí všechny bílé znaky jako např. konce řádků a tabulátory mezerou. V dalším kroku ořízne mezery ze začátku a konce hodnot a vícenásobný výskyt mezer nahradí jednou mezerou. Normalizace se provádí na všechny datové typy s výjimkou string a normalizedString a od nich odvozený uživatelských typů. U typu string se neprovádí normalizace vůbec a u typu normalizedString se pouze znaky konce řádků a tabulátory převedou na znak mezera.
3.3.4
Jmenné prostory
Aby byly elementy a atributy jednoznačné v rámci více schémat, zařazují se schémata do jmenných prostorů. Tak zamezíme možným konfliktům a umožníme používání více schémat
16
KAPITOLA 3. XML SCHÉMATA
v jednom dokumentu. Příkladem může být např. XHTML stránka se SVG obrázkem, nebo dokumentace v DocBook s matematickými vzorci podle MathML. Jmenné prostory jsou identifikovány URL adresou, na které se ovšem nic konkrétního nenachází, ta souží pouze jako identifikátor daného jmenného prostoru. Elementu lze přiřadit jmenný prostor pomocí atributu xmlns. Pro zkrácení zápisu je možné definovat prefix daného jmenného prostoru, zápis elementu se poté zapíše jednoduše prefix:element.
3.3.5
Připojení WXS k dokumentu
Pokud chceme říci parseru, kde se nachází schéma našeho dokumentu, použijeme značky z jmenného prostoru http://www.w3.org/2001/XMLSchema-instance. Jestliže používáme jmenné prostory, použijeme atribut schemaLocation, jehož hodnota obsahuje dvojice hodnot URI a umístění schématu, kde dvojice jsou odděleny bílými znaky, jako např. mezera: Pokud jmenné prostory nepoužíváme, stačí nám atribut noNamespaceSchemaLocation, jehož hodnotou je URL adresa, kde se nachází schéma. Ta může být i relativní, např. zde vidíme, že se soubor se schématem nachází přímo v adresáři s dokumentem:
3.3.6
Modularizace schémat
Často naše schéma nabobtná do takových rozměrů, že je obtížné a nepřehledné s ním pracovat v jednom souboru. Proto můžeme schéma rozdělit do několika souborů, a ty pomocí elementu include vložit do našeho souboru: <xs:include schemaLocation="cast-schematu.xsd"/>
3.4 3.4.1
Relax NG schéma Úvod
Relax NG je nejnovější ze zde popisovaných schémat. Bylo vyvinuto konsorciem OASIS a standardizováno organizací ISO. Jedná se o velmi mocný, ale zároveň elegantní jazyk pro zápis XML schémat. Ačkoliv jeho specifikace je daleko jednodušší a do počtu stránek kratší než u WXS, Relax NG se jeví býti hlavním formátem pro XML schémata. Tomu nasvědčuje i fakt,
KAPITOLA 3. XML SCHÉMATA
17
že Kohsuke Kawaguchi ze společnosti Sun pracuje na programu Sun Multi-Schema Validator (MSV), který má být validátorem pro DTD schémata, RELAX NG schémata a W3C XML Schemata. Přitom všechna schémata jsou při kontrole převedena do vnitřní formy, která je jednoduše Relax NG. To demonstruje, že vyjadřovací síla Relax NG [10] je tak silná a flexibilní, že 99% omezeních, které lze vyjádřit v ostatních jazycích, lze zapsat v Relax NG. Na rozdíl od WXS, které je založeno na datových typech, je Relax NG založeno na vzorech. Schéma napsané v Relax NG je vzor dokumentu, který se skládá z vzorů pro elementy, atributy a textové uzly. U těchto vzorů pak můžeme určovat, zda jsou povinné, počet opakování, dále je lze kombinovat do uspořádaných i neuspořádaných skupin. Tímto jednoduchým způsobem můžeme specifikovat i složité struktury v dokumentu. Stejně jako WXS, i Relax NG je zapisováno v XML jazyce. Ale oproti WXS Relax NG nabízí i jinou formu zápisu. Jedná se o tzv. kompaktní syntaxi, která je člověkem mnohem lépe čitelná než XML zápis a samozřejmě se také lépe vytváří. Přitom jsou oba způsoby zápisu mezi sebou plně převeditelné. XML zápis se obvykle umísťuje do souboru s koncovkou rng, kompaktní syntaxe pak do souboru s koncovkou rnc. Pro porovnání si uvedeme příklady obou zápisů (stejně tak i u většiny následujících příkladů v této podkapitole). Schéma, které budou popisovat, je schéma dokumentu popisující vozy, u kterých nás zajímá značka, typ, rok výroby a hmotnost. Každý vůz bude mít svůj identifikátor id jako atribut. Nejprve příklad XML zápisu: <element xmlns="http://relaxng.org/ns/structure/1.0" name="vuz"> <element name="znacka"> <element name="typ"> <element name="vyrobeno"> <element name="hmotnost"> A nyní totéž schéma zapsané v kompaktní syntaxi: element vuz { attribute id { text }, element znacka { text }, element typ { text }, element vyrobeno { text }, element hmotnost { text } } Tomu potom vyhovuje následující XML:
18
KAPITOLA 3. XML SCHÉMATA
ŠkodaFabia Combi20061150kg Na předchozích příkladech vidíme 3 elementy základních typů vzorů, ze kterých se Relax NG schéma skládá, pro elementy je to element element, pro atributy je to element attribute a pro textové uzly je to element text. Na rozdíl od WXS, v Relax NG lze tyto elementy libovolně kombinovat (ve WXS mohly být atributy pouze na konci), což umožňuje při kombinaci s dalšími elementy mnohem větší vyjadřovací schopnost.
3.4.2
Opakování vzorů
Pokud chceme vyjádřit počet opakování některého vzoru, vložíme ho do elementů pro opakování. Například pro vyjádření toho, že vzor je nepovinný (počet opakování 0 až 1), vzor vložíme do elementu optional, např. pro vyjádření toho, že element hmotnost je nepovinný bude schéma vypadat takto: <element name="vuz"> <element name="znacka"> <element name="typ"> <element name="hmotnost"> V kompaktní syntaxi se počet opakování vyjadřuje speciálním znakem za vzorem, jehož počet opakování chceme ovlivnit. V případě že opět chceme vyjádřit že hmotnost je nepovinná, je speciálním znakem znak „?ÿ: element vuz { element znacka { text }, element typ { text }, element hmotnost { text }? } Stejným způsobem se vyjadřují i ostatní počty opakování. Pokud chceme vyjádřit, že se atribut vyskytuje alespoň jednou, ale může se libovolně opakovat, vložíme vzor do elementu oneOrMore, resp. v kompaktní syntaxi umístíme za vzor znak „+ÿ. Pokud se vzor opakuje libovolně, ale je nepovinný, umístíme ho do elementu zeroOrMore, resp. v kompaktní syntaxi za něj vložíme znak „*ÿ. Pro přehlednost uvádím tabulku s elementy a znaky (tab 3.1).
19
KAPITOLA 3. XML SCHÉMATA Počet opakování 1 0 až 1 1 a více 0 nebo více
RNG
RNC
optional oneOrMore zeroOrMore
? + *
Tabulka 3.1: Počty opakování vzorů V Relax NG není možnost přímo specifikovat přesný počet opakování jako ve WXS pomocí atributů minOccurs a maxOccurs. Naštěstí v praxi situace, kdy toto potřebujeme, nastává velmi zřídka. I přesto to lze obejít tak, že uvedeme vzor tolikrát, kolik je minimum výskytů a poté zbytek do maxima výskytů uvedeme v elementech optional resp. v kompaktní syntaxi se znakem „?ÿ. Např. pro vyjádření, že daný element má počet opakování 3 až 5 uvedeme element 3x a poté ještě dvakrát uvozený v elementu optional. Pro větší počty a složitější schémata je tento způsob ale nepřehledný. V takovém případě může být ulehčením využití pojmenovaných vzorů (viz. dále). Pro vyjádření toho, že má být obsah elementu prázdný, slouží vzor empty. Typicky se používá v XHTML pro horizontální oddělovače hr, nebo odřádkování br.
3.4.3
Seskupování, výběr a prolínání
Základní vzory lze seskupovat do skupin. S těmito skupinami můžeme pak zacházet stejně, jako s jednoduchými vzory, tj. například vyjádřit počet opakování, ale i další možnosti o kterých bude tato kapitola. Seskupení vzorů do skupiny provedeme tak, že vzory, které chceme seskupit, vložíme do elementu group, resp. v kompaktní syntaxi je uvedeme v kulatých závorkách a oddělíme čárkou. Pokud chceme ve schématu vyjádřit, že se z určité skupiny vzorů má v dokumentu vyskytovat právě jeden, vložíme tyto vzory do elementu choice, resp. v kompaktní syntaxi tyto varianty oddělujeme znakem „|ÿ. Posledním vzorem, který je v Relax NG v kombinaci s ostatními vzory velmi mocný, můžeme vyjádřit to, že se dané vzory mohou vyskytovat v libovolném pořadí. Vyjádříme to tak, že dané vzory uvedeme uvnitř elementu interleave, resp. v kompaktní syntaxi je oddělíme znakem „&ÿ. Velká vyjadřovací síla Relax NG spočívá v kombinaci těchto vzorů. Vzory je možné téměř libovolně kombinovat. Podmínkou je, aby bylo výsledné schéma jednoznačné (touto problematikou se zabývá např. [10]). Na několika příkladech si ukážeme, jak je možné tyto vzory kombinovat. V první části následujícího příkladu umožňujeme pro osobu zadat buď element jmeno nebo oba elementy krestni a prijmeni. To uděláme kombinací vzoru pro skupiny s vzorem pro výběr. V druhé části potom vyjádříme to, že email může být buď atribut, nebo element. Zde je vidět jaké možnosti získává Relax NG díky tomu, že se vzor pro atributy může vyskytovat kdekoliv mezi ostatními vzory. <element name="osoba"> <element name="jmeno">
20
KAPITOLA 3. XML SCHÉMATA
<element name="krestni"> <element name="prijmeni"> <element name="email"> element osoba { (element jmeno { text } | (element krestni { text }, element prijmeni { text })), (element email { text } | attribute email { text }) } Tomu potom vyhovují např. následující příklady: Jan <prijmeni>Tollan <jmeno>Jan Tollan <email>[email protected] Pomocí vzoru interleave můžeme např. jednoduše zapsat smíšený obsah, který se často používá v textově orientovaných XML aplikacích jako je XHTML nebo Docbook. Typickým příkladem je odstavec (para) s elementy pro zvýraznění (strong) a odkaz (link) ve kterém se mezi těmito elementy může libovolně vykytovat text: <element name="para"> <element name="strong"> <element name="link">
KAPITOLA 3. XML SCHÉMATA
21
element odstavec { element pojem { text }* & element odkaz { attribute url { text }, text }* & text } Vzor text odpovídá jak prázdnému řetězci, tak libovolnému počtu opakování, proto u něj není třeba zdůrazňovat počet opakování. Jelikož se smíšený obsah v textově orientovaných XML aplikacích používá často, zavádí Relax NG element mixed, který přímo vyjadřuje, že mezi vzory, které obsahuje, může být i text, tudíž už není třeba uvádět vzor text: <element name="para"> <mixed> <element name="strong"> <element name="link"> element odstavec { mixed { element pojem { text }* & element odkaz { attribute url { text }, text }* } } Těmto předpisům vyhovuje např.: <para> Hmota jak ji známe tvoří pouze <strong>4% vesmíru.
22
3.4.4
KAPITOLA 3. XML SCHÉMATA
Datové typy
Samotné Relax NG mnoho datových typů nenabízí, ale má zabudovaný mechanismus, který dovoluje používat datové typy z libovolných externích knihoven. Nejčastěji se používají datové typy z W3C XML schémat. Tudíž můžeme i v Relax NG kontrolovat, zda hodnota elementu či atributu vyhovuje datovému typu. Datový typ určíme pomocí vzoru data. Jeho atribut type určuje datový typ. Knihovnu datových typů určíme pomocí dalšího atributu vzoru data datatypeLibrary. Na příkladu vidíme knihovnu datových typů WXS určenou jejím URL: <element name="hmotnost"> Specifikovat knihovnu datových typů pro každý element a atribut, u kterého chceme určit datový typ, by bylo pracné. Proto stačí specifikovat knihovnu jednou, pouze v kořenovém elementu a všechny vzory uvnitř tohoto elementu dědí definici aktuální knihovny datových typů. V kompaktní syntaxi se pak datové typy zapisují pomocí prefixu, který si vytvoříme pro danou datovou knihovnu, dvojtečky a samotného jména datového typu: datatypes xs = "http://www.w3.org/2001/XMLSchema-datatypes" element hmotnost { xs:decimal } Jelikož se typy z WXS používají zdaleka nejčastěji, je pro ně předdefinována předpona xsd: element hmotnost { xsd:decimal }
3.4.5
Parametry datových typů
Pro datové typy lze určit další upřesňující parametry. Pro datové typy z WXS tak můžeme určit většinu integritních omezení, která známe z předchozí kapitoly o WXS. Pro nastavení parametru daného datového typu se používá atribut name, který specifikuje jméno parametru a jehož obsahem je hodnota tohoto parametru. <element name="adresa" xmlns="http://relaxng.org/ns/structure/1.0" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <element name="mesto"> <param name="minLength">2 <param name="maxLength">25 <element name="cp"> <param name="minInclusive">1 <param name="maxExclusive">100000
KAPITOLA 3. XML SCHÉMATA
23
<element name="psc"> <param name="pattern">\d{3} \d{2} element adresa { element mesto { xsd:string { minLength = "2" maxLength = "25" } }, element cp { xsd:decimal { minInclusive = "1" maxExclusive = "100000" } }, element psc { xsd:string { pattern = "\d{3} \d{2}" } } } Tomuto předpisu vyhovuje např.: <mesto>Aš 211250 11
3.4.6
Výčtové typy
Relax NG nabízí možnost specifikovat možné hodnoty atributu nebo elementu. Proto je zakázáno používání parametru datového typu enumeration. Pro vytvoření seznamu přípustných hodnot se používá vzorů value uvedené ve vzoru choice: ŠkodaFordLamborghini attribute znacka { "Škoda" | "Ford" | "Lamborghini" }, Pokud nám stačí pouze jedna přípustná hodnota, můžeme vzor choice vynechat. U atributu elementu můžeme také specifikovat datový typ pomocí atributu type. Má to smysl např. pokud chceme zakázat normalizaci bílých znaků. To provedeme specifikováním datového typu string. V kompaktní syntaxi se tento datový typ zapisuje jednoduše před danou hodnotu.
24
3.4.7
KAPITOLA 3. XML SCHÉMATA
Nepovolené hodnoty
Někdy je vhodnější specifikovat hodnoty, kterých element či atribut nabývat nesmí. Vyjádření tohoto požadavku se zapisuje pomocí vzoru except. <element name="jehlicnany"> <except> dubbukbříza
Pro některé aplikace XML se hodí pro zkrácení zápisu zapsat několik hodnot do jedné hodnoty elementu nebo atributu. Z hlediska filozofie XML to není sice nejlepší, ale pro různé aplikace to může výrazně zkrátit a zpřehlednit zápis dat. Např. zapsat 3D souřadnice bodu každou do zvláštního elementu či atributu by bylo možno zkrátit následovně: 0.0 0.0 0.01.0 0.0 0.00.0 1.0 0.0 Ve schématu toho docílíme pomocí seznamu, který se uvádí elementem list. Jeho obsahem jsou datové typy nebo hodnoty, které se v daném atributu nebo elementu mohou nacházet oddělené mezerou. <element name="bod"> <list> element bod { list { xsd:decimal, xsd:decimal, xsd:decimal } }
KAPITOLA 3. XML SCHÉMATA
3.4.9
25
Modularizace schémat
Často se stává, že se jisté vzory vyskytují na více místech, typickým příkladem je adresa, která bude jak u zaměstnanců podniku, tak u dodavatele a odběratele na faktuře apod. Proto Relax NG umožňuje pro tyto vzory definovat jméno, na které se potom jednoduše odkážeme. Definice jména nebo více jmen musí být v tagu grammar, aby byla splněna podmínka XML, že každý dokument musí mít právě jeden kořenový element. Jméno potom specifikujeme elementem define. Pokud používáme tyto definice, tak musíme ještě pomocí tagu start definovat, kde validace začíná. <start> <element name="faktura"> <element name="adresaDodavatele"> <element name="adresaOdberatele"> <define name="adresa"> <element name="mesto"> <element name="ulice"> <element name="psc">
start = element faktura { element adresaDodavatele { adresa }, element adresaOdberatele { adresa } } adresa = element ulice { text }, element město { text }, element psč { text }
3.4.10
Jmenné prostory
Stejně jako WXS i Relax NG umožňuje deklarovat elementy a atributy patřící do jmenného prostoru. Náležitost k jmennému prostoru pro vzor atributu či elementu se vyjádří atributem
26
KAPITOLA 3. XML SCHÉMATA
ns, jehož hodnotou je jméno jmenného prostoru. V praxi by samozřejmě bylo pracné psát u každého elementu atribut ns se jménem jmenného prostoru, a proto elementy dědí jmenný prostor od svých předků. Toto však platí jen pro elementy, nikoliv pro atributy, u těch jmenný prostor uvádět musíme. <element xmlns="http://relaxng.org/ns/structure/1.0" name="a" ns="urn:schemas:pokus"> <element name="b"> <element name="c"> Pokud definujeme schéma, které používá více jmenných prostorů, můžeme si nadefinovat prefixy pro dané jmenné prostory, které potom budeme používat před danými elementy a atributy. Mezi prefixem a jménem elementu bude dvojtečka. V kompaktní syntaxi se prefix definuje slůvkem namespace: <element xmlns="http://relaxng.org/ns/structure/1.0" name="vu:vuz" xmlns:vu="urn:schemas:vuz" xmlns:car="urn:schemas:car"> <element name="car:weight">
namespace vu = "urn:schemas:vuz" namespace car = "urn:schemas:car" element vu:vuz { element car:weight { text } } Často definujeme schéma, kde je většina atributů a elementů z jednoho jmenného prostoru a jen několik málo jich je z jiných jmenných prostorů. Proto se hodí definovat implicitní jmenný prostor, do kterého potom patří všechny elementy, které jsou uvedeny bez prefixu. Toto opět platí pouze pro elementy, protože i v dokumentu psaném podle schématu se implicitní jmenný prostor na atributy nevztahuje. Implicitní jmenný prostor se v kompaktní syntaxi definuje slůvky default namespace, v XML syntaxi mu pak odpovídá zápis na příkladu výše, kde se pomocí atributu ns definuje jmenný prostor, který se poté dědí všechny elementy uvnitř kořenového elementu. default namespace vu = "urn:schemas:vuz" namespace car = "urn:schemas:car" element vuz { element car:weight { text } }
KAPITOLA 3. XML SCHÉMATA
3.5
27
Shrnutí vlastností XML schémat
Nejstaršími a nejrozšířenějšími XML schématy jsou DTD schémata. Dnes už mají mnohdy nedostačující vyjadřovací schopnosti. Nepodporují datové typy ani jmenné prostory. Ačkoliv jsou schématem pro XML, tak nejsou zapisovány v XML notaci. Velkou předností je jednoduchost a podpora v software. Základem W3C XML jsou datové typy. W3C XML schémata mohou vyjádřit mnohem složitější omezení než DTD. Jsou zapisovány XML notací a podporují jmenné prostory. Velkou nevýhodou je složitost a délka specifikace. Relax NG schémata jsou nejmladší z uvedených. Jejich vyjadřovací síla je asi největší a zároveň jejich specifikace je mnohem kratší než u W3C XML schémat. Podporují dva způsoby zápisu, jeden je XML notací, druhý tzv. kompaktní notací. Druhý uvedený je vhodný pro editaci člověkem, protože je daleko lépe čitelný a také kratší. Oba zápisy jsou mezi sebou plně převeditelné. Relax NG schémata sice přímo moc datových typů nepodporují, ale mají mechanismus pro využití externích knihoven, včetně datové knihovny W3C XML schématu. Také jmenné prostory jsou podporovány. Nevýhoda je poměrně malá podpora v software, jelikož jsou např. oproti DTD relativní novinkou.
28
KAPITOLA 4. ANALÝZA
4 Analýza 4.1
Podobné existující projekty
V této kapitole provedu průzkum podobných projektů, aby bylo zřejmé, že tento projekt přinese něco nového a užitečného. Tímto průzkumem také jistě získám řadu poučení a dobrých nápadů. Průzkum se bude týkat především open source a také freeware projektů, které spadají do stejné nebo podobné kategorie [2], jako tento projekt.
4.1.1
Emacs + nXML mód
• Platformy: Linux, Windows a mnoho dalších • Zvýraznění syntaxe: Ano • XML schéma: Ano (RelaxNG, W3C Schema, DTD) • Domovská stránka: http://www.gnu.org/software/emacs/ • Licence: GPL Samotný editor Emacs asi není nutno představovat. Ve zkratce se jedná o velmi mocný editor, který má vlastní vnitřní skriptovací jazyk založený na jazyku Lisp, jménem Emacs Lisp. Má také velmi dobře propracovaný systém zkratek, který je standardně navolen tak, že uživatel nemusí přesouvat ruce k navigační části klávesnice (šipky, atd.). Velká výhoda tohoto přístupu je v tom, že uživatel neztratí základní polohu prstokladu na klávesnici, a tudíž je psaní a editace jakéhokoliv textu rychlejší. Navíc funkce této navigace nejenže nahrazují tuto část klávesnice, ale jsou i mnohem efektivnější. Např. umožňují navigaci a editaci po slovech, větách apod. Samozřejmostí je možnost si tyto zkratky předefinovat, dále je možné na klávesové zkratky namapovat libovolné funkce editoru. Pro usnadnění editace XML kódu můžeme použít nXML mód. Samozřejmostí je zvýraznění syntaxe a automatické odsazení tagů dle jejich hierarchie. Hlavní vlastnost tohoto módu je možnost načtení XML schéma a s tím související velmi užitečné možnosti. Editor s načteným XML schématem umožňuje klávesovou zkratkou vyvolat nápovědu, která např. vkládání tagu (či atributů) uživateli říká, který tag je dle schématu a kontextu současné pozice kurzoru možné vložit. Pokud jsou uvedena počáteční písmena, editor zobrazuje už jen tagy začínající těmito písmeny. Nicméně i zde by se dalo hodně zlepšit. Například by editor sám mohl vkládat koncové tagy při vkládání počátečních nebo automaticky doplňovat jména tagů či elementů, když je dle schématu jednoznačně dané, který tag na dané pozici musí povinně být. Bohužel seznam možných elementů a atributů k dokončení se zobrazuje velmi nevhodným způsobem. Okno editoru se rozpůlí na dvě části a nápověda tak zabere celou spodní půlku editoru. To je pravděpodobně způsobeno zastaralou GUI knihovnou editoru Emacs, která toho kromě velmi mocné komponenty pro editování textu moc nenabízí. Na druhou stranu tento editor jako jediný z uvedených lze provozovat i v textovém terminálu. Další vlastnost, kterou tento editor disponuje, je validace dokumentu dle načteného schématu, která probíhá za běhu. Jako snad jediná z uvedených editorů podporuje kromě kontroly jmen tagů, atributů a jejich hierarchie i kontrolu obsahu elementu a hodnot atributů podle uvedeného datového typu ve schématu. Pokud uvedeme hodnotu, která neodpovídá příslušnému typu, editor ji podtrhne.
KAPITOLA 4. ANALÝZA
29
Obrázek 4.1: Screenshot programu Emacs
Zhodnocení Jedná se o velmi mocný editor s nejlepší podporou XML schémat ze všech zde uvedených editorů. Bohužel má už dnes poněkud zastaralé grafické uživatelské rozhraní, které např. pro nápovědu dokončení XML tagu otevře nové okno přes půlku editoru.
4.1.2
Kate
• Platformy: Linux (KDE) • Zvýraznění syntaxe: Ano • Domovská stránka: http://kate.kde.org/ • XML schéma: ANO (pouze DTD) • Licence: GPL Jedná se o obecný editor pro KDE. Podporuje zvýraznění syntaxe nejen pro XML, ale i pro mnoho programovacích jazyků a jiných formátů souborů. Kromě toho pro něj existují pluginy XML Completion a XML Validation. Díky XML Completion můžeme načíst DTD schéma a podle něj program při vkládání tagu (po vložení znaku „<ÿ) dá uživateli vybrat z tagů, které jsou dle schématu přípustné.
30
KAPITOLA 4. ANALÝZA
Stejně tak je tomu u atributů. Nabízené možnosti se objeví v malém okně hned pod kurzorem, a když uživatel píše, tak se automaticky okruh možného výběru zmenšuje na ty, které stejně začínají. Bohužel editor trpí několika zbytečnými nedostatky, např. po vložení tagu pomocí vybrání tagu z výběru možných se sice doplní i koncový tag, ale kurzor skočí až za tento koncový tag, tudíž se uživatel musí vracet zpět, pokud chce vložit něco do tagu nebo mu přidat atribut (drtivá většina případů). Další nepříjemnost je, že pokud uživatel psaní jména tagu nedokončí a přesuneme kurzor jinam a pak se na místo vrátí, není možné již dokončování vyvolat. Plugin XML Validation na povel z menu zhodnotí, zda je XML soubor dle schématu validní a podá detailní hlášení o chybách včetně místa, kde jsou. Mnohem lepší by však bylo, kdyby program prováděl validaci automaticky a např. podtrhával chyby, aby uživatel včas zjistil, že píše nevalidní dokument. Jelikož program umí pracovat pouze s DTD schématy, neumí kontrolovat typ obsahu tagů a atributů.
Obrázek 4.2: Screenshot programu Kate
Zhodnocení Tento editor má pěkně zpracované GUI pro výběr možných tagů a atributů dle DTD schématu. Bohužel trpí několika nedostatky, které rychlou editaci XML kódu znesnadňují. Také možnost kontroly validity je omezena pouze na DTD schéma a validace se musí explicitně vyvolat a nepodtrhává chyby v textu (pouze dá hlášení o chybách).
KAPITOLA 4. ANALÝZA
4.1.3
31
Jaxe
• Platformy: Java • Zvýraznění syntaxe: Ano • Domovská stránka: http://jaxe.sourceforge.net/ • XML schéma: Ne • Licence: GPL Tento editor je napsaný v jazyce Java, tím pádem přenositelný na mnoho platforem. Jedná se o editor, který má blíže k vizuálním editorům. Umožňuje editovat několik typů XML souborů (xhtml, W3C XML schéma, XSLT, a částečně DocBook). Pro tyto XML soubory jsou v programu nadefinovány speciální konfigurační soubory, které definují vzhled jednotlivých elementů, ale i např. možnost přidávání pouze správných tagů a atributů dle kontextu. Pomocí těchto souborů je tedy možné i např. aby byly matematické vzorce (které se zapíší obyčejným textovým editorem jako text) zobrazovány vizuálně, tak jak skutečně vypadají, přímo v editovaném dokumentu. V pravé části okna programu je vlastní dokument, v levé pak několik užitečných záložek. V první je hierarchické zobrazení XML pomocí stromu. V druhé potom nápověda, které elementy je možné vkládat v daném kontextu. Třetí pak možné atributy pro vybraný element. Velkou nevýhodou tohoto editoru je, že lze editovat pouze soubory, pro které existuje příslušný konfigurační soubor. Nicméně je tu i možnost si tyto soubory vytvořit. Bohužel klávesové zkratky pro různé akce jsou spíše výjimkou. Zhodnocení Tento program umožňuje editaci několika vybraných typů XML souborů, a to částečně vizuální formou. Je však i rozšířitelný, tudíž je možné dopsat speciální konfigurační soubory i pro jiné typy XML souborů.
4.1.4
Teddy XML Editor
• Platformy: Linux, Windows, Max OS X • Zvýraznění syntaxe: Ne • Domovská stránka: http://gravitybind.com/ • XML schéma: Ne • Licence: GPL Tento editor se od ostatních odlišuje. Autor měl zajímavý nápad editovat XML pomocí tabulky podobné sešitu z programů MS Excel či OpenOffice Cacl. Uživatel je tak odstíněn od zdrojového kódu XML. Hierarchické úrovně jsou zde znázorněny pomocí odsazení o jeden sloupec. Element, atributy, hodnoty atributů a text jsou buňky sešitu a jsou odlišovány různou barvou pozadí. Názvy atributů jsou o řádek výše než element a nad příslušnou hodnotou atributu (tvoří hlavičku tabulky atributů). To umožňuje pro skupinu stejných elementů uvést název atributu pouze jednou jako hlavičku sloupce pro několik řádků najednou (viz. screenshot na obr. 4.4).
32
KAPITOLA 4. ANALÝZA
Obrázek 4.3: Screenshot programu Jaxe
Program má na každou akci klávesovou zkratku, bohužel tyto zkratky nelze předefinovat dle přání uživatele. Program sám sice neumožňuje přímou editaci XML kódu, ale je možné vyvolat nabídkou z menu externí editor, který si uživatel může zvolit. V prostředí KDE je jako výchozí nastaven výše zmíněný editor Kate. Zhodnocení Editor se zajímavým způsobem editace XML přes rozhraní podobné tabulkovým procesorům. Nepodporuje však žádný způsob dokončování či validace na bázi XML schémat.
4.1.5
KXMLEditor
• Platformy: Linux (KDE) • Zvýraznění syntaxe: Ano • XML schéma: Ne • Domovská stránka: http://kxmleditor.sourceforge.net • Licence: GPL Jedná se o XML editor, v kterém probíhá editace pomocí editace uzlů hierarchického XML stromu, který je v levé části obrazovky. Pokud je aktivní element, tak se v pravé části
KAPITOLA 4. ANALÝZA
33
Obrázek 4.4: Screenshot programu Teddy XML Editor
nachází tabulka s atributy. Pokud je aktivní textový uzel, tak je zde přímo zobrazený text. Dále editor zobrazuje XML kód podstromu, jehož kořenem je vybraný uzel stromu. Uživatel tedy je při tvorbě odstíněn od zdrojového XML kódu, ale zároveň na něj může nahlédnout. Pro vkládání elementů, atributů atd. jsou zde definovány klávesové zkratky, které je možné i předefinovat. Je možná i přímá editace kódu, ovšem bez jakékoliv asistence, pouze k orientaci pomáhá zvýrazněná syntaxe. Užitečné je, že při ukončování editace se udělá alespoň základní kontrolu XML, takže je uživatel upozorněn na invalidní kód. Zhodnocení Editor nad XML stromem (strom pomocí GUI), který umožňuje i přímou editaci XML kódu, avšak bez jakékoliv pomoci uživateli. Nepodporuje žádné XML schéma.
4.1.6
xmloperator
• Platformy: Java • Zvýraznění syntaxe: Ne • XML schéma: ANO (DTD, RelaxNG) • Domovská stránka: http://www.xmloperator.net/
34
KAPITOLA 4. ANALÝZA
Obrázek 4.5: Screenshot programu KXMLEditor
• Licence: BSD-style Jedná se o XML editor napsaný v javě, využívající knihovnu Xerces. V editoru vytváříme a editujeme XML soubor vizuálně pomocí stromu. Do stromu vkládáme uzly jakožto elementy XML, struktura stromu pak znázorňuje vnořování elementů. Velkou výhodou tohoto editoru je, že podporuje XML schémata, a to DTD a RelaxNG. Pokud máme načtené schéma, tak nám při vkládání elementů a atributů dá editor na výběr jen z možností povolených v daném kontextu. Také pokud jsou některé elementy či atributy povinné, tak je hned sám doplní. Velkou výhodou je, že takto vytvořený dokument je vždy validní. Další výhodou je, že každá akce má svou klávesovou zkratku, což velmi urychluje vytváření a editaci XML souboru. Bohužel není možné klávesové zkratky předefinovat. Editor má ale i mnoho často zbytečných nedokonalostí. Např. není vidět, že je označen uzel stromu, který je prázdný text, takže uživatel ztrácí přehled, kde se v dokumentu nachází. Další zbytečnou nedokonalostí je, že po vložení elementu, který může dle schématu obsahovat jiné elementy, program při vkládání jeho obsahu nenabízí možnost vybrat si z těchto elementů, ale pouze vloží prázdný text. Teprve když tento text změníme na nějaký element, tak nám program při vkládání obsahu do prvně vloženého elementu nabídne možnost vybrat si elementy dle schématu. Podobná chyba je i opačným směrem, tj. když chceme vložit text do elementu, který obsahuje jiný element, tak nám není tato možnost při vkládání dána, proto musíme nejdříve vložit libovolný element a poté ho změnit na text. Editor sice podporuje přímou editaci XML kódu, ale po uložení pomocí save v dialogu editace se dokument nesesynchronizuje s načteným dokumentem, tudíž je v programu načtená
KAPITOLA 4. ANALÝZA
35
neaktuální kopie a při uložení o data z editace XML souboru přijdeme. Musíme tedy ještě předtím provést znovuotevření téhož dokumentu (reopen). Také v okně přímé editace není ani zvýrazněná syntaxe, ani se neprovádějí žádné kontroly, proto není problém napsat nevalidní kód. Další nevýhodou tohoto programu je, že výstupní XML soubor je pouze jedna dlouhá řádka, tudíž člověkem téměř nečitelný. Editor sice obsahuje volbu „indent elementsÿ (odsazení elementů), která dokument přehledně odřádkuje a odsadí podle úrovně vnoření, nicméně po aplikování této transformace se před a za každý element ve stromu editoru doplní prázdné textové uzly. Ten se poté načne do stromu, tudíž je zase téměř nemožné se vyznat při standardním editování ve stromu, protože se počet uzlu ztrojnásobí.
Obrázek 4.6: Screenshot programu xmloperator
Zhodnocení Jedná se o vizuální XML editor, který k editaci používá strom XML uzlů. Jeho předností je možnost používání XML schémat. Bohužel obsahuje mnoho malých chyb, který ho dělají obtížně použitelným.
4.1.7
Shrnutí
Žádný z editorů plně neodpovídá požadavkům na tento projekt specifikovaným v kapitole 2.3, jako např. zjednodušená XML syntaxe a jednoduchou možnost rozšíření. Jako jediný editor s dobrou podporou XML schémat se ukázal být Emacs, který má dnes již velmi zastaralé grafické uživatelské rozhraní. Použitelným se jeví i editor Kate, který však nepodporuje automatickou validaci dle schématu během editování a trpí jinými menšími chybami.
36
KAPITOLA 4. ANALÝZA
Myslím že projekt prezentovaný v této práci přinese do světa open source a freeware něco nového a že bude užitečným nástrojem pro efektivní editaci datových a především konfiguračních XML souborů.
4.2
Výběr technologií
V této podkapitole probereme jednotlivé možnosti nástrojů potřebných k implementaci projektu. Diskutovat se zde budou programovací jazyky, GUI a jiné podpůrné knihovny, vývojové nástroje apod.
4.2.1
Programovací jazyk
V dnešní době se již běžně používají jazyky, které se nekompilují přímo do strojového kódu procesoru, ale používají např. virtuální stroje či se jiným způsobem interpretují. Jejich výhoda je větší efektivita programátora, protože se např. starají o uvolňování paměti (pomocí tzv. garbage collectoru). Vzhledem k požadavkům na multiplatformnost byly nejlepšími kandidáty Java a Python. Oba jazyky jsou dostatečně rozšířené, mají velkou podporu ze strany knihoven třetích stran a jsou zdarma. Na základě průzkumu i vlastních zkušeností jsem pro implementaci vybral Python. Podobně jako programování v Javě je několikrát produktivnější, než např. v C++, tak i programování v Pythonu je několikanásobně produktivnější než v Javě [5] [1]. Stejně tak z důvodů podpory vytváření rozšíření editoru se více hodí Python, který se nemusí nikterak kompilovat a jeho syntaxe je jednodušší a kratší. Dalšími odstavci toto tvrzení podepřu několika příklady a vysvětleními. Jeden z největších rozdílů mezi Javou a Pythonem je v typové kontrole. Oba jazyky jsou sice silně typované, ale Java je staticky typovaný jazyk, tzn. že ke každé proměnné musí být explicitně zadaný i její typ, který je tím pádem znám již při překladu. Oproti tomu Python je dynamicky typovaný jazyk, proměnná (ani její typ) se zde nikdy nedeklaruje. V pythonu je objekt vše, včetně obyčejných celočíselných konstant. Proměnná se sváže s objektem pomocí operátoru přiřazení. Pokud je proměnné přiřazen objekt, může ji být později přiřazen i objekt jiného typu. Ale Python je stále silně typovaným jazykem, neboť v každém okamžiku víme, jakého typu je daná proměnná. Kontejnery v Pythonu, jako např. seznamy (lists) a asociativní pole (dictionaries) ukládají objekty libovolného typu, což samozřejmě znamená i čísla či jiné kontejnery. Pokud vyzvednete objekt z kontejneru, stále si pamatuje svůj typ, tudíž není nutné přetypování. V Pythonu také můžeme najít polymorfismus v pravém slova smyslu, tj. ne jen u objektů, které dědí z jednoho potomka (pomocí dědičnosti), ale i polymorfismus nad společným protokolem. To znamená, že stačí, aby dva objekty implementovali stejně se jmenující metodu a jsou nad touto metodou polymorfní, přitom od sebe nedědí a nemají společného předka (kromě Object). Další vlastností Javy je upovídanost, tzn. že obsahuje více slov, než je nezbytné. Python oproti tomu vyjádří hodně v několika málo slovech, obvykle přesně, stručně, bez nadbytečností. V kódu jazyka Python se pak také lépe člověk orientuje. Upovídanost Javy ilustruje klasický příklad programu „Hello world!ÿ: public class HelloWorld {
KAPITOLA 4. ANALÝZA
37
public static void main (String[] args) { System.out.println("Hello world!"); } } Oproti Pythonu: print "Hello world!" Dalším příkladem je objekt, který potřebujeme inicializovat s jedním, dvěma či třemi parametry. V Javě musíme napsat tři konstruktory: public class Employee { private String myEmployeeName; private int myTaxDeductions = 1; private String myMaritalStatus = "single"; //--------- constructor #1 ------------public Employee(String argEmployeName) { myEmployeeName = argEmployeeName; } //--------- constructor #2 ------------public Employee(String argEmployeName, int argTaxDeductions) { myEmployeeName = argEmployeeName; myTaxDeductions = argTaxDeductions; } //--------- constructor #3 ------------public Employee(String argEmployeName, int argTaxDeductions, String argMaritalStatus) { myEmployeeName = argEmployeeName; myTaxDeductions = argTaxDeductions; myMaritalStatus = argMaritalStatus; } ... Oproti tomu v Pythonu díky vlastnosti implicitní hodnoty parametrů nám stačí pouze jeden konstruktor: class Employee: def __init__(self,
... Další příklad se týká počtu chyb, které programátor může udělat při psaní kódu. Vezměme třeba jednoduchou konstrukci if, ta v Javě vypadá následovně: if (a > b) { a = b; b = c; } A v Pythonu: if
a > b: a = b b = c
Java má 6 míst, kde se vyskytují řídící znaky („{ÿ, „}ÿ, „(ÿ, „)ÿ, „;ÿ), a ve stejném příkladu má Python pouze jeden (dvojtečku). Programátor tak u Javy stráví mnohem více času uspokojováním kompileru, místo toho aby se soustředil na problém, který má řešit. Python má ještě jeden kontrolní znak, který jiné jazyky jako Java na první pohled nemají, tj. odsazovaní bloků. Jeho používání je ale prakticky nutnost u všech jazyků, protože bez odsazování se téměř nedá přehledný kód napsat. Samozřejmě Python má i své nevýhody, např. kvůli tomu, že se jedná o dynamicky typovaný jazyk, se musí mnoho kontrol provádět až za běhu programu. V Javě už je mnoho z těchto kontrol uděláno při překladu. To je jeden z důvodů, proč je Python o něco pomalejší než Java. Oba jazyky mají v dnešní době JIT (Just In Time) kompiler, který urychluje běh programu. Výkon Pythonu není ale až tak velký problém, částečně proto, že počítače jsou dnes již na většinu problémů dostatečně rychlé, částečně z dobré podpory jazyka k ladění výkonu a dobré spolupráci s jazykem C/C++. Python má totiž v sobě zabudovaný profiler, kterým (v případě že nám výkon programu nevyhovuje, což se zas tak často nestává) můžeme jednoduše najít úzké hrdlo programu a to poté optimalizovat, popřípadě pomocí Python C API relativně jednoduše přepsat do jazyka C či C++. Pomocí tohoto API se také dají namapovat funkce již existující knihovny napsané v C/C++ na Python a z Pythonu pak jednoduše použít.
4.2.2
GUI Knihovna
S jazykem Python spolupracuje většina známých multiplatformních knihoven pro práci s grafickým uživatelským rozhraním. Jmenujme např. QT známé především z linuxového prostředí KDE, GTK+, které používá linuxové prostředí GNOME nebo třeba knihovnu wxWindows. Jelikož mám dobré zkušenosti s použitím GTK+ pod jazykem Python, rozhodl jsem se právě pro
KAPITOLA 4. ANALÝZA
39
tuto knihovnu. K tomuto výběru mě také vedla možnost vizuální tvorby GUI pomocí nástroje GTK Glade builder, v kterém je možno GUI vytvořit jednoduše pomocí myši, uložit ho do XML souboru a ten poté načíst do vlastní aplikace. V Pythonu se GTK+ používá prostřednictvím knihovny PyGTK. GTK+ GTK+ je multiplatformní knihovna pro vytváření grafického uživatelského rozhraní. Nabízí kompletní sadu komponent a hodí se jak pro vytváření malých projektů tak i pro velké aplikace. Je to open source software a je distribuován pod licencí GNU LGPL, která dovoluje tuto knihovnu použít všemi vývojáři včetně těch co vyvíjí proprietární software a to bez jakýchkoliv poplatků. GTK+ je postavena na třech knihovnách vyvíjených GTK+ týmem: • GLib je nízkoúrovňová knihovna, která je základním jádrem GTK+. Poskytuje datové struktury pro programovací jazyk C, portabilní wrappery a rozhraní pro takové funkce jako dynamické načítání a objektový systém. • Pango je knihovna pro vykreslování a renderování textu s důrazem na multijazyčnost. Je to jádro pro zacházení s textem a fonty pro GTK+-2.0. • ATK je knihovna, která poskytuje rozhraní pro přístupnost. Podporou ATK rozhraní může být aplikace použita s takovými zařízeními jako je čtečka obrazovky, lupy a alternativní vstupní zařízení. GTK+ bylo od začátku navrženo tak, aby podporovalo mnoho jiných programovacích jazyků, ne jen C/C++. Používání GTK+ z takových jazyků, jako je Python (obzvláště v kombinaci s používáním aplikace pro grafické vytváření GUI Glade GUI builder) poskytuje velmi efektivní metodu pro rapidní vývoj aplikací. PyGTK PyGTK [6] poskytuje rozhraní pro pohodlné programování v GTK knihovně s použitím programovacího jazyka Python. Stará se o mnoho „nudnýchÿ detailů jako je správa paměti a přetypování datových typů. Stejně jako GTK+, i PyGTK je open source, a to pod licencí GNU LGPL, tudíž je použitelná jak pro svobodný software tak i proprietární aplikace. PyGTK používá mnoho aplikací, od malých jednoúčelových až po velké aplikace.
4.2.3
Komponenta pro editaci textu
Základním prvkem tohoto projektu bude komponenta pro editaci textu. V GTK k tomu slouží komponenta TextView. Ta i umožňuje obarvování textu, které bude potřeba pro zvýrazněnou syntaxi. Ale přímo pro tyto účely TextView dělaná není a tak je obarvování textu poněkud obtížnější. Proto vznikla komponenta GTKSourceView, která se specializuje na editoru zdrojových kódů a umožňuje jednodušším způsobem dosáhnout obarvení syntaxe. To se provádí pomocí definice zapsané ve speciálním XML souboru, který obsahuje např. klíčová slova a vzory syntaktických entit.
40
KAPITOLA 4. ANALÝZA
Nakonec mě nejvíce oslovila komponenta pro editaci textu s názvem Scintilla, která je jádrem editoru SciTE [7]. Je však vydávána zvlášť jako samostatná knihovna. Je taktéž open source licence a multiplatformní. V Pythonu se používá přes knihovnu PyGTKScintilla. Kromě definice pro obarvování syntaxe pomocí speciálního souboru také dovoluje napojit vlastní lexikální analyzátor. Může se zde využít i vícevrstvé obarvování - např. pro náš problém to může znamenat v první fázi zvýraznění syntaxe, v druhé fázi kontrola, zda je dokument well-formed (a zvýraznění případných chyb), a v třetí fázi totéž s kontrolou validity dle XML schématu. Tato komponenta také umožňuje přístup ke svým funkcím pomocí volání metod (od pohybu kurzoru přes hromadné odsazení řádků v označeném bloku až po vyhledávání v textu pomocí regulárních výrazů). Tyto funkce poté bude možno namapovat na klávesové zkratky a také bude možno pomocí jejich skládání vytvářet moduly rozšiřující funkce editoru.
4.2.4
Vývojové prostředí
Mezi vývojovými nástroji pro programování v Pythonu u mně mezi projekty jako např. Eric3, Wing IDE, SPE atd. vyhrálo známé vývojové prostředí Eclipse. Eclipse je open source systém, který je založen na modulární technologii. Primárně je určen pro programování v Javě, ale díky své modularitě je možno Eclipse rozšířit o mnoho další funkcionality. Pro vývoj v Pythonu je zde plugin PyDev. Tento plugin obsahuje funkce jako je code copletion, zvýrazňování syntaxe, analýza syntaxe za pomoci PyLint, refaktoring, ladění a mnoho dalších. PyLint je analyzátor zdrojového kódu napsaného v jazyce Python, který odhaluje chyby a nízkou kvalitu kódu.
4.2.5
Knihovna pro práci s XML
Pro tento projekt je velmi důležitá práce s XML. Pro jazyk Python je na výběr řada knihoven. Od knihoven napsaných v čistém Pythonu po knihovny napsané v C/C++, které v sobě často obsahují i vazbu na Python, popřípadě vazby na Python těchto knihoven poskytuje třetí strana. Výhody knihoven napsaných v C jsou především ve velké rychlosti zpracování dat. Nevýhodou je, že se musí pro danou platformu kompilovat a že ze skriptovacího jazyka není snadné proniknout do nitra této knihovny. Oproti tomu knihovny napsané v čistém Pythonu není třeba kompilovat pro dané platformy a jádro knihovny je průhledné, což se pro programování této práce může hodit. Mezi nejznámější XML knihovny napsané v C, které mají vlastní Python vazbu patří libxml. Je to open source sada nástrojů pro práci s XML, implementující celou řadu standardů jako např. SAX, DOM, XPath, validace podle schémat Relax NG a W3C XML Schémat, XSLT a jiné. Kromě zabudované vazby na Python můžeme pro tuto knihovnu nalézt ještě jednu vazbu pro Python, tj. lxml. Tato knihovna vznikla proto, že standardní vazba na Python obsažená v samotné libxml je až příliš podobná samotnému jazyku C. Knihovna lxml tedy umožňuje jednodušší použití stylem, jaký jsou programátoři v Pythonu zvyklí. Dále přidává i několik vlastností navíc. Příkladem knihovny pro XML napsané v Pythonu je PyXML. Obsahuje nástroje pro parsování SAX a DOM, XSLT transformace, DTD schémata a další. Má zabudované rozhraní PyExpat pro přidání rozšíření napsané v C, což mnohdy znamená násobné zrychlení procesu parsování.
KAPITOLA 4. ANALÝZA
41
V následující sekci popíši příklady použití těchto technologií s použitím knihovny PyXML, kterou jsem nakonec vybral právě kvůli tomu, že je jednoduše z Pythonu přístupná až do svého jádra. Práce s XML pomocí SAX Zkratka SAX znamená Simple API for XML. Jedná se o styl parsování řízený událostmi, které vznikají procházením XML dokumentu jako např. událost počáteční element, koncový element. Na tyto události programátor vytvoří reakce v podobě callback funkcí. Programování v SAX je obecně pro programátora více pracnější, než pomocí DOM, ale výhodou je, že není třeba mít celý dokument v paměti, což v některých případech může být zásadní požadavek. Pomocí callback funkcí musí programátor udržovat informace o aktuálním stavu parsování dokumentu [4]. V následujících příkladech použijeme knihovnu PyXML na vyhledání čísla mobilního telefonu v adresáři reprezentovaným následujícím dokumentem: Eric Idle999-999-999555-555-555 <street>12, spam road LondonH4B 1X3Terry Gilliam555-555-554999-999-998 <street>3, Brazil Lane LeedsF2A 2S5 Kód k takovému vyhledávání může s použitím PyXML vypadat např. takto: import sys from xml.sax import make_parser, SAXException from xml.sax.handler import ContentHandler class PhoneContentHandler(ContentHandler): def __init__(self, name): self.look_for = name self.is_name = False self.is_mobile = False
42
KAPITOLA 4. ANALÝZA self.buffer = ’’ def startElement(self, name, attrs): if name == ’phone’ and attrs.get(’type’) == ’mobile’: self.is_mobile = True elif name == ’name’: self.is_name = True def endElement(self, name): self.buffer = ’’ if self.is_name: self.current_name = self.buffer.strip() self.is_name = False elif self.is_mobile: if self.current_name == self.look_for: self.mobile = self.buffer raise SAXException(’Found mobile phone’) # stop parsing else: self.is_mobile = False def characters(self, chars): if self.is_name or self.is_mobile: self.buffer += chars
def find_mobile_phone(name): handler = PhoneContentHandler(name) parser = make_parser() parser.setContentHandler(handler) try: parser.parse(open(’addressbook.xml’)) except SAXException: return handler.mobile return None if __name__ == ’__main__’: name = ’ ’.join(sys.argv[1:]) phone = find_mobile_phone(name) if phone: print ’Mobile phone is’, phone else: print ’No mobile phone found for’, name Program nejprve přečte parametr, který představuje jméno osoby, jejíž mobilní číslo chceme najít. Toto jméno předáme funkci find mobile phone, která vytvoří instanci naší třídy PhoneContentHandler. Tato třída je odvozena od třídy ContentHandler. Přetížení jejích metod mapujeme naše reakce na události vyvolávané během parsování. Ve funkcích si držíme stav, ve kterém se parsování dokumentu nachází, přesněji pouze pro nás zajímavé situace, tj. pokud se nacházíme v elementu name nebo phone s atributem mobile. V případě nalezení požadovaného čísla osoby ukončíme parsování vyhozením výjimky. Celý proces parsování odstartujeme metodou parse objektu parser.
KAPITOLA 4. ANALÝZA
43
Práce s XML pomocí DOM DOM neboli Document Object Model je standard vytvořen pro W3C konzorciem pro práci s XML a HTML dokumenty. Jedná se o sadu API, která je ve specifikaci reprezentována pomocí jazyka IDL (Interface Definition Language). Díky použití IDL je tato specifikace nezávislá na jazyku a standard DOM je tudíž implementován téměř v každém moderním jazyce. Specifikace DOM je modulární, tj. skládá se z povinného modulu Core a ostatních modulů, které jsou volitelné k implementaci. Tak mohou programátoři různých aplikací implementovat jen ty moduly, které pro svou práci potřebují. DOM drží celý dokument v paměti pomocí stromové hierarchie objektů. Všechny tyto objekty implementují rozhraní Node. Z tohoto rozhraní dále dědí specializovanější objekty, jako jsou například Document, Element atd. API dále obsahuje specifikaci rozhraní pro jednoduché procházení takto vytvořené hierarchie (objektového modelu), stejně jako vytváření, editaci a mazání jejích uzlů. Z charakteristiky specifikace DOM vyplývají i výhody a nevýhody použití tohoto rozhraní. DOM je vhodné použít pokud potřebujeme přehled nad celým dokumentem, jeho jednoduché procházení nebo změnu. Není vhodné ho použít pro velké dokumenty, pro velké nároky na operační paměť (celý dokument je držen v operační paměti). Jako příklad použití v PyXML uveďme opět nalezení mobilního čísla podle jména osoby z adresáře z předchozí sekce:
import sys from xml.dom.ext.reader import PyExpat def findMobilePhone(xmlDOMObject, lookForName): personNames = xmlDOMObject.getElementsByTagName(’name’) for personName in personNames: if personName.firstChild.nodeValue == lookForName: phones = personName.parentNode.getElementsByTagName(’phone’) for phone in phones: if phone.getAttribute(’type’) == ’mobile’: return phone.firstChild.nodeValue
if __name__ == ’__main__’: name = ’ ’.join(sys.argv[1:]) reader = PyExpat.Reader() xmlDOMObject = reader.fromUri(’addressbook.xml’) phone = findMobilePhone(xmlDOMObject, name) if phone: print ’Mobile phone is’, phone else: print ’No mobile phone found for’, name reader.releaseNode(xmlDOMOobject)
44
KAPITOLA 4. ANALÝZA
V příkladu nejdříve vytvoříme objekt reader, kterým poté načteme soubor a vytvoříme objekt XML DOM. Pak už jednoduše procházíme objekty modelu a hledáme elementy, které nás zajímají. Je vidět, že práce s DOM potřebná k vytvoření takového programu je asi menší, než při použití SAX. Také je asi zřejmé, že pro účely tohoto projektu bude potřeba mít přístup k celému stromu (např. pro automatické dokončování či validaci), a proto bude použit pravděpodobně DOM.
45
KAPITOLA 5. REALIZACE
5 Realizace 5.1
Alternativní XML syntaxe
Požadavek na tento projekt je použití alternativní XML syntaxe, která by byla lépe čitelná a editovatelná pro člověka. Pro tento účel jsem se velmi inspiroval syntaxí zvanou SOX (Simple XML Outline) [3]. Výsledná použitá syntaxe byla přizpůsobena tomu, že editor je určen především k editaci konfiguračních souborů (konkrétně přidání komentářů a odebrání víceřádkového řetězce v trojitých uvozovkách). V tomto dokumentu budeme dále zkratkou SOX označovat tuto upravenou verzi. Pro představu uveďme hned příklad, jak může vypadat klasické XHTML, vlevo normální a vpravo zapsaný SOX syntaxí:
Element je zapsán svým jménem a následován znakem „>ÿ. Obsah elementu je pak v odsazeném bloku. Díky odsazení žádný koncový tag v SOX syntaxi není. SOX
Normální XML
element> ... ...
<element> ... ...
46
KAPITOLA 5. REALIZACE
Atribut se zapisuje svým jménem a následně znakem „=ÿ. Vše od znaku „=ÿ až do konce řádku je hodnota atributu. Atribut musí být umístěn uvnitř elementu a nesmí mu na stejné úrovni předcházet element nebo textový uzel. Jinými slovy na dané úrovní odsazení pro daný element se nejdříve zapisují atributy a poté teprve zbylý obsah daného elementu. SOX