**XPath** (lyhenne sanoista *XML Path Language*) on ei-XML-pohjainen kieli XML-dokumenttien osien osoittamiseen ja XML-dokumentin rakenteeseen perustuvan tiedon luontiin. XPath-kieli perustuu XML-dokumentin puumuotoiseen esitystapaan ja antaa siten mahdollisuuden poimia eri osia dokumentista tietyillä valintakriteereillä. XPath kehitettiin halusta saada yhtenäinen syntaksi ja käyttäytymismalli XPointerin ja XSL:n välille. Kehittäjät ovat nopeasti ottaneet XPathin käyttöönsä pienenä kyselykielenä.

Merkintätapa
------------

Yleisin XPath-lauseke on polkulauseke, josta kieli on saanut nimensä. Polkulauseke koostuu peräkkäisistä askeleista, joilla päästään XML-solmusta yhteen tai useampaan toiseen solmuun. Askeleet erotetaan toisistaan vinoviivalla, "/". Jokaisessa askeleessa on vähintään kaksi osaa:

* Akselimäärittely (axis specifier)
* Solmutesti (node test)
* Predikaatti (predicate)

Näistä viimeinen eli predikaatti on vapaaehtoinen osa, mutta niitä voi olla useita peräkkäin. Komponentit esiintyvät yllä luetellussa järjestyksessä. Akselimäärittely ja solmutesti erotetaan tosistaan kahdella kaksoispisteellä `::`, predikaatit erotetaan kirjoittamalla kukin niistä hakasulkeiden `[]` sisään.

Tarjolla on kaksi eri merkintätapaa. **Lyhennetty syntaksi** on tiiviimpi ja usein helpompi lukea ja kirjoittaa – usein tutuilla merkeillä ja rakenteilla. Täysi syntaksi on monisanaisempi, mutta sen avulla voi määritellä enemmän asetuksia.

### Lyhennetty syntaksi

Tiivis merkintätapa sallii joitain oletuksia ja lyhenteitä. Yksinkertaisin XPath-lauseke on muotoa `/A/B/C`, joka valitsee XML-juurielementin A lapsielementtien B lapsielementit C. XPathin syntaksi on suunniteltu muistuttamaan URI:n ja tiedostopolkujen syntaksia.

Monimutkaisempia lausekkeita voi muodostaa muun muassa määrittelemällä:

* akselin, joka on jokin muu kuin oletusarvoinen lapsiakseli,
* solmutestin, jossa testataan jotain muuta kuin nimeä tai
* predikaatin, jonka voi kirjoittaa minkä tahansa askeleen perään hakasuluissa "[]".

Esimerkiksi lauseke `A//B/*[1]` valitsee ensimmäisen (`[1]`) minkä tahansa nimisen elementin (`*`), joka on lapsi (`/`) elementille B, joka taas itsessään on elementin A jälkeläinen (`//`), joka on nykyisen kontekstisolmun lapsi, koska koko lauseke ei ala merkillä `/` tai muulla akselimäärittelyllä.

### Täysi syntaksi

Lyhentämättömässä syntaksissa yllä olevat esimerkit näyttävät tältä:

* `/child::A/child::B/child::C` ja
* `child::A/descendant-or-self::node()/child::B/*[1]` joka on sama kuin `child::A/descendant::B/*[1]`.

Jokaisessa askeleessa **akseli** on määritelty eksplisiittisesti: `child` tai `descendant-or-self`). Akselia seuraa `::` ja **solmutesti**, kuten `A` tai `node()` yllä olevissa esimerkeissä.

### Lyhennetyn ja täyden syntaksin vastaavuudet

| Valinnan tyyppi | Lyhennetty syntaksi | Täysi syntaksi |
| --- | --- | --- |
| Valitse kontekstisolmun lapsielementti nimeltä "nimi" | `nimi`(lapsi on oletussuunta) | `child::nimi` |
| Valitse nykyisen puun juuri ja kaikki sen jälkeläiset | `//` | `/descendant-or-self::node()/` |
| Valitse nykyinen solmu | `.` | `self::node()` |
| Valitse ylemmän tason solmu | `..` | `parent::node()` |
| Valitse attribuutti nimeltä "nimi" | `@nimi` | `attribute::nimi` |

Akselimäärittelyt
-----------------

Akselimäärittely ilmaisee liikkumissuuntaa XML-dokumentin puumaisessa esitystavassa. Mahdolliset akselimäärittelyt ja niiden merkitykset ovat:

