Delphi - XML felhasználása Delphi-ben

XML 2. rész

Az XML cikksorozat előző részében megismerkedtünk az XML történelmével, alapjaival. Ebben a részben részletesen tárgyaljuk a dokumentumban előforduló jelöléseket (DTD, egyedek, elemek, stb.). Egyed meghatározás
Az egyedeket a rájuk való első hivatkozás előtt definiálni kell az egyed deklaráció használatával:
<!ENTITY …>
Az egyed nevének megadásakor a következő szabályokat kell betartani:
  • a név betűvel, "-" vagy ":" karakterrel kell, hogy kezdődjön;
  • a további karakterek lehetnek betűk, számok, ".", "-", "_" vagy ":" jelek;
  • a névben a kis- és nagybetűk különbözőnek számítanak.
<!ENTITY Egyed …>
Ha egy egyed többször is definiálva van, akkor mindig az első lesz figyelembe véve. A dokumentumon belül egy egyedre a nevével hivatkozunk, hivatkozás ugyanazon egyedre akár többször is előfordulhat, illetve előfordulhat olyan eset is, amikor nincs hivatkozás az egyedre.

Egy XML dokumentumban többféle egyedtípus előfordulhat. A belső szöveg egyed egy karaktersorozatot helyettesít.
<!ENTITY dso "Delphi Software Online">
A szöveg megadásánál lehet aposztróf, vagy idézőjel karaktereket is használni. Javasolt az aposztróf karakter használata, mivel így az idézőjel egyszerűbben elhelyezhető a szövegben. Az egyedre úgy hivatkozhatunk a szövegben, hogy egy "&" karaktert teszünk a neve elé, és utána egy ";" karaktert.
<cim>Az oldal címe &dso;</cim>
Mivel néhány karakter eleve foglalt az XML dokumentumban, ezért ezek helyettesítéséhez léteznek beépített egyedek:
  • <: "<" karakter;
  • < ">" karakter;
  • & "&" karakter;
  • ' aposztróf karakter olyan értékekben, ahol ez a határoló karakter;
  • " idézőjel karakter olyan értékekben, ahol ez a határoló karakter.
    <bekezd>Ez egy "idézőjelbe" tett szó!</bekezd>
    
A fenti példa eredménye: "Ez egy "idézőjelbe" tett szó!"

Az ún. karakter egyedekre ugyanúgy hivatkozhatunk, mint a szöveg egyedekre, de az "&" karakter után egy "#" karakter áll, majd ezt követi egy decimális, vagy hexadecimális szám. A 0-255 közötti értékek egy normál ASCII karaktert jelenítenek meg, míg az ennél nagyobb érték (256-65535) egy Unicode/ISO karaktert. Hexadecimális érték esetén a szám előtt még egy "x" karakternek is kell állnia.
<bekezd>Ez egy Unicode karakter: &#FF67;</bekezd>
<bekezd>Ez a < karakter: <</bekezd>
Létrehozhatunk ún. paraméter egyedeket is, melyeket a DTD-ben is felhasználhatunk. A paraméter egyedek neve elé egy százalékjelet ("%") kell tenni, a deklarációnál és a hivatkozásnál egyaránt.
<!ENTITY % kozos "(kep | lista)">
A külső fájlra való hivatkozást a SYSTEM kulcsszó használatával tudunk definiálni. A kulcsszó az egyed neve után áll, és azt követi az URL hivatkozás.
<!ENTITY impr SYSTEM "/KOZOS/IMPR.XML">
Bináris egyed deklarációja nagyon hasonlít a külső fájl egyed deklarációjához, csak annyi a különbség, hogy a hivatkozás után az NDATA kulcsszó után meg kell adni a fájl formátumát is.
<!ENTITY logopic SYSTEM "/IMAGES/LOGO.GIF" NDATA "GIF87A">
A fájl formátumát akkor is meg kell adni, ha az a fájl kiterjesztéséből egyértelműen következik.


