XML

XML schema definition



Bevezetés

Az előző részében már megismerkedtünk az érvényes XML dokumentumok létrehozásának egyik módjával, mégpedig a DTD-kkel. Most ismerkedjünk meg az érvényes XML dokumentumok létrehozásának másik vagy másodlagos módszerével, az XSD-vel.
A másodlagos jelző egyfajta használati vagy akár keletkezési sorrendet akar szimbolizálni, mivel az érvényes XML dokumentumok létrehozásának eredeti és talán elterjedtebb módja a DTD-k használata, melyet az XML specifikáció is magába foglal.

Az egyik legfontosabb eltérés DTD-kkel szemben a deklaráció elhelyezésénél lép fel, mivel a DTDket deklarálhattuk az XML dokumentumon belül, vagy akár kívül egy külső fájlban, amelyet egy hivatkozás segítségével linkeltünk be. Az XML-sémáknál ez nem így van. Az XML-séma definíció, csakis kizárólag egy külső fájlban lehet, amelyet nem linkelünk be az XML dokumentumba. Ahhoz hogy tudja az alkalmazásunk, hogy melyik sémával vesse össze az XML-dokumentumot, az XML-séma szerinti érvényesség ellenőrző szkripttel adhatjuk meg:

HTML>
<HEAD><TITLE>Érvényesség-ellenorzo (Sema)</TITLE>

<SCRIPT LANGUAGE="JavaScript">

function XML_SEMA_ellenor(dok_URL, sema_URL, nevter_neve)
{
  var XMLDocument = new ActiveXObject("Msxml2.DOMDocument.4.0"),
      XMLSemaCache = new ActiveXObject("Msxml2.XMLSchemaCache.4.0");


  XMLSemaCache.add(nevter_neve, sema_URL);

  XMLDocument.schemas = XMLSemaCache;
  XMLDocument.async = false;
  XMLDocument.load(dok_URL);


  if(XMLDocument.parseError.errorCode != 0)
    {
    var msg;
    msg = "Hibaszám: "    + XMLDocument.parseError.errorCode + "\n"
        + "fájlpozíció: "  + XMLDocument.parseError.filepos  + "\n"
        + "sor: "          + XMLDocument.parseError.line      + "\n"
        + "karakter: "      + XMLDocument.parseError.linepos  + "\n"
        + "leírás: "        + XMLDocument.parseError.reason    + "\n"
        + "forrás szöveg: " + XMLDocument.parseError.srcText  + "\n"
        + "URL: "          + XMLDocument.parseError.url;       

    return alert(msg);
    }else alert("OK");
}
</SCRIPT>

</HEAD>
<BODY onLoad="XML_SEMA_ellenor('Leltar Elofordulas.xml', 'Leltar Sema.xsd', '')">

<H2>Sémát használó érvényesség-ellenorzo</H2>

</BODY>
</HTML>

 Magyarázat:

A HTML dokumentum betöltődése (BODY onLoad) után meghívódik a XML_SEMA_ellenor(dok_URL, sema_URL, nevter_neve) függvényünk a következő paraméterekkel:

·        dok_URL - az ellenőrizni kívánt XML dokumentum URL-je

·        sema_URL - az XML-séma URL-je, amely szerint ellenőrizni szeretnénk az XML dokumentumot

·        nevter_neve - az ellenőrizni kívánt XML dokumentum dokumentumelem névterének neve

A függvényben létrehozunk két ActiveX objektumot, az XMLDocument-ot, amely az XML dokumentum betöltését fogja végezni és a XMLSemaCache-t, amely az XML-séma betöltését fogja végezni. Ezután betöltjük az XML-sémát a XMLSemaCache objektum add metódusával, melynek paraméteréül átadjuk az ellenőrizni kívánt XML dokumentum dokumentumelem névterének nevét (vagy üres sztringet, ha nem tartozik semmilyen névtérhez) és az XML-séma URL-jét. Végezetül a séma objektumot (XMLSemaCache) hozzárendeljük a dokumentum objektumhoz (XMLDocument) és szinkron módon (addig nem fut tovább a program, míg az egész dokumentum be nem töltődik) betöltjük az XML dokumentumot (XMLDocument.load(dok_URL)).

XML-séma létrehozása