| Nimi | Selitys |
| --- | --- |
| ancestor | Esivanhempi |
| ancestor-or-self | Esivanhempi tai nykyinen |
| attribute | Attribuutti |
| child | Lapsi |
| descendant | Jälkeläinen |
| descendant-or-self | Jälkeläinen tai nykyinen |
| following | Tuleva |
| following-sibling | Tuleva sisar |
| namespace | Nimiavaruus |
| parent | Vanhempi |
| preceding | Edeltävä |
| preceding-sibling | Edeltävä sisar |
| self | Nykyinen solmu |

Esimerkkinä **attribute**-akselin käytöstä, `//a/@href` valitsee attribuutin nimeltä `href` dokumentin miltä tahansa `a` elementiltä. Suuntaa **self** käytetään usein predikaatissa viittaamaan kontekstisolmuun. Esimerkiksi `h3[.='Katso myös']` valitsee elementin nimeltä `h3`, jonka tekstisisältö on `Katso myös`.

Jos XML-dokumentti piirretään puumuotoon, akselit jakavat dokumentin neljään erilliseen lohkoon: vaakatasossa preceding–following -akselilla ja pystytasossa ancestor–descendant -akselilla. Syntaksin näkökulmasta `preceding` sisältää elementit, joiden lopputagi on jo tullut vastaan ja `following` elementit, joiden alkutagi ei ole vielä tullut vastaan (pois lukien jälkeläiset). Vastaavasti `ancestor` vastaa avoinna olevia elementtejä, ja `descendant` kontekstisolmusta avattavia elementtejä.

Solmutestit
-----------

Elementtien, attribuuttien ja nimiavaruuksien kohdalla solmutesti muodostuu kohteen nimestä. Muilla tyypeillä se koostuu solmun tyyppiä vastaavasta solmutestistä.

Kun XPath-askeleessa solmutestinä on kohteen nimi, viittaa nimi oletuksena aina kohteeseen, jolle ei ole määritelty mitään nimiavaruutta. Haettaessa johonkin nimiavaruuteen kuuluvaa elementtiä tai attribuuttia, pitää solmutestissä aina käyttää nimiavaruusetuliitettä, joka erotetaan kaksoispisteellä nimestä. Tämä pätee vaikkei kohteella dokumentissa olisikaan etuliitettä vaan se kuuluisi oletusnimiavaruuteen. Nimiavaruusetuliitteen ei tarvitse olla sama, mitä dokumentissa mahdollisesti käytetty etuliite. Esimerkiksi jos nimiavaruudelle on määritelty etuliite `gs`, niin `//gs:enquiry` löytää kaikki `enquiry`-nimiset solmut siitä nimiavaruudesta. XPath-kieli ei ota kantaa miten nimiavaruus sidotaan etuliitteeseen vaan se riippuu käytettävästä ohjelmointiympäristöstä.

Solmun tyyppiä vastaavat testit ovat:

comment()löytää XML-kommenttisolmun: `<!-- Comment -->`.
text()löytää tekstisolmun `<k>terve</k>`.
processing-instruction()löytää XML-käsittelyohjeita, kuten `<?php echo $a ?>`. Tässä tapauksessa **processing-instruction('php')** olisi tarkempi lauseke mainitun solmun löytämiseen.
node()vastaa mitä tahansa solmutyyppiä.

Predikaatit
-----------

Predikaatti on vapaaehtoinen osa XPath-askelta. Predikaatti on suodatusehdon tavoin toimiva hakasulkeiden sisällä oleva XPath-lauseke, jonka tulee olla tosi, jotta solmu tulee valituksi mukaan solmujoukkoon. Esimerkiksi `//a[@href='apua.php']`, poimii vain ne `a` elementit, jolla on `href` attribuutti ja sillä arvona `apua.php`. Valinta ei kuitenkaan osu itse attribuuttiin vaan elementtiin, koska tarkentava askel on predikaatissa.

Predikaattien määrälle ei ole rajoituksia eikä niiden tarvitse sijaita polkulausekkeen lopussa. Niitä voi sijoittaa myös sisäkkäin. Predikaatin sisällä käytettävä mahdollinen polku alkaa elementistä, jolle predikaatti alun perin määriteltiin eikä se vaikuta predikaatin ulkopuolella olevaan kontekstiin.

Esimerkki: `//a[@href='apua.php'][../div/@luokka='otsikko']/@kohde` poimii `kohde` attribuutin `a` elementiltä edellyttäen että sillä on `href` attribuuttina arvo `apua.php` ja että `a` elementti on `div` elementin sisällä jolla puolestaan on `luokka` attribuuttina arvo `otsikko`.

Funktiot ja operaattorit
------------------------

XPath 1.0:ssa dokumentin rakenteet ovat olioita, jotka voidaan jakaa neljään eri tietotyyppiin: solmujoukko, merkkijono, numero sekä boolean-tyyppi.

Käytettävissä olevat operaattorit ovat:

