5. fejezet - XPath

Tartalom

Kifejezések
Útkifejezések
Csomópontszekvenciák összefűzése
Rövidítések
Az XPath 2.0 funkciói kategóriákra osztva

Az XML Path Language (röviden XPath) egy deklaratív, kifejezés alapú lekérdező nyelv, melynek segítségével XML dokumentumokban jelölhetünk ki csomópontokat. W3C ajánlás 1999 óta, eredetileg arra terveztek, hogy az XSLT és egyéb technológiák, például Xpointer használják. Az XPath elsődleges célja egy olyan eszközrendszer definiálása, amelynek segítségével egy XML dokumentum részeit meg lehet címezni. Ez a gyakorlatban azt jelenti, hogy az XPath segítségével lehet címezni, azonosítani, mutatni és meghatározni a helyzetét az XDM-ben látott elemcsomópontoknak, attribútumcsomópontoknak, szövegescsomópontoknak és gyakorlatilag bárminek, ami előfordulhat egy XML dokumentumban. Az dokumentum logika felépítése alapján dolgozik és a csomópontok kijelölésére szolgál. Szűrhetjük az elemeket, attribútumokat különböző feltételek alapján, navigálhatunk a szülők, gyermekek között; sztringeket, számokat, logikai értékeket módosíthatunk. Támogatja a névterek használatát.

A címzési rendszeren túl tartalmaz szöveg, numerikus és logikai értékeket kezelő beépített funkciókat, valamint csomópontok és csomópont szekvenciák is manipulálhatóak. Az XPath nem mond semmit arról, hogy mi történjen az eredménnyel miután azt megkaptuk, ez a XPath-t implementáló rendszer feladata. Az XPath 2.0 2007 óta W3C ajánlás, legutolsó verziója 2010-ben jelent meg. 19 egyszerű típussal rendelkezik és felhasználhatjuk az XSD sémákban létrehozott saját típusokat is. Az XPath 2.0 a szekvenciákra fektette az alapokat. A csomópont-halmazokat szekvenciák váltották fel. Minden kifejezés egy szekvenciát ad vissza. Új operátorokat és rengeteg új függvényt vezettek be. A továbbiakban végig az XPath 2.0-ás verziójával foglalkozunk.

A kifejezések kontextusa

Mielőtt az XPath használatába elmerülnénk, fontos megismerni az egyik legfontosabb tényezőt: a kontextust. Minden kifejezés esetén a környezete meghatározó jelentőséggel bír. A feldolgozás két lépcsőben hajtódik végre:

  1. statikus elemzés:

    a kifejezés (és a statikus környezet) alapján felépül egy műveleti fa, azt normalizálni kell majd a kifejezéshez hozzárendelődik egy statikus típus

  2. dinamikus kiértékelés:

    a műveleti fa, az input adatok (és a dinamikus környezet), meghatározódik a kifejezés értéke és a kifejezéshez hozzárendelődik egy dinamikus típus

Kifejezés környezete: a kifejezés eredményét befolyásoló információkat tartalmazza:

Az XPath feldolgozási modell

A XPath alapvetően az adatmodell és a kifejezés kontextus feldolgozásán alapul, a feldolgozási modellje a következő lépésekből áll:

  1. Az adatmodell generálása:

    • Az XML-elemző Infosetet generál, majd esetleg végbemegy egy validáció (PSVI)

    • Ezt az Infosetet vagy PSVI-t XDM-példánnyá kell transzformálni

  2. Séma import feldolgozás

  3. Kifejezések feldolgozása:

    • statikus elemzés

    • dinamikus kiértékelés

  4. Szerializáció

Ezt a folyamatot az alábbi ábra is szemlélteti:

5.1. ábra - Az XPath feldolgozási modellje

Az XPath feldolgozási modellje


Kifejezések

Az XPath alapja a kifejezés. Kifejezések segítségével azonosíthatjuk egy XML dokumentum adott részeit. Egy kifejezés csak egy adott környezetben értelmezhető, a kifejezés eredménye négyféle típusú lehet: csomópont halmaz, logikai, szöveges vagy numerikus típus.