Az XML sémadefiníciót egy külön fájlban kell létrehozni, amelyre ugyanazon jólformázottsági szabályok vonatkoznak, mint egy XML dokumentumra, melyeket pár kiegészítés követ: (a séma egy XML dokumentum, a séma egyik nagy előnye a DTD-vel szemben, hogy egy XML dokumentum, nem kell hozzá más szintaxist feldolgozó elemzőt írni)

·        egyetlen legfelső szintű elemet tartalmazhat a schema-t

·        az összes sémában használt elemnek és jellemzőnek az "http://www.w3.org/2001/XMLSchema" névtérhez kell tartozni, ezzel is jelezve, hogy XML-sémáról van szó

Egyszerű elemtípusok deklarációja:

Az XML-sémában az elemeket az element elemmel tudjuk deklarálni, melyen belül mindenképpen fel kell tüntetnünk az elem nevét.

Amennyiben egyszerű típusú elemet (nem tartalmaz gyermekelemeket) deklarálunk nem származtatott tartalom-típussal, úgy magát az elem (tartalom) típust is az element elemen belül kell megadni.

Példa:

<xsd:element name="NEV" type="xsd:string"/>
<xsd:element name="DATUM" type="xsd:gYear"/>

A példánkban két egyszerű típusú elemet deklaráltunk (NEV, DATUM), melyek típusmeghatározásánál az XML-séma alaptípusait használtuk fel. Az XML-séma egyszerű típusai közül néhány: Az XML-séma által támogatott egyszerű típusok teljes listája megtalálható a http://www.w3.org/TR/xmlschema-0/#CreatDt címen. Ezen típusok úgynevezett alaptípusok, amelyekből lehetőség van saját típus létrehozására úgy, hogy az egyes alaptípusokból egy saját típust származtatunk. Vegyük alapul a fenti példánkból a DATUM elemet. A gYear típus használatával ugyan biztosítva van, hogy a DATUM elem biztosan megfelelő formátumú évet fog tartalmazni, viszont mi tudjuk, hogy csak 1954 és 2003 közötti évekre van szükségünk. Nincs más teendőnk, minthogy lekorlátozzuk a gYear típust:

·        string - bármilyen érvényes karakter

·        integer - <-126789, 126789> intervallumból bármilyen egész szám, vagy nulla. Pl. (-100, 0, 15)

·        positiveInteger - <1, 126789> intervallumból bármilyen egész szám. Pl. (2, 50, 999)

·        negativeInteger - <-126789, -1> intervallumból bármilyen egész szám. Pl. (-25, -559, -78902)

·        nonNegativeInteger - <0, 126789> intervallumból bármilyen egész szám. Pl. (0, 50, 98745)

·        nonPositiveInteger - <-126789, 0> intervallumból bármilyen egész szám. Pl. (0, -50, -98745)

·        decimal - pozitív illetve negatív tizedes szám

·        time - idő a következő formátumban: óó:pp:mm[.mm+-UTC], Pl. (14:30:00, 16:30:00.0, 16:30:00-01:00, 16:30:00.00-01:00)

·        dateTime - dátum és idő a következő formátumban: éééé-hh-nnTóó:pp:mm.mm+-UTC. Pl. (2004-03-15T15:30:00.0-01:00)

·        gYear - év a következő formátumban: éééé. Pl. (2004, 1983)

·        gMonth - hónap a következő formátumban: --hh--. Pl. (--03--, --12--) -> (március, december)

·        gDay - nap a következő formátumban: ---nn. Pl. (---01, ---23)

·        gYearMonth - év és hónap a következő formátumban: éééé-hh. Pl. (1983-02)

Az XML-séma által támogatott egyszerű típusok teljes listája megtalálható a http://www.w3.org/TR/xmlschema-0/#CreatDt címen. Ezen típusok úgynevezett alaptípusok, amelyekből lehetőség van saját típus létrehozására úgy, hogy az egyes alaptípusokból egy saját típust származtatunk. Vegyük alapul a fenti példánkból a DATUM elemet. A gYear típus használatával ugyan biztosítva van, hogy a DATUM elem biztosan megfelelő formátumú évet fog tartalmazni, viszont mi tudjuk, hogy csak 1954 és 2003 közötti évekre van szükségünk. Nincs más teendőnk, minthogy lekorlátozzuk a gYear típust:

