51
Static Typing in XQuery Based on Xquery from the Experts [Katz], chap 4 Presented by Iris Rudner

Static Typing in XQuery Based on Xquery from the Experts [Katz], chap 4 Presented by Iris Rudner

  • View
    217

  • Download
    3

Embed Size (px)

Citation preview

Static Typing in XQuery

Based on

Xquery from the Experts [Katz], chap 4

Presented by

Iris Rudner

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 >

The desired output is an XHTML document that can

be rendered by a browser :

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>

Debugging

Why is the table such a mess ???

[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

Debugging – cont.

Where are the Item Names ???

[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.

Are we done ???

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.

Conclusions

What have we seen?

The benefits of static typing. How Xquery infers the type for each expression

during static analysis. Common errors that can be detected by static typing,

including misspelled names in path expressions and constructors.