XML, XSD, XPath és XSLT alapok

Az XML formátum manapság, ha üzenetkezelő middleware technológiákról esik szó: gyakorlatilag megkerülhetetlen. XML, mint eXtensible Markup Language, azaz kiegészíthető jelölő nyelv. Ez a nyelv egy általános szintaktikai szabályrendszert biztosít ahhoz, hogy az üzeneteink struktúráját felépítsük.

Az XML szintaktikája teljesen általánosan, elemek és ezekhez kapcsolódó attribútumok jelölésére alkalmas. Az elemek lehetnek egyszerű, csak szöveges tartalommal bíró, valamint komplex típusúak, melyek más elemeket is tartalmazhatnak.

Például:

  • Egyszerű elem: <elem1>elem tartalma</elem1>
  • Egyszerű elem attribútummal: <elem1 attribútum1=”attribútum értéke”>elem tartalma</elem1>
  • Komplex elem: <elem1><elem2>elem2 tartalma</elem2></elem1>

Az XML nyelv nem tartalmaz szemantikai értelmezést a jelölhető objektumokhoz, azaz tartalmazott és tartalmazó elemek, vagy elemek és hozzájuk rendelt attribútumok, de akár egyszerű elemek jelentése is teljes mértékben szabadon értelmezhető. Gyakorlatban legtöbbször az elemek és attribútumok címkéje mutatja a szándékolt jelentést, és itt fontos a szándékolt kitétel, hisz maga az XML dokumentum nem köti meg az értelmezést.

Példa:

<osztaly nev=”1A” evfolyam=”2009-2010”>

<tanulo nev=”Kovács András”>

<targyak>

<matematika evVegiOsztalyzat=”5”>

<osztalyzat>5</osztalyzat>

<osztalyzat>5</osztalyzat>

</matematika>

</targyak>

<tanulo nev=”Kis Eszter” />

</osztaly>

 

Az előző példában látható egy egyszerű XML dokumentum, mely egy középiskolai napló részletét szándékozik leírni. Mindehhez az XML nyelv csak az eddig tárgyalt elemek, az elemek közötti tartalmazó kapcsolat és az attribútumok jelöléséhez szükséges módot biztosítja. A következő fejezetben bemutatott XSD leíró definiálja az XML itt látható felépítését, azaz a használható elem és attribútumcimkéket, az elemek egymáshoz való viszonyát, valamint a lehetséges értékeiket. De egyelőre csak azt akartam kiemelni, hogy bár az XML dokumentumokat szokás önleírónak nevezni, az értelmezésük mégsem teljesen kötött.

 

Egy XML dokumentumban lévő elemek a tartalmazás kapcsolat mentén hierarchiába szerveződnek. Ez a hierarchia egy egygyökerű fával reprezentálható. A dokumentum legfelső szintjén található a gyökér elem, melyet nem tartalmaz másik elem. Majd következnek a gyökér elem gyerekei, majd azok gyerekei és így tovább. Valóban fáról, azaz körmentes gráfról beszélünk, mivel egy elemnek csakis egy szülő eleme lehet a tartalmazás kapcsolat mentén. Ezen hierarchiában, tehát egy általános elemnek lehetnek szülő eleme, testvér elemei és gyerek elemei. Ezen fogalmak az XML dokumentum feldolgozása során az abban történő navigáláshoz alkalmazandóak. Az attribútumok praktikusan, mint az őket birtokló elem gyerek csomópontjai helyezhetőek a hierarchiába.

Például az előző XML dokumentum felépítése:

Amennyiben egy dokumentum megfelel az XML szabványban definiált szintaktikának, akkor azt jól formáltnak (well formed) nevezzük.

Természetesen itt csak az XML formátum alapvető koncepciójával foglalkoztam, a formátum részletes leírása a http://www.w3.org/TR/xml/ linken olvasható.

 

Az XSD leíró szolgál a leírt XML dokumentumok felépítésének megadására. XSD, mint XML Schema Definition, azaz XML séma definíció. Programozástechnikai kifejezésekkel élve az XSD leíró tekinthető, mint egy osztálydefiníció, míg a neki megfelelő XML dokumentumok, mint az egyes osztálypéldányok.

Az XSD leíró segítségével definiálható az XML dokumentumokban használható elemek és attribútumok címkéje, értékeik típusa és értékkészlete, valamint az elemek hierarchiája. Amennyiben egy XML dokumentum megfelel az őt leíró XSD-nek, akkor azt validnak nevezzük.