Kifejezések három csoportra oszthatók. Az egyik csoport az útkifejezések, másik csoport az érték kifejezések, ide tartoznak a sztring és numerikus literálok, változó hivatkozások, függvényhívások, logikai, összehasonlító és aritmetikai kifejezések. A harmadik csoport pedig a csomóponthalmaz kifejezések, melyek két csomóponthalmazt dolgoznak fel.

A sztring literálok egyszeres vagy kétszeres aposztróffal körül vett karakterláncok. A számokat dupla pontosságú lebegőpontos értékként kezeli. A változók szintaktikája: dollárjellel kezdődik ($), amit egy minősített név (QName) követ. A változó típusa lehet bármely XPath által támogatott típus vagy a hivatkozott környezet által támogatott típus. Függvény hívása a függvény nevéből és a neve után zárójelek közötti vesszővel elválasztott argumentumokból áll. A függvények nevei minősített nevek. Minden argumentum egy kifejezés. A visszatérési érték bármely támogatott érték lehet.

Útkifejezések

XPath jelölőrendszere nagyon hasonlít egyes operációs rendszereke fájlrendszer jelöléséhez. A UNIX-hoz hasonlóan perjelet (/) használ az útvonal kifejezésekben a lépések elkülönítésre. Ez a jelölés nagyon hasonlít az URL-eknél használt jelölésekre, az első elem azonosítja az elsődleges erőforrást, az alelemek pedig további erőforrásokat azonosítanak az elsődleges erőforráson belül.

Az XPath-ban a fa navigációja a környezeti csomópontok sorozatával kezdődik. Az XPath navigációs szintaxis:

cs0/lépés

ahol csr (context sequence 0) a környezeti csomópont-szekvenciát jelenti, melyből a navigációs lépést megtesszük. Általános hibának számít a kifejezések esetén az olyan XPath navigációk tesztelése, melyek esetén nincs definiálva környezeti csomópont-szekvencia. Az XPath navigáció tartalmazhat több lépést is. Az első lépés a környezeti csomópontsorozat cs0 pontjából indul és cs1 új csomópontok sorozatába mutat. Cs1 lesz az új csomópont-szekvencia a lépés2 számára és így tovább…

cs0/lépés1/lépés2/...
    ≡
((cs0/step1)/step2)/...
  '-------'
     cs1

A legtöbb kifejezés egy dokumentum részeit lokalizálja. A részeket egy vagy több lokalizáló lépés határozza meg. Relatív út az környezetcsomóponttól van számítva és az abszolút útvonaltól könnyen megkülönböztethető, mert nem perjellel kezdődik. Az abszolút útvonal perjellel kezdődik, és ezt követheti egy relatív útvonal. Egy lokalizáló lépés önmaga pedig három részből áll:

ax :: nt [p1] ... [pN]
  1. tengely (ax):

    navigáció iránya, melyet a környezeti csomópontokból állapítunk meg. A lokalizáló lépés által kiválasztott csomópontok és a környezetcsomópont közötti kapcsolat típusát határozza meg a fában.

  2. csomópont tesztet (nt)

    meghatározza a csomópont típusát és a lokalizáló lépés által kiválasztott csomóponthalmaz nevét.

  3. Opcionális predikátumok (pi)

    tetszőleges kifejezések, mellyel tovább lehet szűrni a csomópontok sorozatát, amelyekhez navigálunk. Ha mind teljesül, akkor lesz kiválasztva a vizsgált csomópont.

Egy lépés eredményül mindig egy csomópont halmazt ad. Végrehajtása során elsőnek előállít egy csomópont halmazt a csomópont teszt és tengely alapján, majd ezeket a predikátumok szerint szűri. A tengely és predikátum elhagyható. A csomópont tesztben nem csak neveket használhatunk, hanem megadhatunk egyéb jelölőket is, például "*". Ekkor minden egyes csomópontot ( a saját hatáskörén belül ) kiválaszt szűrésre.

Tengelyek

