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