XPath nyelv
-----------
Egy XPath kifejezés tulajdonképpen egy helymeghatározó útvonal, vagyis egy elérési út.
Az XPath kifejezés eredménye egy szekvencia, amelynek elemei nem feltétlenül azonos típusúak.
A szekvencia elemei lehetnek csomópontok, attribútumok, vagy egyszerű típusú adatok (pl. szöveg).
A köztes lépésekben is mindig szekvenciákat kapunk, és ezekre alkalmazzuk a további kifejezéseket.
Az XPath kifejezés kiértékelése a dokumentum egy adott pontján kezdődik, amit szokás kontextus-
csomópontnak nevezni. A gyökércsomópontból induló helymeghatározó útvonalakat abszolút utaknak hívjuk,
a máshonnan indulókat relatív utaknak.
Az XPath kifejezések építőkövei a lokációs lépések (location step).
Egy-egy lokációs lépés egy tengelyből (axis), egy csúcs ellenőrzésből (node test) és egy
opcionális predikátumból áll. A tengely egy csomópont halmazt ad eredményül, ami üres is lehet.
A csúcs ellenőrzés a fenti csomóponthalmazt szűri meg, amit a predikátumok alkalmazásával
tovább szűrhetünk. A tengely és csúcs teszt megadása kötelező, a predikátumok opcionálisak.
Az axisok lehetnek:
attribute, self, parent, child, ancestor, ancestor-or-self, descendant, descendant-or-self
following-sibling, preceding-sibling, following, preceding.
following -> a dokumentumban a kontextuscsomópont után elhelyezkedő csomópontokat tartalmazza,
de nem tartalmazza a leszármazott csomópontokat.
preceding -> a dokumentumban a kontextuscsomópont előtt elhelyezkedő csomópontokat tartalmazza,
de nem tartalmazza a felmenő (ős) csomópontokat.
Példa: (a példák alapjául szolgáló XML dokumentum az xml_dok_pelda.txt fájlban található)
Adjuk meg a Kis Virag által kölcsönzött ABBA CD-t követő tengely (following::) elemeit.
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzo[@nev="Kis Virag"]//CD[@eloado="ABBA"]/following::*').getstringval()
FROM kolcsonzes k;
Az eredményben benne lesz a következő CD (Zorán), valamint annak minden leszármazottja, és a későbbi
kölcsönző (Nagy Pal), valamint annak minden leszármazottja. Az ABBA CD leszármazott csomópontjai
viszont nincsenek benne az eredményben!
Adjuk meg a Gipsz Jakab által kölcsönzött Tuskevar Konyv-et megelőző tengely (preceding::) elemeit.
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzo[@nev="Gipsz Jakab"]//Konyv[@cim="Tuskevar"]/preceding::*').getstringval()
FROM kolcsonzes k;
Az eredményben csak a megelőző Könyv (Momo) lesz benne, valamint annak leszármazottja. A felmenő csomópontok
nem lesznek benne az eredményben!
A lokációs lépések "egymásba fűzésével" lokációs ösvények (locations paths) készíthetők.
Példa: ... child::Kolcsonzo[position()=1]/descendant::DVD[@ar=4000]
axis -> child::, node test -> Kolcsonzo, predicate -> [position()=1]
axis -> descedant::, node test -> DVD, predicate -> [@ar=4000]
Rövidítések:
Tengelyek mindig szerepelnek a lokációs lépésekben. Ha nem írjuk oda a tengelyt, akkor a child tengely
van implicit módon odaértve. A tengelyek rövidített szintaxissal is használhatók.
@ : attribute
. : self
.. : parent
// : descendant-or-self
Szemantika
----------
axis::csúcs[predikátum1][predikátum2]...[predikátumn]
A kiértékelési szemantika a következő. Minden lépésben adott a számunkra egy szekvencia.
(Kezdetben a teljes dokumentumból álló 1 elemű szekvencia.) Ezen a szekvencián megyünk végig,
és mindig van egy aktuális elemünk (kontextuscsomópont). Erre alkalmazzuk a lokációs lépést
a következőképpen:
Vesszük az aktuális csúcs vizsgálandó tengelyén lévő olyan csomópontokat, amelyek megfelelnek a
csúcs ellenőrzésnek, vagyis a cimkéjük az, hogy 'csúcs', majd egymás után alkalmazzuk rájuk
a predikátumokat, és csak azok maradnak meg, amelyekre mindegyik igaz lesz. Az eredmény ismét
egy szekvencia lesz, amire majd alkalmazzuk a következő lokációs lépést.
Az egymásba ágyazott listákat kisimítva kell értemezni, pl.
( (1,2,3), 4, 5) -> (1,2,3,4,5)
Predikátumok
------------
[felt or felt] [felt and felt] [not(felt)]
A feltételben tesztelni lehet
attribútum értékét vagy létezését -> [@att="..."], [@att]
csomópont tartalmát -> [text()="..."]
gyermek csomópont tartalmát vagy létezését -> [Csnev="..."], [Csnev]
függvények eredményét vagy igaz/hamis voltát [count(*)=2], [last()] -> [position()=last()] rövidítése
útkifejezések eredményét vagy létezését [//Csnev="..."], [//Csnev]
... lényegében bármit, aminek logikai értéke van. A +1 visszatérési érték is igaznak minősül.
Vigyázat! A predikátumokban szereplő útkifejezések nem a kontextuscsomóponttól relatívan értendők.
Vagyis ha az érdekel, hogy kik kölcsönöztek CD-t, akkor az alább a helyes megoldás.
(A predikátimon belül a '.' nem hagyható el.)
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzo[.//CD]/@nev') FROM kolcsonzes k;
Függvények prototípusa (amiket az Oracle10g-ben megvalósítottak)
----------------------
number count(node-set) - megszámolja a csomópontokat
number sum(node-set) - összeadja az értékeket
node-set id(object) - elemek kiválasztása azonosítójuk (ID) alapján (Séma vagy DTD kell hozzá)
number last() - a kontextus méretét adja vissza
string name([node-set]) - az első csomópont nevét adja vissza, ha nincs param a kontextuscsomópontét
number position() - a kontextuscsomópont pozícióját adja vissza a kontextuson belül
boolean boolean(object) - egy szám igaz ha nem 0, csomóponthalmaz ha nem üres, string ha nem üres
string string(object) - az első csomópont stringgé konvertált értékét adja vissza
string translate(string, string, string) - az elsőben cseréli a karaktereket a második 2 alapján
string concat(string, string ...)
boolean contains(string, string)
boolean starts-with(string, string)
number string-length(string)
string substring(string, number [,number])
string substring-before(string, string)
string substring-after(string, string)
string substring(string, number [,number])
boolean false()
boolean true()
boolean not(boolean)
number number([object]) - paraméter nélkül a kontextuscsomópontra vonatkozik
number round(number)
number floor(number)
number ceiling(number)
Nem tartoznak a fenti kategóriákba a text(), node(), comment(), processing-instruction() függvények.
Ezek predikátumon kívül is szerepelhetnek, és bizonyos speciális típusú csomópontok elérésére alkalmasak.
Az alábbi példákban az első négy lekérdezés mindegyike csak egyetlen gyermek csomópontját adja vissza a
Kolcsonzes-nek, az ötödik viszont mindegyiket.
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzesek/*') FROM kolcsonzes k WHERE azon=2;
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzesek/text()') FROM kolcsonzes k WHERE azon=2;
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzesek/comment()') FROM kolcsonzes k WHERE azon=2;
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzesek/processing-instruction()') FROM kolcsonzes k WHERE azon=2;
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzesek/node()') FROM kolcsonzes k WHERE azon=2;
-- A fentiek az alábbi utasítás futtatása után értendők:
INSERT INTO kolcsonzes VALUES(2, SYS.XMLType.CreateXML(
'
'));
Vagyis a * csak a 'rendes' csomópontokra illeszkedik, a node() viszont a speciálisakra is!!!
Példák függvényekre:
--------------------
-- Most nincs séma, ahol megmondanánk, hogy a név az azonosító (!)
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzo[id("Nagy Pal")]').getstringval() FROM kolcsonzes k;
-- Csak az első elemeket fűzi össze (!)
SELECT k.kolcs_spec.EXTRACT('//Kolcsonzo[concat(.//CD/@eloado, .//CD/Ar)="ABBA2000"]/@nev')
FROM kolcsonzes k;
-- string konverzió
SELECT k.kolcs_spec.EXTRACT('//DVD[string()="Jegkorszak"]').getStringVal() FROM kolcsonzes k;
-- Adjuk meg azokat a csomópontokat, amelyek nevének 2. betűje "i".
SELECT k.kolcs_spec.EXTRACT('//*[substring(name(), 2, 1)="i"]').getStringVal() FROM kolcsonzes k;
SELECT k.kolcs_spec.EXTRACT('//*[substring-before(name(), "onzo") ="Kolcs"]').getStringVal()
FROM kolcsonzes k;
SELECT k.kolcs_spec.EXTRACT('//*[substring-after(name(), "Kolcs") ="onzo"]').getStringVal()
FROM kolcsonzes k;
SELECT k.kolcs_spec.EXTRACT('//DVD[translate(name(), "DV", "dv")="dvd"]').getStringVal()
FROM kolcsonzes k;
-- A nemüres karakterlánc -> true
SELECT k.kolcs_spec.EXTRACT('//CD[boolean(Cim)]').getStringVal() FROM kolcsonzes k;
Műveletek a predikátumokon belül:
---------------------------------
+, -, *, div, mod
-- Példák XPath kifejezésekre (teljes szintaxis)
---------------------------------------------------------------
-- child::para selects the para element children of the context node
-- child::* selects all element children of the context node
-- child::text() selects all text node children of the context node
-- child::node() selects all the children of the context node, whatever their node type
-- attribute::name selects the name attribute of the context node
-- attribute::* selects all the attributes of the context node
-- descendant::para selects the para element descendants of the context node
-- ancestor::div selects all div ancestors of the context node
-- ancestor-or-self::div selects the div ancestors of the context node and, if the context node is a div element,
-- the context node as well
-- descendant-or-self::para selects the para element descendants of the context node and, if the context node
-- is a para element, the context node as well
-- self::para selects the context node if it is a para element, and otherwise selects nothing
-- child::chapter/descendant::para selects the para element descendants of the chapter element children of
-- the context node
-- child::*/child::para selects all para grandchildren of the context node
-- / selects the document root (which is always the parent of the document element)
-- /descendant::para selects all the para elements in the same document as the context node
-- /descendant::olist/child::item selects all the item elements that have an olist parent and that are in
-- the same document as the context node
-- child::para[position()=1] selects the first para child of the context node
-- child::para[position()=last()] selects the last para child of the context node
-- child::para[position()=last()-1] selects the last but one para child of the context node
-- child::para[position()>1] selects all the para children of the context node other than
-- the first para child of the context node
-- following-sibling::chapter[position()=1] selects the next chapter sibling of the context node
-- preceding-sibling::chapter[position()=1] selects the previous chapter sibling of the context node
-- /descendant::figure[position()=42] selects the forty-second figure element in the document
-- /child::doc/child::chapter[position()=5]/child::section[position()=2] selects the second section of the
-- fifth chapter of the doc document element
-- child::para[attribute::type="warning"] selects all para children of the context node that have a type
-- attribute with value warning
-- child::para[attribute::type='warning'][position()=5] selects the fifth para child of the context node
-- that has a type attribute with value warning
-- child::para[position()=5][attribute::type="warning"] selects the fifth para child of the context node
-- if that child has a type attribute with value warning
-- child::chapter[child::title='Introduction'] selects the chapter children of the context node that have
-- one or more title children with string-value equal to Introduction
-- child::chapter[child::title] selects the chapter children of the context node that have one or more
-- title children
-- child::*[self::chapter or self::appendix] selects the chapter and appendix children of the context node
-- child::*[self::chapter or self::appendix][position()=last()] selects the last chapter or appendix
-- child of the context node
-- Rövidített szintaxis
------------------------------------------------------------------
-- para selects the para element children of the context node
-- * selects all element children of the context node
-- text() selects all text node children of the context node
-- @name selects the name attribute of the context node
-- @* selects all the attributes of the context node
-- para[1] selects the first para child of the context node
-- para[last()] selects the last para child of the context node
-- */para selects all para grandchildren of the context node
-- /doc/chapter[5]/section[2] selects the second section of the fifth chapter of the doc
-- chapter//para selects the para element descendants of the chapter element children of the context node
-- //para selects all the para descendants of the document root and thus selects all para elements in
-- the same document as the context node
-- //olist/item selects all the item elements in the same document as the context node that have an olist parent
-- . selects the context node
-- .//para selects the para element descendants of the context node
-- .. selects the parent of the context node
-- ../@lang selects the lang attribute of the parent of the context node
-- para[@type="warning"] selects all para children of the context node that have a type attribute with value warning
-- para[@type="warning"][5] selects the fifth para child of the context node that has a type attribute with value warning
-- para[5][@type="warning"] selects the fifth para child of the context node if that child has a type attribute
-- with value warning
-- chapter[title="Introduction"] selects the chapter children of the context node that have one or more title children
-- with string-value equal to Introduction
-- chapter[title] selects the chapter children of the context node that have one or more title children
-- employee[@secretary and @assistant] selects all the employee children of the context node that have both a
-- secretary attribute and an assistant attribute
-- Példák az existsNode() használatára
-----------------------------------------------------------------------
SELECT azon
FROM kolcsonzes
WHERE existsNode(kolcs_spec, '//DVD[text()="Shrek"]')=1;
-- Példák az extractValue() használatára
-------------------------------------------------------------------------------
A EXTRACTVALUE függvény annyiban különbözik az EXTRACT-tól, hogy ez csak egyetlen elemre vagy
attribútumra működik, és annak eredményét VARCHAR2-ként adja vissza.
-- A Nagy Pal által kölcsönzött egyetlen DVD elem szöveges gyermekét adja vissza
SELECT EXTRACTVALUE(kolcs_spec, '//*[@nev="Nagy Pal"]//DVD') FROM kolcsonzes;
----------
Uvegtigris
Maga a csomópont így néz ki:
SELECT EXTRACT(kolcs_spec, '//*[@nev="Nagy Pal"]//DVD').getstringval() FROM kolcsonzes;
-------------------------------
Uvegtigris