<xsd:element name="DATUM">             

  <xsd:simpleType>                   

    <xsd:restriction base="xsd:gYear">

      <xsd:minInclusive value="1954"/>

      <xsd:maxInclusive value="2003"/>

    </xsd:restriction>               

  </xsd:simpleType>                 

</xsd:element>

Ahogy az a definíciórészletből is kiderül a típusszármaztatás a restriction elem segítségével történik amely a simpleType gyermekeleme, egyszerű típusról lévén szó. A restriction elem base jellemzőjének adjuk meg azt a típust, amelyből származtatni szeretnénk a saját típusunkat. A restriction elem gyermekelemeiként megadhatjuk az új típusra vonatkozó megszorításokat. Jelen esetben ezek a megszorítások a minimális (minInclusive) és maximális (maxInclusive) érték meghatározása. Ezen kívül használhatnánk még:

·         reguláris kifejezést(pattern) - segítségével egy olyan sablont hozhatunk létre, amellyel pontosan leírhatjuk egy karaktersorozatban használható karakterek listáját illetve sorrendjét. Pl.:

<xsd:simpleType name="szemelyiSzamTipus">             

  <xsd:restriction base="xsd:string">   

    <xsd:pattern value="[A-Z]{2} \d{6}"/>

  </xsd:restriction>                   

</xsd:simpleType>   

 

<!-- megfelelő típusok pl. ("SP 225588", "KC 147896", ...) -->

·          felsorolást (enumeration) - melynél egy előre definiált lista elemei közül választhatunk egyet. Pl.:

<xsd:simpleType name="nemTipus">

  <xsd:restriction base="xsd:string">

    <xsd:enumeration value="férfi" />

    <xsd:enumeration value="nő" />

  </xsd:restriction>

</xsd:simpleType>

 

<!-- megfelelő típusok ("ferfi", "nő") -->

·        minimális érték (minInclusive) meghatározását - lásd a használatát feljebb

·        maximális érték (maxInclusive) meghatározását - lásd a használatát feljebb

Gondolom mindenkinek feltűnt, hogy másként vannak definiálva a lista példaprogramjaiban található típus-származtatások és a fejezet első példaprogramjában található típus-származtatása. Mindkét megoldás helyes, az első példaprogramban névtelen típust hoztunk létre, míg a többiben nevesítettet. Működésileg semmi különbség sincs a két megoldás között. Ha nevesített típust hozunk létre, akkor azt a típust az egész sémában használhatjuk mint új típus (egyszerűen a típushoz a mi új származtatott típusunk nevét írjuk).

Összetett elemtípusok deklarációja:

Összetett típusúnak nevezzük azon elemeket, melyek gyermekelemeket, jellemzőket, vagy karakteres adatokat és gyermekelemeket is tartalmaznak egyidejűleg. Amennyiben összetett típusú elemeket szeretnénk használni, a következő lehetőségek közül választhatunk:

·         általános összetett típus (anyType) használata esetén az elem tartalmazhat bármilyen jellemzőt, elemet és karakteres adatot

<xsd:element name="BARMITARTALOM" type="anyType" minOccurs="0" maxOccurs="unbounded"/>

·         saját összetett típus létrehozása akár névtelenül, akár nevesített módon (névtelen és nevesített típusok definícióját lásd feljebb)

Összetett típusokat hasonló módon hozhatunk létre, mint az egyszerű típusokat. Az egyes gyermekelemek a complexType elemen belül deklarált sequence, choice vagy all gyermekeiként adjuk meg, attól függően, hogy:

·         felsorolást szeretnénk kötött elemsorrenddel (sequence):

<xsd:complexType name="vilagbajnokTipus">

  <xsd:sequence>

    <xsd:element name="EV" type="xsd:gYear"/>

    <xsd:element name="NEV" type="xsd:string"/>

    <xsd:element name="NEMZETISEG" type="xsd:string"/>

  </xsd:sequence>

</xsd:complexType>

·         választólistát szeretnénk(choice):

<xsd:complexType name="emberTipus">

  <xsd:choice>

    <xsd:element name="GYEREK" type="xsd:string"/>

    <xsd:element name="FIATAL" type="xsd:string"/>

    <xsd:element name="FELNŐTT" type="xsd:string"/>

  </xsd:sequence>

