XPath Performance Test

There are 6 groups of queries: XPath-A, XPath-B, XPath-C, XPath-D, XPath-E, XPath-F. For each query in any of the groups, we specify an identifier, the query in natural language, the target of the query (enclosed in curly brackets), and finally the query formula. For parametric queries, we provide a parametric definition and a generator program (in Perl). For transitive queries (XPath-F) we provide the XQuery encoding. Here is an archive containing all the queries (in XPath, XQuery, and XSLT formats).

XPath-A

A1 Keywords in annotations of closed auctions {child}

/site/closed_auctions/closed_auction/annotation/description/text/keyword

A2 Keywords in annotations of closed auctions {descendant}

//closed_auction//keyword

A3 Keywords in annotations of closed auctions {child and descendant}

/site/closed_auctions/closed_auction//keyword

A4 Closed auctions with an annotation containing a keyword {filter with child}

/site/closed_auctions/closed_auction[annotation/description/text/keyword]/date

A5 Closed auctions with an annotation containing a keyword {filter with descendant}

/site/closed_auctions/closed_auction[descendant::keyword]/date

A6 People that have declared both gender and age {conjunction in filters}

/site/people/person[profile/gender and profile/age]/name

A7 People that have declared either phone or homepage {disjunction in filters}

/site/people/person[phone or homepage]/name

A8 People that have declared address and either phone or homepage and either credit card or profile {conjunction and disjunction in filters}

/site/people/person[address and (phone or homepage) and (creditcard or profile)]/name

XPath-B

B1 American items {parent}

/site/regions/*/item[parent::namerica or parent::samerica]/name

B2 Paragraph items containing a keyword {ancestor}

//keyword/ancestor::listitem/text/keyword

B3 Bidders except the last one of each open auction {following-sibling}

/site/open_auctions/open_auction/bidder[following-sibling::bidder]

B4 Bidders except the first one of each open auction {preceding-sibling}

/site/open_auctions/open_auction/bidder[preceding-sibling::bidder]

B5 Items of the document except the last one {following}

/site/regions/*/item[following::item]/name

B6 Items of the document except the first one {preceding}

/site/regions/*/item[preceding::item]/name

B7 People that have declared an income {attribute}

//person[profile/@income]/name

B8 Open auctions with exactly one bidder {filter with negation}

/site/open_auctions/open_auction[bidder and not(bidder/preceding-sibling::bidder)]/interval

B9 Open auctions {propositional reasoning: the filter is always true (it is a tautology)}

/site/open_auctions/open_auction[
(not(bidder/following::bidder) or not(bidder/preceding::bidder)) or
(bidder/following::bidder and bidder/preceding::bidder)]/interval

B10 No open auction {propositional reasoning: the filter is always false (it is a contraddiction)}

/site/open_auctions/open_auction[
(not(bidder/following::bidder) or not(bidder/preceding::bidder)) and
(bidder/following::bidder and bidder/preceding::bidder)]/interval

B11(i) {Parametric query featuring child and parent} generator

X + Y(i) + Z for i = 0,1,...
X = //open_auction
Y(i) = (/bidder/..)i
Z = /interval

B12(i) {Parametric query featuring attribute and parent} generator

X + Y(i) + Z for i = 0,1,...
X = //item
Y(i) = (/@id/..)i
Z = /name

B13(i) {Parametric query featuring descendant and ancestor} generator

X + Y(i) for i = 0,1,...
X = //keyword
Y(i) = (/ancestor::parlist/descendant::keyword)i

B14(i) {Parametric query featuring following-sibling and preceding-sibling} generator

X + Y(i) for i = 0,1,...
X = //bidder
Y(i) = (/following-sibling::bidder/preceding-sibling::bidder)i

B15(i) {Parametric query featuring following and preceding} generator

X + Y(i) for i = 0,1,...
X = //keyword
Y(i) = (/following::keyword/preceding::keyword)i

XPath-C

C1 People of age having an income less than 10000 and living is a city that is not Dallas {comparing the string value of a path expression with an atomic values}

/site/people/person[profile/age >= 18 and 
profile/@income < 10000 and address/city != "Dallas"]/name

C2 Open auctions having some bidder's increase equal to the current amount {comparing the string value of two path expressions}

/site/open_auctions/open_auction[bidder/increase = current]/interval

C3 People with an income equal to the current price of some item {join on values}

/site/people/person[profile/@income = /site/open_auctions/open_auction/current]/name

C4 People that are sellers in an auction that they are watching {join on keys}

/site/people/person[watches/watch/id(@open_auction)/seller/@person = @id]/name

C5 The person corresponding to a give key {id() function on a static parameter}

id("person0")/name

C6 Open auctions that someone is watching {id() function on a dynamic parameter. Single chasing}

/site/people/person/watches/watch/id(@open_auction)/interval

C7 People that are watching an auction that sells an Australian item {id() function on a dynamic parameter. Double chasing}

/site/people/person[watches/watch/id(@open_auction)/itemref/id(@item)/parent::australian]/name

C8(i) Categories that are reachable from a given category in i steps, for i >= 1. {parametric join on keys} generator

Y(i)/id(.)/name for i = 1,2,...
Y(1) = /site/catgraph/edge[@from = "category0"]/@to
Y(i) = /site/catgraph/edge[@from = Y(i-1)]/@to for i >= 2

C9(i) Open auctions that are watched by sellers of open auctions that are watched by sellers of open auctions... {parametric query on id() function. The result node set shrinks monotonically} generator

X + Y(i) + Z for i = 0,1,...
X = /site/open_auctions/open_auction
Y(i) = (/seller/id(@person)/watches/watch/id(@open_auction))i
Z = /interval

C10(i) People that are bidders of open auctions that are watched by people that are bidders of open auctions that are watched by people... {parametric query on id() function. The result node set shrinks monotonically} generator

X + Y(i) + Z for i = 0,1,...
X = /site/people/person
Y(i) = (/watches/watch/id(@open_auction)/bidder/personref/id(@person))i
Z = /name

XPath-D

D1 Open auctions with an odd number of bidders {counting}

/site/open_auctions/open_auction[(count(bidder) mod 2) = 0]/interval

D2 The number of pieces of prose contained in the document {counting}

count(//text) + count(//bold) + count(//emph) + count(//keyword)

D3 Open auctions with a total increase greater than 10 times the initial price {summing}

/site/open_auctions/open_auction[sum(bidder/increase) > 10 * initial]/interval

D4 Open auctions with a total increase different from the difference between the current and initial prices {summing}

/site/open_auctions/open_auction[sum(bidder/increase) != (current - initial)]/interval

D5 Open auctions with an average increase greater than the double of the initial price {taking the average, i.e. summing and counting}

/site/open_auctions/open_auction[bidder and 
(sum(bidder/increase) div count(bidder)) > 2 * initial]/interval

XPath-E

E1 Open auctions whose increase in the median position is contained between the first and the last increase of the auction {accessing elements with a specific position wrt child axis}

site/open_auctions/open_auction[bidder[1]/number(increase) <
bidder[floor((last() + 1) div 2)]/number(increase) and
bidder[floor((last() + 1) div 2)]/number(increase) <
bidder[last()]/number(increase)]/interval

E2 The last keyword appearing in the description of an European item {accessing elements with a specific position wrt descendant axis}

/site/regions/europe/item/description/descendant::keyword[last()]

E3 The closest paragraph item containing a keyword {accessing elements with a specific position wrt ancestor axis}

//keyword/ancestor::listitem[1]/text/keyword

E4 Bidders of an open auction whose increase is between the increase of the previous and next bidders of the auction {accessing elements with a specific position wrt sibling axes}

site/open_auctions/open_auction/bidder
[preceding-sibling::bidder[1]/number(increase) <= number(increase) and
number(increase) <= following-sibling::bidder[1]/number(increase)]

E5 Items that have at least 100 items following them in the document and at least 100 items preceding them in the document {accessing elements with a specific position wrt following and preceding axes}

/site/regions/*/item[preceding::item[100] and following::item[100]]/name

