View
217
Download
3
Embed Size (px)
Citation preview
Intro
Xquery implementations must support dynamic typing, and may support static typing.
Objective: How to use the Xquery type system to write type-safe queries, how to understand and resolve type errors and how to work around the type system when necessary.
The Benefits of Static Typing
Can help by detecting common type errors during static analysis instead of being discovered only when the program is run.
A type error occurs when the type of an expression is not compatible with the type required by the context in which the expression is used.
Static typing is conservative. For example:
expression of type element(surgeon) | element(plumber)
in a context requiring element(surgeon)
Static typing allows to detect all type errors.
Cannot detect errors such as divide-by-zero or
array-bounds-overflow.
The Benefits of Static Typing (cont.)
An Xquery Programming Scenario
XML Schema for the Relational Auction Data:
<xs:schema targetNamespace=http://example.com.auction xmlns:xs=http://www.w3.org/2001/XMLSchema xmlns="http://www.example.com/auction"> <xs:element name="auction"><xs:complexType>
<xs:sequence><xs:element name="users"/><xs:element name="articles"/><xs:element name="bids"/>
</xs:sequence></xs:complexType> </xs:element>
<xs:element name="users"><xs:complexType>
<xs:element ref="user" maxOccurs="unbounded"/> </xs:complexType>
</xs:element>
<xs:element name="articles"><xs:complexType> <xs:element ref="article" maxOccurs="unbounded"/></xs:complexType>
</xs:element> <xs:element name="bids">
<xs:complexType><xs:element ref="bid" maxOccurs="unbounded"/>
</xs:complexType> </xs:element> <xs:element name="rating" type="xs:string"/> <xs:element name="user" type="User"/> <xs:complexType name="User">
<xs:sequence> <xs:element name="name">
<xs:complexType name=""> <xs:element name="first" type="xs:string" minOccurs="0"/> <xs:element name="last" type="xs:string"/> </xs:complexType>
</xs:element> <xs:element ref="rating" minOccurs="0"/> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/>
</xs:complexType>
<xs:attribute name="idref" type="xs:IDREF"/> <xs:element name="article" type="Article"/> <xs:complexType name="Article"> <xs:sequence>
<xs:element name="name" type="xs:string"/><xs:element name="seller">
<xs:complexType><xs:attribute ref="idref"
use="required"/> </xs:complexType></xs:element><xs:element name="start_date" type="xs:date"/><xs:element name="end_date" type="xs:date"/><xs:element name="reserve_price" type="xs:decimal"/><xs:element name="description" type="Freeform"
minOccurs="0"/>
</xs:sequence><xs:attribute name="id" type="xs:ID" use="required"/>
</xs:complexType> …
etc.
Relational Auction (partial) Data in XML:<auction xmlns="http://example.com/auction" >
<users> <user id = "U01"> <name> <first>Tom</first> <last>Jones</last> </name>
<rating>B</rating></user>
</users><articles>
<article id = "1001"><name>Red Bicycle</name><seller idref = "U01"/><start_date>1999-01-05</start_date>
<end_date>1999-01-20</end_date><reserve_price>40</reserve_price>
</article></articles><bids>
<bid><userid idref = "U02"/>
<articleno idref = "1001"/><amount>45</amount><date>1999-01-11</date>
</bid></bids> </auction >
XML Schema for XHTML:<xs:schema targetNamespace="http://www.w3.org/2001/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns = "http://www.w3.org/2001/xhtml">
<xs:element name="html" type="html.type"/><xs:complexType name="html.type">
<xs:sequence><xs:element ref="head"/><xs:element ref="body"/>
</xs:sequence></xs:complexType>
<xs:element name="head" type="head.type"/><xs:complexType name="head.type">
<xs:element ref="title"/></xs:complexType>
<xs:element name="title" type="title.type"/><xs:complexType name="title.type" mixed="true"/>
XML Schema for XHTML – cont. :
<xs:element name="body" type="Block.type"/><xs:complexType name="Block.type" mixed="true">
<xs:choice minOccurs="0" maxOccurs="unbounded"><xs:element ref="h1"/><xs:element ref="p"/><xs:element ref="table"/>
</xs:choice></xs:complexType> …<xs:element name="tr" type="tr.type"/>
<xs:complexType name="tr.name"><xs:choice maxOccurs="unbounded">
<xs:element ref="th"/><xs:element ref="td"/>
</xs:choice></xs:complexType>
<xs:element name="th" type="Block.type"/><xs:element name="td" type="Block.type"/>
</xs:schema>
Xquery:[1] default element namespace = "http://www.example.com/auction"[2] declare namespace x = "http://www.w3.org/1999/xhtml" [3] define variable $base := xs:anyURI("http://www.example.com/auction/")[4] define function makeURI ($resource as xs:string) as xs:anyURI { [5] xs:anyURI(fn:concat(xs:string($base), $resource)) [6] }[7] let $auction := $input/auction[8] return [9] <x:html>[10] <x:body>[11] <x:h1>Auctions</x:h1>[12] <x:table>[13] <x:td>[14] <x:th>Item Name</x:th>[15] <x:th>Seller</x:th>[16] <x:th>Last Bid</x:th>[17] <x:th>Closes On</x:th>[18] </x:td>[19] {[20] for $article in $auction/articles/article[start_date <=
date()]
Xquery – cont. :[21] let $last_bid := $auction/bids/bid[articleno/@idref = $article/@id]
[last()][22] return[23] <x:td>[24] <x:tr>[25] <x:a href="{makeURI($article/@id) }"> {
data($article/anme) } </x:a>[26] </x:tr>[27] <x:tr>[28] <x:a href="{ makeURI($article//@idref) }">{[29] fn:data($auction/users/user[@id =
$article//@idref]/name)[30] } </x:a>[31] </x:tr>[32] <x:tr>{ fn:data($last_bid/amount) }</x:tr>[33] <x:tr>{ fn:data($last_bid/date) }</x:tr>[34] </x:td>[35] }[36] </x:table> [37] </x:body> [38] </x:html>
[12] …<x:table>[13] <x:td>[14] <x:th>Item Name</x:th>
…..[18] </x:td>…[22] return[23] <x:td>[24] <x:tr>[25] <x:a href="{makeURI($article/@id) }">
{data($article/anme) } </x:a>[26] </x:tr>[27] <x:tr>[28] <x:a href="{ makeURI($article//@idref) }">{[29] fn:data($auction/users/user[@id =
$article//@idref]/name)[30] } </x:a>[31] </x:tr>[32] <x:tr>{ fn:data($last_bid/amount) }</x:tr>[33] <x:tr>{ fn:data($last_bid/date) }</x:tr>[34] </x:td>[35] } ….
A closer look at the query:
tr and td tags are inverted
[25] <x:a href="{makeURI($article/@id) }"> {data($article/anme) } </x:a>
should be:
[25] <x:a href="{makeURI($article/@id) }"> {data($article/name) } </x:a>
Debugging – cont.
Debugging – cont.
…
[28] <x:a href="{ makeURI($article//@idref) }">
…
Xquery – link to seller’s details :
Lets see which descendants of article has an idref attribute …
XML Schema:<xs:element name="article" type="Article"/> <xs:complexType name="Article"> <xs:sequence><xs:element name="name" type="xs:string"/><xs:element name="seller"><xs:complexType> <xs:attribute ref="idref" use="required"/></xs:complexType> </xs:element>
… <xs:element name="description"
type="Freeform" minOccurs="0"/>
</xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> </xs:complexType> <xs:complexType name="Freeform" mixed="true"><xs:anyAttribute processContents="skip"/> <xs:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/> </xs:complexType>
xs:anyType
possibly:Line [28]: Run-time type error. Argument to function ‘makeURI’ contains more than one value.
Debugging – cont.
correction:[28] <x:a href="{ makeURI($article/seller/@idref) }">
It took us 4 cycles of debugging by running the query and then changing the query…
Validation
It is important to validate the formats of the input and output documents.
To enable validation – explicitly import the schemas of the input and output, and explicitly validate the input data.
No need to explicitly validate the output data, because element constructors validate the elements they create.
Validation – cont.
[1] import schema default element namespace = "http://www.example.com/auction“ at “auction.xsd”
[2] import schema namespace x = "http://www.w3.org/1999/xhtml" at “xhtml.xsd”
[2a] default validation strict
…
[7] let $auction := validate { $input }
The query will raise a run-time error of the input document does not conform to the auction schema or if the output document does not conform to the XHTML schema.
Requires a declaration for the element
When running our query we get the error message:Validation error: Missing ‘x:head’ element in x:html element.
Lets look at the XHTML schema:…<xs:complexType name="html.type">
<xs:sequence>
<xs:element ref="head"/>
<xs:element ref="body"/>
</xs:sequence>
</xs:complexType>
<xs:element name="head" type="head.type"/>
<xs:complexType name="head.type">
<xs:element ref="title"/>…
Whereas the query:…[9] <x:html>[10] <x:body>….
Validation – cont.
How would validation affect our earlier debuggingcycles?
Detects the inverted tr and td tags. Fails to detect the misspelled element name. Fails to detect the error which occurs for input
data in which description elements contain idref attributes.
Static Typing
Validation detects the presence of certain types of error in the format of the data.
Static typing guarantees their absence.
It can spot errors during static analysis rather than at run-time.
It can detect many errors at once.
Not dependant on the input.
Static Typing
Line [10]: Element ‘x:body: encountered where element ‘x:head’ expected.
Line [13]: Element ‘x:td: encountered where element ‘x:tr’ expected.
Line [23]: Element ‘x:td: encountered where element ‘x:tr’ expected.
Line [25]: Expression ‘$article/anme’ is always empty.Line [28]: Argument to function ‘makeURI’ has actual type
(attribute(@idref) | attribute(@idref, xs:anySimpleType) )+ instead of expected type ‘xs:string’.
The result of static typing our query :
Getting Started with Types
Coming up:
How the type system assigns a type to different kinds of expressions.
Including: literals & operators, variables, function calls, conditionals, paths, FLWORs and element constructors.
XML Schema and Xquery types
Xquery’s type system is based on XML Schema.
But, it is simpler and more concise, for the sake of type checking.
More on the relationship between XML Schema and Xquery’s type system in the following lecture (chap 5).
XML Schema and Xquery types
XML Schema – global element:
<xs:element name="user" type="User"/>
formal type notation:
define element user of type User
define element rating of type xs:string<xs:element name="rating" type="xs:string"/>
In XML Schema, element declarations may be global, at the top level, or local, nested within a type declaration.
XML Schema and Xquery types – cont.
XML Schema – local elements, unnamed types & complex types:<xs:complexType name="User"> <xs:sequence> <xs:element name="name"> <xs:complexType name="">
<xs:element name="first“ type="xs:string“
minOccurs="0"/> <xs:element name="last"
type="xs:string"/> </xs:complexType> </xs:element>
<xs:element ref="rating" minOccurs="0"/> </xs:sequence> <xs:attribute name="id" type="xs:ID"
use="required"/>
</xs:complexType>
formal type notation:define type User {
attribute id of type xs:ID ,
element name of type AnonymousType1,
element rating ?
}
define type AnonymousType1{
element first of type xs:string ? ,
element last of type xs:string
}
XML Schema and Xquery types – cont.
XML Schema – simple type:<xs:simpleType name="IntegerList">
<xs:list itemType="xs:integer"/>
</xs:simpleType>
formal type notation:
define type IntegerList {xs:integer + }
In the formal type notation:
List types are formed using ?, + & *. Union types are formed using the choice operator | .
XML Schema – the NewUser type derived by restriction of the type User:<xs:complexType name="NewUser">
<xs:complexContent> <xs:restriction base="User">
<xs:sequence> <xs:element name="name">
<xs:complexType> <xs:element name="first"
type="xs:string"/> <xs:element name="last"
type="xs:string"/> </xs:complexType></xs:element><xs:element name="rating"
type="xs:string"/> </xs:sequence> <xs:attribute name="id" type="xs:ID" use="required"/> </xs:restriction>
</xs:complexContent></xs:complexType><xs:element name="newuser" type="NewUser"/>
formal type notation – type declarations for NewUser:
define type NewUser restricts User { attribute id of type xs:ID ,
element name of type AnonymousType2 ,
element rating
}
define type AnonymousType2 {
element first of type xs:string ,
element last of type xs:string
}
define element newuser of type NewUser
XML Schema and Xquery types – cont.
define function user-name($user as element(*,user)) as xs:string {…}
Can be applied to either a user or newuser element:
All types are derived from xs:anyType.
All simple types are derived from xs:anySimpleType.
Values
Xquery expression evaluates to a value in the Xquery data model.
Every Value is a sequence of individual items.
An item is either an atomic value or a node.
Every atomic value, element node and attribute node has an associated Xquery type.
The process of XML Schema validation specifies how elements and attributes are labeled with types.
Values – cont.
XML input document:<user id = "U02">
<name><first>Mary</first><last>Doe</last>
</name><rating>A</rating>
</user>
Xquery values representation:element user of type User {
attribute id of type xs:ID { “U02” } ,
element name of type AnonymousType1{
element first of type xs:string {“Mary”},
element last of type xs:string {“Doe”},
} ,
element rating of type xs:string { “A” }
}
If we apply fn:data to the first element, we get the value xs:string(“Mary”).
Relating Values and Types
Types are used ay analysis time and at evaluation time.
At evaluation time, the value of a query depends upon the types that label values.
It’s possible to refer to type labels explicitly:
//element(*, x:Block.type)
Both evaluation and type assignment proceed bottom-up.
Literals and Operators
How does the static type system assigns types to expressions?
Literals:
“hello” has type xs:string 42 has type xs:integer
42.00 has type xs:decimal 4.2e1 has type xs:double
arithmetic operations:
42 + 69 has type xs: integer 42 + 69.00 has type xs: decimal
order of promotion: xs:integer -> xs:decimal ->xs:float -> xs:double
Variables
let $z := 1+2 return $z+$z has type xs:integer
let $x as xs:integer := 1+2 return $x+$x has type xs:integer
Implicit:
Explicit:
let $x := xs:double(1+2) return $x+$x has type xs:double
let $x as xs:decimal := 1+2 return $x+$x has type xs: decimal
let $x as xs:double := 1+2 return $x+$x is a static type error
xs:integer is not a subtype of xs:double
Functions
function call:
fn:concat(“http://www.example.com/auction/”, “1001”) has type xs:string
function signature:
fn:concat( $op1 as xs:string ? , $op2 as xs:string ? ) as xs:string
fn:concat( () , “1001”) has type xs:string
The argument type must derive from the required type or can be promoted to it:
fn:concat(10e1, “1001”) is a static type error
unlike arithmetic operators, there’s no notion of promotion:
Conditionals
if ($x<$y) then 3 else 4 has type xs:integer
if ($x<$y) then “three” else 4.00 has type ( xs:string | xs:decimal )
if ($x<$y) then 4.2e1 else 69 has type ( xs:double | xs:integer )
unless arithmetic is performed on an operand expression of type ‘union’:(if ($x<$y) then 4.2e1 else 69) + 0.5 has type
( xs:double | xs:decimal )
Path Expressions
$auction/articles has type element(articles)
$auction/articles/article has type element(articles)+
$auction/itesm/article is a static type error (has type empty())
assume $auction has type element(auction) :
$auction/(articles | users) has type ( element(articles) | element(users) )+
$auction/(articles | users) doesn’t have type ( element(users) ,
element(articles) )
Predicates
$auction/articles/article[start_date <= date()] has type element(article)*
$auction/articles/article[@id = $id] has type element(article)*
exactly-one($auction/articles/article[@id = $id]) has type element(article)
zero-or-one($auction/articles/article[@id = $id]) has type element(article)?
one-or-more($auction/articles/article[@id = $id]) has type element(article)+
FLWOR Expressions
for $article in $articles return $article/end_date - $article/start_date
has type xdt:dayTimeDuration+
assume $articles has type element(article)+ :
for $article in $articles[start_date <= current_date()] return $article/end_date - $article/start_date
has type xdt:dayTimeDuration*
Element Construction Objective: how to construct data.
Simplest way – include literal XML data in a query :<article id = "1001"><name>Red Bycicle</name><seller idref = "U01"/>
<start_date>1999-01-05</start_date><end_date>1999-01-20</end_date> <reserve_price>40</reserve_price>
</article>
has type element(article)
At evaluation time, the element is constructed and then validated.
Element Construction – cont. Using computed data in a constructor:define function bargain ($a as element(article)) as element(article)
{
<article> {$a/@id,$a/name,$a/seller,<start_date>{ fn:current-date() }</start_date><end_date>{ fn:current-date() + ($a/end_date - $a/start_date) }</end_date><reserve_price>{ $a/reserve_price * 0.80 }</reserve_price>
}</article>
}
has type element(article)
Element Construction – cont.
Using computed data in a constructor – bad example:define function bargain ($a as element(article)) as element(article) {
<article> { $a/name, $a/seller, <start_date>{ fn:current-date() }</start_date> <end_date>{ $a/end_date - $a/start_date }</end_date> <reserve_price>{ $a/reserve_price * 0.80 }</reserve_price>
}</article>
}
the type system detects 2 errors.
no id attribute
type expected for end_date element is xs:date.the type of the expression is xs:dayTimeDuration.
Validation Context
let $first := "Mary" ,
$last := "Doe" ,
$rating := "A“
return
<user id="U02"> <name>
{ if (fn:string-length($first) > 10) then () else <first>{ $first }</first> }<last>{ $last }</last>
</name> { if ($rating > "C") then () else <rating>{ $rating }</rating> }</user>
validated in global context
validated in user context
validated in user/name context
validation context specified by lexical scope of constructors:
Validation Context – cont.
let $first := validate context user/name { <first>Mary</first> },
$last := validate context user/name { <last >Doe</last > },
$rating := validate context user { <rating>A</rating> }return <user id="U02"> <name>
{ if (fn:string-length($first) > 10) then () else $first, $last
}</name> if ($rating > "C") then () else $rating }</user>
validation context specified explicitly in validate expression:
the first, last & rating elements are no longer lexically nested within the user and name elements => validation context must be explicitly given.