XPath kifejezések csomópontok kiválasztásakor számos különböző tengely használhatnak. A tengely meghatározza az csomópontok kiválasztásának irányát a környezetcsomóponthoz viszonyítva. A tengelyek utat mutatnak, segítségükkel bejárhatunk egy XML dokumentumot. Gyakorlatilag bármely csomópontból el lehet jutni bármely csomópontba a dokumentumban a tengelyek használatával. Jelölésük: a tengely neve után ”::” operátor szerepel.

A 13 tengely a következő:

Tengely Leírás Irány Látható csomópont típusok
child:: A környezetcsomópontból közvetlenül leszármazó elemek. Forward Elem, komment, feldolgozó utasítás és szöveg csomópontok
parent:: Közvetlenül a környezetcsomópont feletti elem. Reverse Gyökér, elem csomópontok
descendant:: A child:: tengely kiterjesztése. A környezetcsomópontból leszármazó elemek. Forward Elem, komment, feldolgozó utasítás és szöveg csomópontok
ancestor:: A parent:: tengely kiterjesztése a csomópont fán felfele. Reverse Gyökér, elem csomópontok
descendant-or-self:: Mint a descendant:: tengely, de tartalmazza a környezetcsomópontot. Forward Attribútum és névtér nem lehet.
ancestor-or-self Mint a ancestor:: tengely, de tartalmazza a környezetcsomópontot. Reverse Attribútum és névtér nem lehet.
following:: Minden csomópont, ami a környezetcsomópontot követi, kivétel a leszármazottjai. Forward Gyökér csomópont, attribútum és névtér nem lehet.
preceding:: Minden csomópont, ami a környezetcsomópontot megelőzi, kivétel a felmenői. Reverse Gyökér csomópont, attribútum és névtér nem lehet.
following-sibling:: Minden csomópont, ami a környezetcsomópontot követi és közös a szülőcsomópontja. Forward Gyökér csomópont, attribútum és namespace nem lehet.
preceding-sibling:: Minden csomópont, ami a környezetcsomópontot megelőzi és közös a szülőcsomópontja. Reverse Gyökér csomópont, attribútum és namespace nem lehet.
attribute:: A környezetcsomópont attribútjai. Forward Csak attribútum.
namespace:: A környezetcsomópont névtere. Forward Csak névtér.
self:: A környezetcsomópont. Bármelyik csomópont lehet.

A fenti tengelyeket az alábbi ábra teheti szemléletessé:

5.2. ábra - XPath tengelyek

XPath tengelyek


XPath szemantika:

  • Bármely XPath navigáció által előállított csomópontsorozat dokumentum sorrendű és nem tartalmaz duplikációt.

    (<a b="0"> 
    	<c d="1"><e>f</e></c>
    	<g><h/></g>
    </a>)/child::node()/parent::node()             => ( <a ..> ... </a> )
         /child::node()/following-sibling::node()  => ( <c d="1"><e>f</e></c> ,<g><h/></g> )
  • Az XPath dokumentum sorrendű szemantikát követ.

    (<a><b/><c/></a>,
    <d><e/><f/></d>)/child::node()         => (<b/>,<c/>,<e/>,<f/>)

    Az XPath dokumentum sorrendű szemantika megköveteli, hogy <b/> előbb forduljon elő, mint <c/>, illetve <e/> előbb forduljon elő, mint <f/>. (Természetesen a (<e/>, <f/>, <b/>, <c/>) eredmény is rendben lenne! )

XPath csomópont teszt

Amikor egy XPath lépés a csomópontok egy sorozatához érkezik, csomópont tesztet hajthatunk végre, hogy szűrjük a csomópontokat jellegzetességeik és nevük alapján.

Jellegzetesség teszt Szemantikák
Node() Minden csomópontot elfogadunk.
Text() Csak a szöveg csomópontokat fogadjuk el.
Comment() Csak a megjegyzés csomópontokat fogadjuk el.
Processing-instruction() Csak a feldolgozási utasításokat fogadjuk el.
Processing-instruction(p) Csak a <?p…?> formájú feldolgozási utasítást fogadjuk el.
Document-node() Csak a (láthatatlan) dokumentum gyökér csomópontot fogadjuk el.