De még mielőtt részletesebben foglalkoznánk az XSD leírókkal, fontos, hogy az XML névterekről is essen szó. A névterek használata lehetővé teszi, hogy egy XML dokumentumban a más-más forrásból származó, azonos címkéjű objektumokat egyértelműen meg lehessen különböztetni. Ennek megfelelően egy XML névtéren belül egyedi minden egyes elem, attribútum, vagy típus, azaz ugyan azon név alatt nem szerepelhet több objektum. A névteret az objektumok címkéjében megjelenő névtér azonosító jelzi, míg az azonosítót, annak az adott részfában való első megjelenésénél felvett xmlns definíció inicializálja. Egy XSD leírón belül egy névtérben definiálhatunk objektumokat, de egy XML dokumentumban több névtérből származó objektum is szerepelhet.

Példa névtér hivatkozására:

Ez esetben az adott elem gyerekei csak a megfelelő névtér címke alkalmazásával kerülnek a megadott névtérbe.

Az elem minden gyerek eleme is a megadott névtérből való, hacsak más névtér nem kerül megadásra.

A névterek neve tradicionálisan URI ként kerül megadásra, de ez ne tévesszem meg senkit, névként bármilyen egyedi karakterlánc használható, valamint a megadott URI nem az XSD leíró elérési helyét adja meg.

Az XSD leírókban, noha csak egy névtérben definiálhatóak objektumok, más névtérben definiált objektumok használhatóak, amihez az adott névteret importálni szükséges, majd az objektumok a ref kulcsszóval hivatkozhatóak.

 

 

Például:

<xs:schema targetNamespace=”http://myURI.org/” xmlns:xs=”http://www.w3.org/2001/XMLSchema”xmlns:tns=”http://myURI.org/” xmlns:importedns=”http://myImportedURI.org/”>

<xs:import namespace=”http://myImportedURI.org” schemaLocation=”schema1.xsd”>

<xs:element name=”elem1”>

<xs:complexType>

<xs:sequence>

<xs:element ref=”importedns:elem2” />

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:schema>

 

Most pedig lássuk az XSD leírók általános lehetőségeit egy a korábban használt XML dokumentumhoz készült XSD leíró bemutatásával:

<xs:schema targetNamespace=”http://myURI.org/” xmlns:xs=”http://www.w3.org/2001/XMLSchema”xmlns:tns=”http://myURI.org/”>

<xs:complexType name=”osztalyType”>

<xs:sequence>

<xs:element minOccurs=”1″ maxOccurs=”40″ name=”tanulo” type=”tns:tanuloType”/>

</xs:sequence>

<xs:attribute name=”nev” type=”xs:string” />

<xs:attribute name=”evfolyam” type=”xs:string” />

</xs:complexType>

<xs:complexType name=”tanuloType”>

<xs:sequence>

<xs:element minOccurs=”1″ maxOccurs=”1″ name=”targyak” type=”tns:targyakType”/>

</xs:sequence>

<xs:attribute name=”nev” type=”xs:string” />

</xs:complexType>

<xs:complexType name=”targyakType”>

<xs:sequence>

<xs:element minOccurs=”0″ maxOccurs=”1″ name=”biologia” type=”tns:targyType”/>

<xs:element minOccurs=”0″ maxOccurs=”1″ name=”matematika” type=”tns:targyType”/>

</xs:sequence>

<xs:attribute name=”evVegiOsztalyzat”>

<xs:restriction base=”xs:nonNegativeInteger”>

<xs:simpleType>

<xs:enumeration value=”1″/>

<xs:enumeration value=”2″/>

<xs:enumeration value=”3″/>

<xs:enumeration value=”4″/>

<xs:enumeration value=”5″/>

</xs:simpleType>

</xs:restriction>

</xs:attribute>

</xs:complexType>

 

<xs:complexType name=”targyType”>

<xs:sequence>

<xs:element minOccurs=”0″ maxOccurs=”unbounded” name=”osztalyzat” type=”xs:nonNegativeInteger”/>

</xs:sequence>

</xs:complexType>

<xs:element name=”osztaly” type=”tns:osztalyType”/>

</xs:schema>

 