E6 Items whose description contains the name of the item {searching for a string}

/site/regions/*/item[contains(description, name)]/name

E7 Items whose description contains the word 'passion' followed by the word 'eros' followed by the word 'dangerous' {searching for a string}

/site/regions/*/item[contains(substring-before(description, "eros"), "passion") and 
contains(substring-after(description, "eros"), "dangerous")]/name

E8 Items with a long description {string processing}

/site/regions/*/item
[string-length(translate(normalize-space(description)," ","")) > 10000]/name

XPath-F

F1 Bidders such that there exists a following sibling bidder with increase bigger than 10 and for all bidders in between the increase is smaller or equal than 10 {until-like statement; closure of a single step} xquery version

//bidder[number(increase) <= 10 and (BIGGER or closure(.,SMALLER)/BIGGER)]

BIGGER = following-sibling::bidder[position()=1 and number(increase) > 10]
SMALLER = following-sibling::bidder[position()=1 and number(increase) <= 10]

F2 Bidders such that there exists a preceding sibling bidder with increase bigger than 10 and for all bidders in between the increase is smaller or equal than 10 {since-like statement; closure of a single step} xquery version

//bidder[number(increase) <= 10 and (BIGGER or closure(.,SMALLER)/BIGGER)]

BIGGER = preceding-sibling::bidder[position()=1 and number(increase) > 10]
SMALLER = preceding-sibling::bidder[position()=1 and number(increase) <= 10]

F3 Paragraph items that contain a keyword nested under an odd number of paragraph items {closure of a 2-step path} xquery version

//listitem[text/keyword or
closure(.,parlist/listitem/parlist/listitem)/text/keyword]/text/keyword

F4 Open auctions that are watched by sellers of open auctions that are watched by sellers of open auctions... {Closure of a long step} xquery version

/site/open_auctions/open_auction[position() <= 5]/
closure(.,seller/id(@person)/watches/watch/id(@open_auction))/interval

F5 People that are bidders of open auctions that are watched by people that are bidders of open auctions that are watched by people... {Closure of a long step} xquery version

/site/people/person[position() <= 5]/
closure(.,/watches/watch/id(@open_auction)/bidder/personref/id(@person))/name

F6 Elements that contain a reference to the first person of the document {idref() function}

/site/people/person[1]/idref(@id)/..

F7 Categories that are reachable from a given category through an arbitrary path in the category graph {Transitive closure on let statement} xquery version

//category[@id="category0"]/@id/
closure(.,let $i = . return ($i | //edge[@from = $i]/@to))/id(.)/name

F8 Categories that are reachable from a given category through an arbitrary path in the category graph {Transitive closure on idref() function} xquery version

//category[@id="category0"]/@id/
closure(.,idref(.)[name() = "from"]/../@to)/id(.)/name
XHTML + CSS