XPath név teszt

A csomópont teszt egyben egy név teszt is, mely csak azokat az elem vagy attribútum csomópontokat őrzi meg, melyeknek egyezik a nevük.

Név teszt Szemantikák
name Csak azokat a csomópontokat fogadjuk el, amelyek tag névvel rendelkeznek
* Azokat a csomópontokat fogadjuk el, amelyek tetszőleges tag névvel rendelkeznek

Megjegyzés

Megjegyzés: Általában cs/ax::* részhalmaza cs/ax::Node()-nak.

Predikátumok

Harmadik lépésként a tengely által kiválasztott csomópontok [ p1 ] … [ pN ] predikátumainak listázása történik. Predikátumokat feltételek megadására használjuk a csomópontok kiválasztásánál.

Fontos tudni, hogy az XPath-ban a predikátumoknak magasabb a precedenciája, mint a lépésnek (’/ ’jelnek) Pl.:

cs/step[ p1 ][ p2 ] ≡ cs/((step[ p1 ])[ p2 ])

// A  pi értékek balról jobbra sorrendben értékelődnek ki.
// A  pi-ben, az aktuális környezeti csomópont elérhető ’.’ jelként.
// Az aktuális környezeti csomóponton azon predikátumokat értjük, melyek alkalmazhatók tetszőleges elemek sorozatára.

Több predikátum esetén logika( or, and, not ), illetve összehasonlító operátorokat(<, >, =, !=) is használhatunk.

/persons/person[@id or number]

// ha egy predikátumban nevet adunk meg operátorok, függvények nélkül, akkor annak a létezést vizsgálja

Továbbá a predikátumok tetszőleges mélységig egymásba ágyazhatóak.

/shop/items/item[price<2000 and stock[@available=true()]]

// Azokat az árukat szeretnénk megkapni, amelyeknek az ára kevesebb mint 2000 Ft és elérhető a raktárról

Atomizáció

Az atomizáció az ( x1, …, xN ) elemsorozatot ( v1,.., vN ) atomi értékekké alakítja át:

  1. ha xi atomi érték, vi ≡ xi

  2. ha xi csomópont, vi xi típusos értéke

Az atomizáció lehet implicit:

(<a>                                        (<b>42</b>,
    <b>42</b>                                <c><d>42</d></c>,
    <c><d>42</d></c>                    =>   <d>42</d>
    <e>43</e>                                )
</a>)/descendant-or-self::*[. eq 42]

Illetve explicit:

(<a>
<b>42</b>
<c><d>42</d></c>
<e>43</e>
</a>)/descendant-or-self::*[data(.) cast as double eq 42 cast as double]

Pozicionális hozzáférés

A [p] predikátumon belül az érvényes környezeti elem a ’.’ kifejezéssel érhető el:

  • Egy kifejezés elérheti a ’.’ pozíciót a környezeti sorozatban a position() függvény segítségével. Az első elem az 1-es pozíción található.

  • Továbbá, a legutolsó környezeti elem pozíciója elérhető a last() segítségével.

(x1, x2,...,xn )[position() eq i] => xi
(x1, x2,...,xn )[position() eq last()] => xn

A [position() eq i] alak predikátuma i-vel bármely XQuery numerikus kifejezés esetén, rövidíthető [i]-vel.

A precedencia szabályaira pedig a továbbiakban is fontos figyelni, mert az alábbi példa érdekes meglepetéseket hozhat:

// a predikátum ([]) erősebben köt, mint a lépés (/)
// viszont csak azok után értékelődnek ki!
(cs/descendant-or-self::node()/child::x)[2]
vs.
cs/descendant-or-self::node()/child::x[2]

A környezeti elem: .