Mint látható az XSD leírók is XML formátumúak, gyökér elemük az xs:schema, ahol az xs (természetesen más névtér címke is használható) hivatkozza az XSD-k nyelvét leíró névteret. A gyökér elemben érdemes a leíróban általánosan használt valamennyi névteret és címkéjüket megadni. A schema elemben kell megadni a leíróban definiált névteret is a „targetNamespace” attribútumban, tehát a leíróban definiált valamennyi objektum az ebben az attribútumban megadott névtérbe fog tartozni. A példa XSD, komplex típusokat, elemeket, valamint attribútumokat definiál. Mint látható minden elem és attribútum tartalma típusával adott, az xs névtérben megadott egyszerű típusokon túl a komplex elemeket saját komplex típusok írják le. A komplex típusokon belül definiált elemek sorrendje a sequence elem által kötött, valamint minden elem ismétlődési száma a minOccurs és maxOccurs attribútumokkal adott. Az evVegiOsztalyzat attribútum esetében látható, hogy az egyes egyszerű objektumok értékkészlete, az egyszerű típusokon belül tovább szűkíthető.

Az XSD leíróban megadható megkötésekről elmondható, hogy azok csak dokumentum típusra vonatkozhatnak, olyan megkötést, ami adott dokumentum példányban szereplő értékektől függ nem tudunk megadni.

Az XSD leírók részletes leírása a következő linken érhető el: http://www.w3.org/XML/Schema

 

Az XPath jelölés az XML dokumentumokban való elérési utak hivatkozására ad eszközt számunkra. Használatával az XML dokumentum bármely objektuma hivatkozható, hasonló módon, mint egy háttértár esetén.

Az XML dokumentum gyökerét a „/” jelöli, fontos, hogy ez nem a gyökér elem, hanem a dokumentum kezdete gyakorlatilag. Itt fontos megemlíteni, hogy az XML dokumentumokban, minden objektum közvetlenül hivatkozható, tehát nem csak az eddig tárgyalt elemek és attribútumok, hanem például a feldolgozási utasítások, kommentek és a szöveges értékek is.

De az XPath nem csak abszolút címek megadására alkalmas. Ha a címet nem a „/” karakterrel kezdjük, akkor a megadott cím az aktuális objektum gyerek elemeitől érvényes relatív hivatkozásként értelmezendő.

Az XPath-szal nem elsősorban konkrét objektumok, hanem általában objektumok csoportja hivatkozható. Például a /osztaly/tanulo XPath kifejezés, valamennyi „tanulo” elemet hivatkozza a korábbi példa XML dokumentumban. Ahhoz, hogy ilyen esetekben pontosítani tudjuk a hivatkozott objektumot, az objektum további tulajdonságaira illeszkedő feltételes kifejezéssel kell kiegészítenünk az XPath kifejezést. Például: a/osztaly/tanulo[@nev=’Kovács András’] kifejezés, már csak azokra a „tanulo” elemekre fog illeszkedni, ahol a „nev” attribútum értéke Kovács András.

Az XPath kifejezésekben alkalmazhatóak, mind a navigációra, mind az értékekre vonatkozó wildcard karakterek. A „//” jelölés, azt jelenti, hogy a dokumentumban, az adott pozíciótol bárhol, tehát nem csak az adott pozíciótól számított gyerek elemek között lévő elem. Például a //tanulo minden „tanulo” elemet hivatkoz a korábbi példa XML dokumentumban. A „.” az aktuális objektumot, míg a „..” jelölés annak szülejét jelöli. Például a /osztaly//targyak/.. kifejezés, a példa dokumentumunkban szintén a „tanulo” elemeket hivatkozza. A „*” karakter a bármely érték jelölése. Például a /osztaly/* jelöléssel újra a „tanulok” elemekre kaptunk hivatkozást.

Az eddig tárgyal hivatkozások mind XML objektumokat hivatkoztak, de nem ezek értékét. Ahhoz, hogy egy objektum értékéhez hozzáférjünk a text() XPath függvényt kell használnunk. Például: A Kovács András nevű tanuló minden osztályzatának értékét a következő kifejezéssel kaphatjuk meg //tanulo[@nev=’Kovács András’]//osztalyzat/text() . További gyakran használt függvények a névtereket alkalmazó dokumentumok kezeléséhez a local-name() és a namespace-uri(), melyek segítségével az elemek pontos címkéje hivatkozható. Például a //*[local-name()=’elem1’ and namespace-uri()=’http://tempuri.org’] kifejezés minden olyan elemet jelöl, melynek címkéje a http://tempuri.org névtérben definiált elem1.

Az XPath jelölésről bővebben a: http://www.w3.org/TR/xpath/ linken találhatunk leírást.

 