</xsd:complexType>

·         felsorolást szeretnénk kötetlen elemsorrenddel (all):

<xsd:complexType name="f1vilagbajnokTipus">

  <xsd:all>

    <xsd:element name="EV" type="xsd:gYear"/>

    <xsd:element name="NEV" type="xsd:string"/>

    <xsd:element name="NEMZETISEG" type="xsd:string"/>

  </xsd:all>

</xsd:complexType>

Amint azt a DTD-k használatánál már láttuk az XML-sémánál is lehetséges az egyes felsorolás típusok összeolvasztása, amennyiben megfelelünk néhány szabálynak:

·        all típusú felsorolásba nem olvasztható be sem sequence sem pedig choice típusú felsorolás

·        sequence és choice típus összeolvasztható

·        sem a sequence sem a choice felsorolásba nem olvasztható all típusú felsorolás

Üres elem létrehozásánál hasonlóan járunk el, mint egy összetett típusú elem deklarálásánál, azzal a különbséggel, hogy nem deklarálunk gyermekelemeket, tehát a complexType elemnek nem lesznek element típusú gyermekelemei.

Vegyes elemet szintén összetett típusúnak kell deklarálni, mivel tartalmaz gyermekelemet és szöveges tartalmat is egyben. A complexType elem mixed jellemzőjének igazra állításával jelezzük, hogy vegyes elemet szeretnénk deklarálni.

Példa:

<xsd:element name="COMMENT">

  <xsd:complexType mixed="true">

    <xsd:sequence minOccurs="0" maxOccurs="unbounded">

      <xsd:element name="BR">

        <xsd:complexType>

        </xsd:complexType>

      </xsd:element>

    </xsd:sequence>

  </xsd:complexType>

</xsd:element>

Jellemzők deklarálása:

Ahhoz, hogy egy elem tartalmazhasson jellemzőket összetett típusúnak kell lennie. Az egyes jellemzőket a complexType gyermekelemeiként deklaráljuk. Az egyes jellemzők csakis kizárólag egyszerű típusúak lehetnek, tehát vagy az alaptípusok egyikét használjuk, vagy származtatunk egy új típust. A származtatás és létrehozás nagyban hasonlít az egyszerű típusú elemek létrehozásához.

Példa:

<xsd:element name="BEKEZDES">
  <xsd:complexType>
    <xsd:attribute name="ALIGN" type="xsd:string" default="left" />
  </xsd:complexType>
</xsd:element>

Az egyes jellemző deklarációk a következő jellemzőket támogatják:

·        default - alapérték, amelyet felvesz a jellemző akkor, ha nem adunk meg neki értéket

·         fixed - értékéül megadhatjuk azt az értéket, amelyet mindenképpen fel kell venni a jellemzőnek, tehát ha nem adunk meg értéket, akkor a fixedben megadott értéket veszi fel a jellemző, viszont, ha megadunk értéket akkor csakis kizárólag a fixedben megadott értéket adhatjuk.

·        use - értékéül megadhatjuk:

o       optional - a jellemző elhagyható, ami egyben az alapérték is

o       prohibited - a jellemző le van tiltva, olyan mintha nem is deklaráltuk volna

o       required - a jellemző használata kötelező


Nem látható karakterek kezelése (white space handling):

Az XML dokumentumok írásakor általános gyakorlat lehet, hogy a dokumentumokban (a dokumentumok jobb olvashatósága érdekében) nem látható karakterekkel tagoljuk a dokumentumot. A dokumentum készítésekor „két féle” nem látható karakter csoporttal kell számolnunk: azokkal a nem látható karakterekkel, amelyek az XML dokumentum szerkezetét teszik szemmel láthatóvá, és mint ilyenek nem relevánsak az elkészítendő (cél)dokumentum szempontjából, és azokkal, amelyek részei a „tiszta dokumentumnak” (ezek legtöbbször program forráskódok, vagy irodalmi alkotások esetében különösen fontos szerepet játszanak).