Az XPath egyik hasznos általánosítása, hogy az aktuális környezeti elem (’.’) nem csak predikátumok esetén érhető el, hanem minden lépésben. Azaz egy cs/e kifejezésben az ’e’ kifejezés a környezeti szekvenciának/sorozatnak megfelelően fogja a ’.’ környezeti elemet kiértékelni. Eredményként pedig a kiértékelt sorozatot kapjuk vissza.

Megjegyzés: ha 'e' csomópontokat (e node* típusú) ad vissza, a kiértékelt sorozat dokumentum sorrendben lesz, továbbá ismétlődések nélkül.

(<a>1</a>,<b>2</b>,<c>3</c>)/(. + 42) => (43.0,44.0,45.0)
(<a>1</a>,<b>2</b>,<c>3</c>)/name(.)  => ("a","b","c")
(<a>1</a>,<b>2</b>,<c>3</c>)/position() => (1,2,3)
(<a><b/></a>)/(./child::b, .)           => (<a><b/></a>,<b/>)

Csomópontszekvenciák összefűzése

Az XPath három operátort biztosít a szekvenciák kombinációjára: union (rövidítve |), intersect és except. Ezek az operátorok eltávolítják a duplikált csomópontokat az identitásuk alapján és az eredményt mindig dokumentum sorrendben szolgáltatják vissza. Megjegyzés: Ezeket a kifejezéseket azért az XPath környezetben nézzük, mert több hasznos kifejezés is ezekre az operátorokra épül.

Minden x gyermek és attribútum kiválasztása a környezeti csomópontból
cs/(./child::x | ./attribute::x)

Minden testvér kiválasztása a környezeti csomópontból
cs/(./preceding-sibling::node() | ./following-sibling::node())
vagy
cs/(./parent::node()/child::node() except .)

Környezeti csomópont kiválasztása minden testvérrel együtt
cs/(./parent::node()/child::node() | . )

Első közös ős (fca)
(cs0/ancestor::* intersect cs1/ancestor::*)[last()]

Rövidítések

5.1. táblázat - XPath rövidítések

RövidítésTeljes alak
ntchild::nt
@attribute::
..parent::node()
///descendant-or-self::node()/
/root(.)
lépés./lépés


Példák:

a/b/c => ./child::a/child::b/child::c
a//@id => ./child::a/descendant-or-self::node()/attribute::id
//a => root(.)/descendant-or-self::node()/child::a
a/text() => ./child::a/child::text()