* `/`, `//` ja `[...]` operaattorit, joita käytetään polkulausekkeissa edellä kuvatulla tavalla.
* Unioni, `|`, joka muodostaa kahden solmujoukon yhdistelmän.
* Boolean-operaattorit `and` ja `or`
* Aritmeettiset operaattorit `+`, `-`, `*`, `div` (jakolasku), ja `mod` (jakojäännös)
* Vertailuoperaattorit `=`, `!=`, `<`, `>`, `<=`, `>=`

### Solmujoukkoja käsittelevät funktiot

count(solmujoukko)
Palauttaa argumenttina annetun solmujoukon koon.
id(olio)
Palauttaa argumenttina annetun id-tunnisteen mukaisen elementin.
last()
Palauttaa kontekstijoukon koon.
local-name(solmujoukko?)
Palauttaa argumenttina annetun solmun *paikallisen nimen*. Mikäli argumenttia ei anneta, argumenttina käytetään kontekstijoukon ensimmäistä solmua.
name(solmujoukko?)
Palauttaa argumenttina annetun solmun *tarkennetun nimen* (*QName*). Mikäli argumenttia ei anneta, argumenttina käytetään kontekstijoukon ensimmäistä solmua.
namespace-uri(solmujoukko?)
Palauttaa argumenttina annetun solmun *nimiavaruus URIn*. Mikäli argumenttia ei anneta, argumenttina käytetään kontekstijoukon ensimmäistä solmua.
position()
Palauttaa konteksijoukossa solmun sijaintia vastaavan luvun.
### Merkkijonofunktiot

concat(merkkijono, merkkijono, merkkijono\*)
Palauttaa argumenttinsa yhteenliitettyinä.
contains(merkkijono, merkkijono)
Palauttaa tosi, jos ensimmäinen argumentti sisältää jälkimmäisen, muuten palauttaa epätosi.
normalize-space(merkkijono?)
Palauttaa argumentin normalisoituna.
starts-with(merkkijono, merkkijono)
Palauttaa tosi, jos ensimmäinen argumentti alkaa jälkimmäisellä, muuten palauttaa epätosi.
string(olio?)
Palauttaa oliota vastaavan merkkijonon.
string-length(merkkijono?)
Palauttaa merkkijonon pituuden. Mikäli argumenttia ei anneta käytetään kontekstisolmun *tekstiarvoa*
substring(merkkijono, numero, numero?)
Palauttaa alimerkkijonon, joka alkaa toisen argumentin osoittamasta paikasta ja jonka pituus vastaa kolmatta argumenttia. Jos kolmatta argumenttia ei ole, pituus on ensimmäisen argumentin loppuun saakka. Huom! Merkkijonon kirjainten indeksointi alkaa luvusta 1.
substring-after(merkkijono, merkkijono)
Palauttaa alimerkkijonon, joka seuraa ensimmäisessä argumentissa jälkimmäistä
substring-before(merkkijono, merkkijono)
Palauttaa alimerkkijonon, joka edeltää ensimmäisessä argumentissa jälkimmäistä
translate(merkkijono, merkkijono, merkkijono)
Palauttaa ensimmäisen argumentin, jossa toisen argumentin osoittamat merkit ovat korvattu vastaavalla sijalla kolmannessa argumentissa olevilla merkeillä.
### Totuusarvofunktiot

false()
Palauttaa arvon epätosi.
lang(merkkijono)
Palauttaa tosi, mikäli kontekstisolmun kieli `xml:lang`-attribuutilla merkittynä vastaa argumenttina annettua merkkijonoa.
not(totuusarvo)
Palauttaa arvon tosi argumentin ollessa epätosi, muussa tapauksessa päinvastoin.
true()
Palauttaa arvon tosi.
### Lukufunktiot

ceiling()
Palauttaa argumentin pyöristettynä kattofunktiolla.
floor(numero)
Palauttaa argumentin pyöristettynä lattiafunktiolla.
number(olio?)
Palauttaa oliota muunnettuna numeroarvoksi.
round()
Palauttaa argumentin pyöristettynä lähimpään kokonaislukuun.
sum(solmujoukko)
Palauttaa solmujoukon solmuja vastaavien numeroarvojen summan

Katso myös
----------

* XML
* XSL, XSLT, XSL-FO
* XQuery
* XLink, XPointer
* XML Schema
* STXPath

Lähteet
-------

1. ↑

Aiheesta muualla
----------------

* XPath 1.0 -määrittely
* XPath 2.0 -kandidaatti
* ilmainen XPath-ohjelmisto
* (saksaksi) XPath opetusohjelma
* (saksaksi) XSLT ja XPath viite (Arkistoitu – Internet Archive)