Dokumentum típus deklaráció (DTD)
Az XML egyik legnagyobb előnye, hogy saját tag neveket hozhatunk létre, amik viszont nem lesznek egyértelműek a feldolgozó program számára. A helyes feldolgozás érdekében szükség van olyan szabályokra, melyek a tag-ek sorrendjét és egymásba ágyazhatóságát határozzák meg. Ezeket a szabályokat deklarálhatjuk a DTD-ben. Az XML-ben négyféle deklaráció van: jelölőelem definíció (element), jellemző definíciók (attlist), egyed (entity) és jelölés (notation) definíció.
A deklarációk a dokumentumtípus-deklarációban (DOCTYPE) szerepelnek:
<!DOCTYPE konyv [
<! …>
<! …>
]>
Ha a deklarációt, vagy legalábbis egy részét több dokumentumban is fel szeretnénk használni, akkor célszerű ezt egy külön fájlban tárolni, amire aztán minden dokumentumból hivatkozhatunk:
<DOCTPYE konyv SYSTEM "./DTD/konyvek.dtd" [
<! …>
<! …>
]>
Egy belső egyed deklarációval felülírhatjuk a külső állományban szereplő meghatározást, ha az egyed mindkét helyen előfordul.

Elem típus deklaráció
Az elem típus deklarációk azonosítják az elemek neveit, és tartalmukat:
<!ELEMENT fejezet (bekezd+, ures)>
Az elem nevének betűvel, "_" jellel vagy kettősponttal kell kezdődnie, és tetszőleges hosszúságú lehet. A név után következnek a tartalmat meghatározó deklarációk. Ha az elem nem tartalmaz további elemeket vagy egyéb tartalmat, akkor az egy üres elem. Ennek jelölése EMPTY. Ha az elem bármilyen másik elemet tartalmazhat, akkor annak jelölése ANY. Ennek használata azonban nem javasolt.
<!ELEMENT ures EMPTY>
<!ELEMENT minden ANY>
A legáltalánosabb eset, amikor az elem meghatározott elemeket vagy szöveget tartalmaz, ilyenkor egy csoportot kell megadni, ami az elemen belül elfogadott.
<!ELEMENT fejezet (bekezd+, kep*)>
<!ELEMENT abra (#PCDATA | kep)*>
Az ilyen elemek tartalma esetenként lehet üres is. Ekkor a nyitó és záró elemek közvetlenül követik egymást:
<bekezd></bekezd>
Ebben az esetben lehetőség van rövidített jelölésre.
<bekezd/>
Ha egy elem deklarációjánál elem, vagy vegyes tartalmat adunk meg, akkor ehhez használhatunk ún. modell csoportokat. Olyan elem, amelynél csak elem tartalmat definiáltunk, csak gyermek elemeket tartalmazhat, míg a vegyes tartalmú egyaránt tartalmazhat elemeket, vagy szöveget. Ez utóbbi a felhasználáskor lehet, hogy csak elemeket, vagy csak szöveget tartalmaz, de lehet, hogy mindkettőt egyszerre. Ezek sorrendjét azonban nem szabályozhatjuk.
A modell csoport szögletes zárójelben jelenik meg, és legalább egy tokent tartalmaz, ami lehet például egy elem neve, amely további elemeket tartalmazhat.
Egy modell csoportban az elemek különböző módon szervezhetők. Az elemek összekapcsolására két különböző logikai műveletet használhatunk: Az "&" (és) összekapcsolás nem használható, mivel ezzel a dokumentumot nagyon bonyolulttá lehet tenni, és a feldolgozás sokkal nehezebb lenne. Ezt a kapcsolatot a sorozat összekapcsoló segítségével lehet pótolni.
A sorozat szabály azt jelenti, hogy "(a, b, c)" esetében az "A" elemet követi a "B" elem, majd ezután következik a "C" elem.
A második esetben, ha a választás szabályt használjuk, akkor az "(a | b | c)" esetében választhatunk, hogy melyiket használjuk, de csak az egyiket választhatjuk.
A műveleti jeleket nem szabad keverni, mivel így a szabály nem lesz egyértelműen meghatározható. Használhatunk viszont egybeágyazott modell csoportokat, ami ennek a problémának a kiküszöbölését szolgálja. A "(a, b | c)" nem használható, viszont a "((a, b) | c)" vagy "(a, (b | c))" igen.

A DTD-ben az is meghatározható, hogy egy elem milyen gyakran fordulhat elő, ezeket az ún. mennyiségi jelzők szabályozzák. Ha egy elem csak egyszer fordulhat elő, de egyszer biztosan, akkor nem kell külön megjelölést használni. Ha egy elem nem kötelezően fordul elő, de ha előfordul, akkor is csak egy példányban, akkor a neve után egy kérdőjelet ("?") kell tenni. Például az "(a, b?)" azt jelenti, hogy a "B" elem opcionális. Ha egy elem legalább egyszer, de akár többször is előfordulhat, akkor ezt egy plusz ("+") jellel jelezhetjük, például "(a, b+)". Ha egy elem tetszőleges számban előfordulhat, de nem kötelező, akkor ezt egy "*" karakterrel jelöljük. Például a "(a, b*)" jelölésnél a "B" elem többször is előfordulhat, de lehet, hogy egyszer sem. A "*" úgy is tekinthető, mint a "?" és a "+" kombinációja ("?+"), ami ebben a formában nem használható.
Meghatározható az is, hogy egy elem minimum kétszer, vagy ennél többször szerepelhet csak. Például egy felsorolás csak akkor felsorolás, ha legalább két eleme van. Ebben az esetben a deklaráció így néz ki: "(tétel, tétel+)".
A mennyiségi jelölések nem csak a modell csoport elemeire használhatók, hanem magára a csoportra is. Például a "(a, b)*" jelölés azt jelenti, hogy az elemek ebben a sorrendben, akár többször is megjelenhetnek, de nem feltétlenül kell előfordulniuk.

Azt, hogy egy elem szöveget tartalmaz, a PCDATA kulcsszóval jelezhetjük, amely előtt egy "#" karakternek kell állnia. A kulcsszó azt jelenti, hogy az elem 0, vagy ennél több karaktert tartalmaz. Ha egy elemet úgy akarunk deklarálni, hogy az csak szöveget tartalmazhasson, akkor azt a következőképpen tehetjük meg:
<!ELEMENT szoveg (#PCDATA)>
…
<szoveg>Itt állhat a szöveg!</szoveg>
Ha egy elem vegyesen tartalmazhat szöveget, vagy további elemeket, akkor annak definíciójánál szigorú szabályokat kell betartanunk. A PCDATA kulcsszónak kell a modell csoportban elöl állnia, és ezután "|" kapcsolattal következhetnek a további elemek, valamint egész modell csoportnak választhatónak kell lennie:
<!ELEMENT bekezdes (#PCDATA | kiemel)*>
<!ELEMENT kiemel (#PCDATA)>
…
<bekezdes>Ez egy <kiemel>fontos</kiemel> szöveg!</bekezdes>
Az egyes elemek tulajdonságait egy ún. jellemző listában adjuk meg, általában az összes tulajdonságot egyszerre. A jellemző definíciókat az ATTLIST kulcsszó vezeti be:
<!ATTLIST bekezdes …
          … …>
Az elem neve után állnak az elem jellemző tulajdonságai. Ha több is van, akkor ezek összegződnek. Ha egy definíció többször is szerepel, akkor mindig az első definíció lesz figyelembe véve. A jellemző definíció meghatározza a jellemző nevét, típusát, és gyakran az alapértelmezett értékét is. A jellemző nevére ugyanazok a szabályok vonatkoznak, mint az elemek nevére.
A jellemző típus a következők egyike lehet:
<!ENTITY logo SYSTEM "C:\IMAGES\LOGO.GIF" NDATA "GIF87A">
<!ELEMENT kep EMPTY>
<!ATTLIST kep fajl ENTITY>

<kep fajl="logo">
  • ENTITIES: többszörös ENTITY attribútum.
  • ID: egy olyan attribútum érték, amelynek elemenként különbözőnek kell lennie, önálló elemek egyedi azonosítói. Minden elemnek csak egy ID attribútuma lehet.
  • IDREF: egyszerű ID attribútum érték.
  • IDPREFS: több IDREF attribútum értéket tartalmaz szóközzel elválasztva.
  • NOTATION: ez határozza meg, hogy milyen elem típusok ágyazhatók be egy elembe.
    <!ATTLIST kep formatum NITATION (TIFF | GIF87A)>
    
    Név csoport: a lehetséges értékek halmazát adja meg. A "piros | sarga | zold" azt adja meg, hogy az érték a felsorolt elemek egyike lehet. Sok esetben akkor is hasznos, ha csak egy lehetséges érték van.
    <!ATTLIST lampa szin (piros | sarga | zold)>
    
    A jellemzők deklarációjánál a legutolsó paraméter az alapértelmezett érték. Ez akkor lép érvénybe, amikor a dokumentum készítője nem ad meg értéket a jellemzőhöz. Ez a paraméter használható arra is, hogy meghatározzuk a készítőnek azt, hogy a jellemzőnek kötelező-e értéket adni, vagy elhagyható. Ha az alapértelmezett értéket kötelezővé tesszük, akkor az lesz az adott jellemző egyetlen érvényes értéke. Ha a #REQUIRED kulcsszóval kötelezővé teszünk egy jellemzőt, akkor annak elhagyása hibaüzenethez vezet.
    <!ATTLIST szemely vnev CDATA #REQUIRED>
    
    Ennek ellentéte a #IMPLIED kulcsszó, amellyel azokat a jellemzőket jelöljük meg, melyek megadása nem kötelező.
    <!ATTLIST szemely tel CDATA #IMPLIED>
    
    Lehetőség van alapértelmezett érték megadására, ami nagyon hasznos, továbbá a dokumentum méretét is csökkentheti. Az alábbi példában a "nem" attribútum alapértelmezett értéke "férfi".
    <!ATTLIST szemely nem (ferfi | no) "ferfi">
    
    Nem adható meg alapértelmezett érték a kötelező (#REQUIRED) és a burkolt (#IMPLIED) jellemzőkhöz. Ha az alapértelmezett értéket megelőzi a #FIXED kulcsszó, akkor a megadott érték lesz az egyetlen, amit a jellemző felvehet.
    Nem hozhatunk létre olyan jellemzőket, melyek az "xml:" karaktersorozattal kezdődnek, mivel ezt a szabvány lefoglalta, az "xml:lang" és "xml:space" jellemzőket pedig már használja is.

    A DTD létrehozását egyszerűsíthetjük paraméter egyedek létrehozásával. Ezek a paraméter egyedek a gyakran használt modell csoportokból állnak össze.
    <!ENTITY % kozos "bekezd | kep | tablazat">
    
    Amikor egy DTD-t úgy készítünk el, hogy az más dokumentumokba is felhasználható legyen, akkor előfordulhat olyan eset, hogy az adott dokumentumban bizonyos részeket nem akarunk felhasználni, és ezeket kizárjuk. Ezt a lehetőséget feltételes részek beiktatásával tudjuk elérni. Ebben az esetben a kizárandó részt befoglalt rész deklarációval (INCLUDE) vesszük körül.
    <![INCLUDE[ … ]]>
    
    A fenti résszel azonban csak megjelöltük a deklarációt, de ez semmilyen hatással nem lesz rá. Ha valóban ki szeretnénk zárni az adott részt, akkor az INCLUDE kulcsszó helyett az IGNORE kulcsszót kell használnunk. Az INCLUDE használatának értelme abban áll, hogy így a befoglalt részt egyszerűen kizárttá tehetjük úgy, hogy az INCLUDE-t átírjuk IGNORE-ra. A kulcsszót helyettesíthetjük paraméter egyeddel is. Az alábbi példában, ha az "elso" paraméter egyed értéke "INCLUDE", akkor a "szoveg" elem tartalmazhatja a B elemet, ellenkező esetben pedig nem. Ennek oka, hogy az egyed deklarációjánál mindig az elsőt veszi figyelembe, a másodikat pedig nem. Ha az "elso" paraméter egyed értéke "IGNORE", akkor a második deklaráció lesz az érvényes.
    <!ENTITY % elso "INCLUDE">
    <![%elso;[<!ENTITY szoveg "#PCDATA | a | b">]]>
    <!ENTITY szoveg "#PCDATA | a">]]>
    
    Az már az eddigiekből is következik, hogy egy egyed tartalmazhat nem XML típusú adatokat. Az elem deklaráció egyértelműen meghatározza, hogy milyen elemeket lehet beágyazni, és egy egyed deklaráció pontosan megadja, hogy milyen adat van beágyazva. Mindkét esetben ez a jelzés deklarációban (NOTATION) van megadva.
    <!NOTATION TeX SYSTEM "..\TEXVIEW.EXE">
    
    A létrehozott, vagy már létező jelzésre az egyed deklarációnál az NDATA kulcsszó után, illetve a jellemző deklarációban lehet hivatkozni:
    <!ENTITY fejlec SYSTEM "fejlec.tex" NDATA TeX>
    <!ATTLIST  kep formatum NOTATION (TeX | GIF) "GIF">
    
    <kep formatum="TeX"> … </kep>
    


    Névterek
    Ha több különböző DTD-vel rendelkező dokumentumot szeretnénk egymásba ágyazni, például egy HTML dokumentumot szeretnénk beszúrni, akkor több probléma is felmerül. Ebben az esetben ugyanis előfordulhat, hogy az azonos nevű elemek vagy jellemzők mást-mást jelentenek a két, vagy több összefűzött dokumentumban, éppen ezért az elemeket azonosítani kell, hogy melyik sémához tartoznak.
    Ennek a problémának a megoldására dolgozták ki a Namespaces in XML szabványt (Névterek az XML-ben).
    Az egyes névterekhez tartozó elemeket és jellemzőket úgy különbözteti meg a szabvány, hogy az elem neve elé egy előtag kerül. Így kapjuk meg az ún. minősített neveket.
    előtag:név
    
    Az előtagnak egyedinek kell lennie, ezért célszerű lenne annak az URL-nek a használata, ahol az adott szabvány van. Egy URL viszont egyrészt túl hosszú is lehet, másrészt tartalmazhat olyan karaktereket, melyek a név definícióban nem használhatók.
    Az "xmlns" jellemzővel tudjuk a névtereket deklarálni, egyszerre megadva az azonosítót, ami az URL-t fogja azonosítani.
    <X:html xmlns:X="http://www.w3.or/TR/REC-html40">
      <X:P>Új bekezdés</X:p>
    </X:html>
    
    Furcsa lehet a fenti deklarációban, hogy a névtér azonosítója az "xmlns" előtt áll.
    Ha egy XML dokumentumba például HTML táblázatot szeretnénk elhelyezni, akkor azt a következőképpen is megtehetjük:
    <X:bekezd>Ez egy bekezdés a dokumentumban</X:bekezd>
    <X:table xmlns:X="http://www.w3.or/TR/REC-html40">
    …
    <X:td>Ez a HTML táblázat egyik cellája!</X:td>
    …
    </X:table>
    <X:bekezd>Ez szintén egy normál bekezdés.</X:bekezd>
    
    Ha minden jellemző elé odaillesztenénk a névtér azonosítóját, akkor az állomány mérete jelentősen megnőne, ráadásul az értelmezhetőség is nehezebb lenne. Éppen ezért a jellemzők alapértelmezésként öröklik annak az elemnek a névterét, amihez tartoznak. Létrehozhatunk alapértelmezett névteret is, ebben az esetben nem kell az azonosítót megadni:
    <bekezd xmlns="file:/bekezd.dtd">
    …
    </bekezd>
    
    Ha névtereket használunk, akkor a dokumentum érvényességének ellenőrzéséhez szükség van a DTD-ben is megadni ezeket.


    URL
    Az URL (Unified Resource Locator) szabványt a dokumentumok Interneten történő eléréshez fejlesztették ki, de kiválóan alkalmas arra, hogy helyi hálózatokon (Intranet), illetve számítógépeken meghatározzuk az állományok helyét.
    A böngészők egy adott weblap megtalálásához, valamint az ezen található hivatkozásokhoz is URL-eket használnak. A közismert egyedi azonosítókat tartalmazó névterek azonosítására szintén ilyen URL-eket használunk.
    Egy URL hivatkozásban a "/" jelet használjuk a szintek elválasztására, míg a ".." a szülő könyvtárat jelenti. A gyökérkönyvtárat "/" jellel azonosítjuk. A hivatkozás elején a használni kívánt protokoll azonosítója áll, "//" karakterekkel lezárva (pl. "http://"). Ezután következik a gazdagép neve, majd a könyvtárak, és a legvégén az állomány neve.
    protokoll://gép/könyvtár/állomány
    
    Ha egy alkalmazáshoz való kapcsolódásánál a port számának megadása is szükséges, akkor azt a gazdagép neve után adhatjuk meg, kettősponttal elválasztva attól:
    protokoll://gép:1234/könyvtár/állomány
    
    Az URL egyes részei elhagyhatók, a legegyszerűbb esetben csak az állománynév szerepel.
    A hivatkozásban a következő karaktereket használhatjuk:
    kis- és nagybetűk;
    számok;
    "-", "_", pont, vessző, "+", "$";
    
    Ha más karaktert is meg kell adni, akkor azt egy százalékjel ("%") után a karakter ASCII kódjának megadásával tehetjük meg. Például a százalékjelet a "%33" a felkiáltójelet, a "%25" jelenti.

    Ha olyan fájlra hivatkozunk, ami a helyi számítógépen van, akkor a protokoll megnevezése helyett a "file:" megnevezésnek kell szerepelnie.
    <!ENTITY fejlec SYSTEM "file:///c:/sajat/header.xml">
    
    Furcsa lehet a "file:" után álló három darab "/" jel. Az első kettő a "protokollt" választja egy a hivatkozás többi részétől. A Harmadik "/" a gyökérkönyvtárat jelöli. Mivel a "file:" nem egy hagyományos értelemben vett protokoll, ezért néhány alkalmazás nem követeli meg az első két perjel használatát.
    <!ENTITY fejlec SYSTEM "file:/c:/sajat/header.xml">
    
    Windows-os környezetben a meghajtó betűjelét nem hagyhatjuk el.

    Az URL-ek segítségével olyan állományokra is hivatkozhatunk, melyek nem részei a helyi rendszernek. Az állományok letöltéséhez leggyakrabban használt protokoll a HTTP (HyperText Transfer Protocol):
    <!ENTITY animare SYSTEM "http://www.animare.hu">
    
    Az FTP protokollt használjuk abban az esetben, ha egy állományt le szeretnénk tölteni a saját rendszerünkben való tárolás céljából, mivel ez a protokoll gyors és biztonságos letöltést tesz lehetővé.
    <!ENTITY letolt SYSTEM "ftp://www.letoltesek.com/program.zip">
    
    Nem mindig kell a teljes elérési útvonalat megadni egy hivatkozásban, sok esetben elég egy ún. relatív hivatkozás, ami a kiinduló állomány elérési útvonalához képest határozza meg az állomány helyét.
    <!ENTITY lista1 SYSTEM "listak/lista1.xml">
    
    A relatív hivatkozások használatának nagy előnye, hogy az összes összefüggő állomány áthelyezhető a hivatkozások módosítása nélkül.

    Hiperhivatkozások
    A hagyományos papíralapú kiadványokkal ellentétben az elektronikusan publikált dokumentumokban nem használhatók lábjegyzetek, szószedetek, valamint ezekhez hasonló információkeresést és tájékozódást segítő elemek. Éppen ezért a dokumentumot megjelenítő alkalmazás számos olyan lehetőséget tár a felhasználó felé, amelyek segítségével a kívánt dokumentumrészletek gyorsan megkereshetők. Egy ilyen megoldás az úgynevezett hiperhivatkozás is.
    Az XML dokumentumban a kiindulási pont a kapcsoló elem, a célobjektum pedig egy erőforrás. A művelet, amely során a kapcsoló elemtől eljutunk a célobjektumig az úgynevezett áttűnés.
    Az XML nem korlátozza a kapcsoló elem, illetve a célobjektum meghatározását tartalmazó jellemző nevét, viszont a DTD-ben speciális jellemző típusokkal kell jelölni azokat az elemeket, amelyek helymeghatározó kódokat tartalmazhatnak.
    A legegyszerűbb kapcsolódás, amikor a dokumentumon belül hivatkozunk egy helyre. Ennek két feltétele van: a hivatkozott elemnek kell, hogy legyen egy ID jellemzője, illetve a kapcsoló elemnek egy IDREF jellemzője. Az ID jellemzőnek egyedi értékkel kell rendelkeznie.
    <!ELEMENT megj (…) >
    <!ELEMENT hiv (..)>
    <!ATTLIST megj azon ID #REQUIRED>
    <!ATTLIST hiv hova IDREF #REQUIRED>
    
    <megj azon="M102">
    <bekezd>Ez egy megjegyzés amire hivatkozhatunk.</bekezd>
    …
    </megj>
    
    <bekezd>Ez itt egy <hiv hova="M102">hivatkozás</hiv> a megjegyzésre</bekezd>
    

    XML cikksorozat