Az XPath 2.0 funkciói kategóriákra osztva

  • Hozzáférhetőségi funkciók: Ezek hozzáférést biztosítanak ahhoz hogy privát módon érhessük el az adatot, egy funkció amely engedélyezi hogy privát módon lekérdezzük és állítsuk be a tulajdonságainak értékét, anélkül hogy közvetlen hozzáférést biztosítana a tulajdonságokat tartalmazó objektumhoz. Egy csak olvasható tulajdonságnak csak egy ilyen függvénye létezik, ami engedélyezi a tulajdonság értékének a lekérdezését.

    • fn:node-name(node) – Csomópont neve

    • fn:string – Visszaadja a csomópont értékét sztringként.

    • fn:data(item [, item,…]) – Szekvenciává alakítja az elemeket,

  • Hibák és nyomkövetés: Hibák kiváltása, és megoldása futás közbeni nyomkövetés segítségével.

    • fn:error(error, description, object) – Kivált egy kivételt.

  • Konstruktorok: Ezek állítják elő az objektum példányokat egy osztályból, vagy definiálnak egy típust.

    • xs:date(), xs:string(), xs:Name(), xs:token()

  • Numerikus függvények: Mint bármely programozási nyelvben, egy numerikus függvény végez valamilyen konverziót illetve kalkulációt, amely után egy számot ad eredményül. Számos numerikus operátor elérhető az XPath használata közben. Rengeteg ezek közül úgy mint a „numeric-add”, elérhető a megszokottabb szimbolikus használati formája is(+).

    • fn:round(num) - Kerekítő függvény.

    • fn:abs(num) – Abszolút érték függvény.

    • fn:number(arg) – Sztringből numerikus típussá konvertál.

  • Szöveges függvények: A műveletek általában szövegen hajtják végre, és legtöbbször ugyanilyen típusú a visszatérési érték is, de nem minden esetben.

    • fn:concat(string [, string..]) – Összefűzi a sztringeket.

    • fn:string-length([ | string]) – A sztring hossza, vagy ha nincs megadva paraméter akkor az aktuális csomóponté.

    • fn:starts-with(string1, string2)/ fn:ends-with(string1, string2)

    • fn:contains(string1, string2) – Tartalmazza e az adott zstringet.

    • fn:replace(string, pattern, replace) – Lecseréli a sztringben az előfordulásokat.

  • URI függvények: URI-kat dolgoznak fel, illetve módosítanak. Az egyetlen függvény ebben a szekcióban:

    • fn:resolve-uri(relative, base) – Feloldja a relatív URI-kat abszolúttá.

  • Boolean függvények

    • fn:boolean(arg) – Sztring, numerikus illetve csomópont értékek boolean értéke.

    • fn:not(arg) – A boolean függvény inverze.

  • Idő és dátum funkciók

    • fn:dateTime(date, time) – Egy TimeStamp típusú objektumot ad vissza.

    • fn:year-from-date(date) – Az adott dátumtól számított időtartam években. Hasonló formában létezik hónapokra, napokra is.

    • fn:hours-from-time(time) - Az adott időponttól számított időtartam órákban. Hasonló formában létezik percekre, másodpercekre is.

    • fn:adjust-dateTime-to-timezone(datetime, timezone) – Egy timestamp objektumot adott időzónának megfelelőre konvertál.

      • Léteznek dátumok összegzését, kivonását, hasonlítását szolgáló függvények is.

  • QName funkciók: (Qualified Name) A QName egy korlátozott név. Egy QName tartalmaz egy névtér URI-t. A QName egy opcionális előtag és egy kettőspont után következik a „helyi” név vagy egy URI és a lokális vagy attribútum név.

    • fn:QName() – Visszadja a QName értékét az adott csomópontnak.

    • fn:local-name-from-QName() – A lokális nevet adja vissza a QName attribútumból.

    • fn:namespace-uri-from-QName() – Névtérrel és URI-val tér vissza.

  • Csomópont függvények

    • fn:name([nodeset]) – Az aktuális csomópont neve, vagy a csomópont kollekció első eleme.

    • fn:root([node]) – Visszaadja a gyökér elemet.

    • op:is-same-node – Igazat ad vissza, ha a két csomópont egyenlő.

  • Szekvencia funkciók: A szekvencia ténylegesen egy lista a nem létező vagy még lehetségesen ismétlődő elemek egy szülő csomóponton belül. A szekvencia ennek következtében egy kollekció. Szekvencia függvények alkalmazhatóak egy egyszerű kollekcióra teljes egészében, vagy a kollekció valamely tagjára.

    • fn:count(collection) - Kollekció elemeinek száma

    • fn:max(collection) - Kollekció elemeinek maximuma

    • fn:avg(collection) – Kollekció elemeinek átlaga

    • fn:empty(collection) – Igazat ad vissza ha üres a kollekció.

    • fn:exists(collection) – Nem üres kollekciókra igazat ad.

  • Tartalmi funkciók: Ezek a funkciók a jelentésekkel dolgoznak, így a meta adatokat dolgozzák fel

    • fn:last() – Megtalálja az utolsó elemet a kollekcióban.

    • fn:current-date()/fn:current-time() – Aktuális dátum illetve időpont.

    • fn:implicit-timezone() – Megtalálja az időzónára vonatkozó értéket.

  • Egyéb típusú függvények: 64bites számokon alapuló operátorok, XML jelölésekre vonatkozó függvények és operátorok. Az XML jelölések(notation) egy formája az XML-nek, amely dialektus specifikus, és nagyon speciális alkalmazásokhoz lett készítve XML-ben úgy, mint a MathXML, CML. A speciális XML dialektus jelölések szabványokat is fektetnek le, és a regionális szemantikát alkalmazzák az egyébként általános XML adathoz.