Az XSLT, mint eXtensible Stylesheet Language Transformation, az az eszköz mely segítségével leírhatjuk az XML formátumú dokumentumokon elvégezendő transzformációkat. Ez a transzformáció leíró alkalmas XML-ből XML-be, de XML-ből bármilyen más szöveges formátumba történő transzformáció megadására is.

A transzformációk megadása a dokumentum adott részeihez rendelt template-ekbe rendezett feldolgozási utasítások megadásával történik.

Példa XSLT részlet, csak a template-ekkel:

<xsl:stylesheet version=”1.0″ xmlns:xsl=”http://www.w3.org/1999/XSL/Transform”>

                <xsl:output method=”xml” version=”1.0″ encoding=”UTF-8″ indent=”yes” />

               

                <xsl:template match=”/osztaly”>

                </xsl:template>

               

                <xsl:template match=”tanulo”>

                </xsl:template>

               

                <xsl:template match=”targyak”>

                </xsl:template>

               

                <xsl:template match=”matematika”>

                </xsl:template>

</xsl:stylesheet>

 

Az egyes template-eket XPath kifejezések kötik az általuk feldolgozandó XML objektumokhoz. Minden egyes XPath kifejezést, a hivatkozó template végrehajtásakor aktuális csomópont által kijelölt dokumentum részfán kell értelmezni.

A forrás dokumentum transzformációjakor, valamennyi template végrehajtódik a dokumentum gyökerét, mint aktuális csomópont tekintve. A template-eken belül az aktuális csomópont, a template által hivatkozott csomópont lesz, ha több objektumot hivatkozik a template, akkor ezek egymás után sorban töltik be az aktuális csomópont szerepet.

Látható, hogy az alkalmazott XPath kifejezések között találhatóak abszolút és relatív hivatkozások is, általánosan elmondható, hogy abszolút hivatkozásokkal szigorúan be tudjuk határolni, hogy az adott template mely elemekre legyen érvényes, míg relatív hivatkozásokat használva lehetővé válik templatek egymás általi meghívása, vagy akár rekurzív szintet elérő hívás egymásba ágyazás is.

Mint említettem a transzformált dokumentumra minden template alkalmazásra kerül, de csak a dokumentum gyökerét, mint aktuális csomópontot alkalmazva, ahhoz, hogy a dokumentumban szabadon navigáljunk, template-ből kell meghívnunk további templateket.

Például:

<xsl:template match=”/osztaly”>

                <xsl:apply-templates />

</xsl:template>

               

<xsl:template match=”tanulo”>

</xsl:template>

 

Az előző példában megfigyelhettük, hogy a dokumentum gyökeréből kiindulva, csak egy template alkalmazható, az amelyik a /osztaly XPath kifejezést adta meg, a többi nem illeszkedett a dokumentum adott szintjén. Ahhoz, hogy ezek is kifejtsék hatásukat, az apply-templates utasítást alkalmazhatjuk. Ez az utasítás az aktuális template által hivatkozott XML objektumokat (minden egyesre illeszkedő objektumot egymás után sorban), mint aktuális csomópontot tekintve hívja meg újra az összes template-et. Így már atanulo XPath kifejezést megadó template is kifejti hatását. Természetesen lehetőség van konkrét template meghívására is a call-template utasítással.

Ezek alapján látható, hogy egy XSLT leíró végrehajtása templateről templatere halad, mindig a legutóbb végrehajtott template által hivatkozott objektumokat, mint aktuális csomópontot tekintve (sorban), valamint, hogy minden template tetszőleges sokszor végrehajtódhat, mivel amikor illeszkedik az aktuális csomóponttól kiindulva, akkor végrehajtásra kerül az általa hivatkozott objektumokon. Így a végrehajtás követéséhez, egyszerre kell követnünk a dokumentumban való navigációt és az adott szinten illeszkedő templateket.

A template-ekben az általuk hivatkozott objektumok céldokumentumbeli megfelelőjét írhatjuk le, azaz a transzformáció kiinduló dokumentumában a templatek által hivatkozott objektumok a céldokumentumba a templatekben leírt formában kerülnek be. Mivel ez a feldolgozás igen sokféle lehet, így erről általánosságban nem írok, de a cikksorozat utolsó részében konkrét példán igyekszem jobban bemutatni a transzformációs lehetőségeket.

Az XSLT leírókról bővebben a http://www.w3.org/TR/xslt linken található leírás.

A cikksorozat következő részében a Web Service-ek működésével, használt leíróival, valamint tipikus alkalmazási területeivel foglalkozom.