Világos, hogy a dokumentumelemen (gyökérelem) kívüli nem látható karakterek nem játszanak szerepet (hacsak azok nem a az XML specifikáció által egy-egy szerkezetleíró deklarációban kötelezően előírt karakterek), ezért az ilyenek szűrhetők. A gyökérelemen belül előforduló nem látható karakterekről (mindegyikről külön-külön) azonban az XML processzornak tudnia kell, hogy ez csak az XML dokumentum szemmel érzékelhető szerkezeti tagoltságát szolgálja, vagy része a (cél)dokumentumnak. Egy XML processzornak minden nem szerkezetleíró karaktert tovább kell adnia az alkalmazói programnak. Melyik nem látható karakter szerkezetleíró, és melyik nem?    

A dokumentum érvényességét ellenőrző XML processzor könnyű helyzetben van az által, hogy az XML specifikáció definiál egy attribútum nevet xml:space, amely attribútum használatával ez a kérdés a dokumentumelem típus kivételével elemtípusról elemtípusra megválaszolható. Egészen pontosan, ha egy elemtípus ezt az attribútumot deklarálja, és a típushoz tartozó előfordulás ehhez az attribútumhoz értéket rendel (vagy az attribútum deklarációjában megadott alapértékkel rendelkezik), akkor ez az érték kiterjed (öröklődik) minden beágyazott elemtípus előfordulásra is, hacsak a beágyazott elem nem ad új értéket ennek az attribútumnak. VIGYÁZAT! Csak az attribútum érték öröklődik. Ha egy beágyazott elem meg akarja változtatni az örökölt értéket, akkor a megfelelő elemtípusnak ezt az attribútumot deklarálnia kell.

Az xml:space nevű attribútumot felsorolás típusúnak kell deklarálni, ahol a szóba jöhető értékek a default és a preserved. A ’default’ azt jelenti, hogy az alkalmazás úgy köteles kezelni a dokumentumban fellelhető nem látható karaktereket, mint ahogyan azt általában teszi. A ’preserved’ érték azt közli az alkalmazással, hogy az elemeken belüli nem látható karaktereket meg kell tartania. Bármely dokumentum gyökérelemét úgy kell tekinteni, hogy rá semmiféle kezelési eljárás nincs előírva a nem látható karakterek kezelését illetően, hacsak az elem nem deklarálja, és nem ad értéket ennek az attribútumnak.

Még mindig a nem látható karaktereknél maradva, a különböző gépi reprezentációkban az új sorok nyitását általában a #xD és a #xA karakterentitásokból álló legfeljebb két karakter hosszúságú karakterlánccal ábrázolják (jelzik: #xA, #xD, #xAD, #xDA). Az XML specifikáció előírja, hogy az ilyen karakterláncok bármelyikét az XML dokumentumokban a #xA (UNIX stílusú sorvég karakter) karakterentitással kell helyettesíteni. Ezt a helyettesítést minden XML processzor az xml:space attribútum értékétől függetlenül elvégzi.      

Létezik egy másik (a fentihez analóg módon) különlegesen kezelt (az attribútum értékének örökletességét is beleértve) attribútum név: xml:lang, amely a dokumentum nyelvét (magyar, angol, német, stb.) specifikálja. Ennek az attribútumnak a lehetséges értékeit az IETFRFC 1766 (Tags for the identification of languages) definiálja. Ezek az értékek egy, az ISO 639 szabvány szerinti két karakteres nyelvi kódból, és egy az ISO 3166 által definiált országkódból állnak, és az attribútum NMTOKEN típusú (az attribútum lehetséges értéke pl.: ’en-GB’).


Programozói felületek és modellek

Az XML a benne megfogalmazott dokumentumok feldolgozása (vagy éppen programmal történő generálása és módosítása) érdekében programozói felületeket, API-ket (Application Processing Interface) biztosít. A két leginkább említésre méltó ilyen felület a meglehetősen alacsony szintű, esemény-orientált SAX (Simple API for XML), amelyet egy XML-DEV nevű alapvetően XML processzor felhasználókból és fejlesztőkből álló ún. „open discussion group” fejlesztett ki, és a W3C által definiált és szabványosított DOM (Document Object Model). Az utóbbi az XML dokumentumnak egy objektum-orientált faszerkezetét állítja elő, és ebből kifolyólag a dokumentumokon tartalmi kritériumoknak megfelelő feldolgozást is lehetővé tesz. A DOM implementációi természetesen a SAX-ra épülnek.