collection

628
Contents Articles XQuery 1 Advanced Search 14 All Leaf Paths 19 All Paths 21 Alphabet Poster 23 Auto-generation of Index Config Files 27 Background 28 Basic Authentication 30 Basic Feedback Form 31 Basic Search 33 Basic Session Management 35 BBC Weather Forecast 37 Benefits 39 Caching and indexes 41 Chaining Web Forms 44 Changing Permissions on Collections and Resources 48 Compare two XML files 50 Compare with XQuery 51 Creating a Timeline 57 Creating XQuery Functions 60 Dates and Time 63 DBpedia with SPARQL - Stadium locations 64 Delivery Status Report 67 Digest Authentication 69 Digital Signatures 72 DocBook to HTML 74 DOJO data 74 Dynamic Module Loading 76 Examples Wanted 79 eXist demo server 79 Extracting data from XHTML files 80 Filling Portlets 81 Flickr GoogleEarth 82 FLWOR Expression 83

Upload: jralbendin

Post on 01-Sep-2014

377 views

Category:

Documents


6 download

TRANSCRIPT

ContentsArticlesXQuery Advanced Search All Leaf Paths All Paths Alphabet Poster Auto-generation of Index Config Files Background Basic Authentication Basic Feedback Form Basic Search Basic Session Management BBC Weather Forecast Benefits Caching and indexes Chaining Web Forms Changing Permissions on Collections and Resources Compare two XML files Compare with XQuery Creating a Timeline Creating XQuery Functions Dates and Time DBpedia with SPARQL - Stadium locations Delivery Status Report Digest Authentication Digital Signatures DocBook to HTML DOJO data Dynamic Module Loading Examples Wanted eXist demo server Extracting data from XHTML files Filling Portlets Flickr GoogleEarth FLWOR Expression 1 14 19 21 23 27 28 30 31 33 35 37 39 41 44 48 50 51 57 60 63 64 67 69 72 74 74 76 79 79 80 81 82 83

Formatting Numbers Generating PDF from XSL-FO files Generating Skeleton Typeswitch Transformation Modules Generating xqDoc-based XQuery Documentation Get zipped XML file Google Chart Bullet Bar Google Chart Sparkline Google Charts Graphing Triples Grouping Items Guest Registry Higher Order Functions Histogram of File Sizes Image Library Incremental Searching Index of Application Areas Index of eXist modules and features Index of XQuery features Inserting and Updating Attributes Installing and Testing Installing the XSL-FO module Introduction to XML Search Keyword Search Latent Semantic Indexing Limiting Child Trees Link gathering List OWL Classes Login and Logout Lorum Ipsum text Lucene Search Multiple page scraping and Voting behaviour MusicXML to Arduino Naming Conventions Navigating Collections OAuth Open Search Overview of eXist search functions and operators Overview of Page Scraping Techniques

84 86 92 100 103 110 112 114 117 119 122 123 125 128 129 132 135 135 136 137 138 141 142 154 157 158 165 167 168 171 178 180 183 184 187 189 190 191

Pachube feed Publishing Overview Publishing to Subversion Quantified Expressions Registered Functions Registered Modules Regular Expressions REST interface definition Returning the Longest String Saving and Updating Data Searching multiple collections Sending E-mail Sequences Sequences Module Setting HTTP Headers Simile Exhibit Sitemap for Content Management System Slideshow SMS tracker Southampton Pubs SPARQLing Country Calling Codes Special Characters Splitting Files Subversion Sudoku Synchronizing Remote Collections TEI Concordance TEI Document Timeline The Emp-Dept case study Time Based Queries Time Comparison with XQuery Timelines of Resource Timing Fibonacci algorithms Transformation idioms Typeswitch Transformations UK shipping forecast Unzipping an Office Open XML docx file Updates and Namespaces

192 204 207 208 209 211 212 215 226 227 229 232 234 245 246 250 252 257 262 267 268 272 273 276 282 287 290 295 302 303 305 309 311 317 327 331 347 349

Uploading Files Uptime monitor URL Driven Authorization URL Rewriting Basics Using Intermediate Documents Using Triggers to assign identifiers Using Triggers to Log Events Using XQuery Functions UWE StudentsOnline Validating a document Validation using a Catalog Web XML Viewer Wikibook list of code links Wikipedia Events RSS Wikipedia Page scraping World Temperature records XHTML + Voice XML Differences XML Schema to Instance XML Schema to SVG XML Schema to XForms XMP data XQuery SQL Module Adder Ah-has Checking for Required Parameters Dataflow diagrams DBpedia with SPARQL - Football teams DBpedia with SPARQL and Simile Timeline - Album Chronology Displaying data in HTML Tables Displaying Lists Employee Search Example Sequencer Excel and XML eXist Crib sheet Filtering Nodes Filtering Words Fizzbuzz

351 352 365 366 370 375 377 379 381 381 383 384 388 389 389 391 406 409 411 420 421 421 423 424 428 429 432 434 443 448 451 452 454 455 457 460 467 470

Getting POST Data Getting URL Parameters Google Geocoding Gotchas Graph Visualization HelloWorld HTML Table View Incremental Search of the Chemical Elements Limiting Result Sets Manipulating URIs Nationalgrid and Google Maps Net Working Days Page scraping and Yahoo Weather Parsing Query Strings Project Euler Searching,Paging and Sorting Sequence Diagrams Simple RSS reader Simple XForms Examples SPARQL interface SPARQL Tutorial String Analysis Tag Cloud Topological Sort Tree View Validating a hierarchy Wiki weapons page Wikibook index page Wikipedia Lookup XML to RDF XML to SQL XPath examples XQuery and Python XQuery and XML Schema XQuery and XSLT XQuery from SQL XQuery IDE XSL-FO Images

471 474 476 480 483 485 487 489 493 496 498 502 505 509 512 515 520 527 529 539 542 552 558 561 563 565 566 567 568 569 575 576 580 581 589 594 609 610

XSL-FO SVG XSL-FO Tables

611 612

ReferencesArticle Sources and Contributors Image Sources, Licenses and Contributors 617 621

Article LicensesLicense 622

XQuery

1

XQueryXQuery Examples CollectionWelcome to the XQuery Examples Collection Wikibook! XQuery is a World Wide Web Consortium recommendation for selecting data from documents and databases.

Current StatusA new release of eXist (1.4) is currently installed and under test. Please note any problems with these examples in the discussion. Recent Changes

About this ProjectThis is a collaborative project and we encourage everyone who is using XQuery to contribute their XQuery examples. All example programs must conform to the creative-commons-2.5 share-alike with attribution license agreement [1]. Execution of examples use an eXist demo server. 1. Instructors: please sign our Guest Registry if you are using this book for learning or teaching XQuery 2. Contributors: please see our Naming Conventions to ensure your examples are consistent with the textbook 3. Learners: If you are looking for an example of a specific XQuery language construct, technique or problem but can't find an example, please add a suggestion to the Examples Wanted section.

Introduction1. 2. 3. 4. Background - A brief history and motivation for the XQuery standard. Benefits - Why use XQuery? Installing and Testing - How to install an XQuery server on your . Naming Conventions - Naming standards used throughout this book.

Example ScriptsBeginning ExamplesExamples that do not assume knowledge of functions and modules. 1. 2. 3. 4. 5. 6. 7. 8. HelloWorld - A simple test to see if XQuery is installed correctly. FLWOR Expression - A basic example of how XQuery FLWOR statements work. Sequences - Working with sequences is central to XQuery. XPath examples - Sample XPath samples for people new to XML and XPath Regular Expressions - Regular expressions make it easy to parse text. Searching multiple collections - How to search multiple collections in a database. Getting URL Parameters - How to get parameters from the URL. Getting POST Data - How to get XML data posted to an XQuery.

9. Checking for Required Parameters - How to check for a required parameter using if/then/else. 10. Displaying Lists - How to take a list of values in an XML structure and return a comma separated list. 11. Extracting data from XHTML files - How to use the doc() function to get data from XHTML pages.

XQuery 12. Displaying data in HTML Tables - How to display XML data in an HTML table. 13. Limiting Result Sets - How to limit the number of records returned in an XQuery. 14. Filtering Words - How to test to see if a word is on a list. 15. Saving and Updating Data - How to have a single XQuery that saves new records or updates existing records. 16. Quantified Expressions - Testing all the items in a sequence. 17. Dates and Time - Sample expressions that work with date and time values 18. Chaining Web Forms - Passing data from one web page to another using URL parameters, sessions or cookies {{stage short|25%|Dec 17th, 2010}

2

Intermediate ExamplesAssumes knowledge of functions and modules. 1. 2. 3. 4. 5. 6. Using XQuery Functions - How to read XQuery function documents and user XQuery functions Creating XQuery Functions - How to create your own local XQuery functions Returning the Longest String - A function to find the longest string from a list of strings Net Working Days - How to calculate the number of working days between two dates Tag Cloud - Counting and viewing the number of keywords String Analysis/ - Regular expression string analysis

7. Manipulating URIs - How to get and manage URIs 8. Parsing Query Strings - Parsing query strings using alternate delimiters. 9. Splitting Files - Splitting a large XML files into many smaller files. 10. Filling Portlets - How to fill regions of a web page with XQuery 11. Filtering Nodes - How to use the identity transform to filter out nodes 12. Limiting Child Trees - You have a tree of information and you want to "prune" only at a specific level 13. Higher Order Functions - Passing functions as arguments to functions 14. Timing Fibonacci algorithms - A couple of Fibonacci algorithms and timing display 15. Using Intermediate Documents - Analysis of a MusicXML file 16. Formatting Numbers - using picture formats to format numbers 17. Uploading Files - how to upload files using HTML forms 18. TEI Concordance - How to build a TEI-based concordance

Search1. Introduction to XML Search - An overview of XML search terminology 2. Basic Search - A simple search page 3. Searching,Paging and Sorting - Searching and Viewing search results 4. Keyword Search - full text search with Google-style results 5. Employee Search - an Ajax example 6. Incremental Search of the Chemical Elements - with Ajax 7. Lucene Search - using eXist's Lucene-based fulltext search 8. Incremental Searching - working with a JavaScript client to perform incremental search 9. Advanced Search - creating complex searches using multiple search fields 10. Open Search - creating an OpenSearch file to describe your search page 11. Auto-generation of Index Config Files - scripts to automatically generate the index configuration file

XQuery

3

Interaction1. 2. 3. 4. Adder - Creating a web service that adds two numbers. Simple XForms Examples Navigating Collections - an example of an AJAX browser Sending E-mail - How to send an e-mail message from within an XQuery

Creating Custom ViewsThese examples use reflection on the structure of an XML document using name() to implement generic functions for XML transformations. 1. HTML Table View - A generic HTML table representation 2. Tree View - A generic HTML tree representation 3. Grouping Items - how to group items in a report

Transforming Complex XML DocumentsXQuery has many features that allow you to transform XML and create full document-style transformation libraries. Unlike traditional "database" documents, complex XML documents have "complex content" that includes in-line elements in unpredictable order. This section provides a foundation for these transformations based on using the XQuery typeswitch functions. Typeswitch function transformations replace XSLT transforms but can also access indexes for very fast transforms of large collections. 1. Typeswitch Transformations Using the typeswitch function for document-style transforms. 2. Transformation idioms Handling transformation tasks 3. Generating Skeleton Typeswitch Transformation Modules Using XQuery to generate a skeleton module for typeswitch-based document transformation 4. Web XML Viewer Using the typeswitch function to transform an XML document to HTML

Paginated ReportsUnlike HTML pages, paginated reports use the concept of text flows between pages. These examples show you how to convert raw XML into high-quality PDF files suitable for printing. The examples use a markup standard called XSL-FO for "Formatted Objects" 1. Installing_the_XSL-FO_module - update your 1.4 configuration to get the current software from the Apache web site 2. Generating PDF from XSL-FO files - Converting XML-FO to PDF files 3. XSL-FO Tables - Generating XSL-FO tables from XML files 4. XSL-FO Images - Embedding images in generated (PDF) files

XQuery

4

Content Publishing1. Publishing Overview - How to transfer a document from an internal intranet server to a public web site 2. Publishing to Subversion - How to transfer a document from an internal intranet to a public SVN server using SSL and digest authentication

XML Document Comparison and Merging1. 2. 3. 4. 5. 6. Compare two XML files - using the eXist compare() function to test to see if two XML files are exactly the same XML Differences - displaying the difference between two XML files Compare with XQuery - Using XQuery to Compare Lists Time Comparison with XQuery - Using XQuery to Compare Dated Items Synchronizing Remote Collections - Using lastModified time stamps to see what items have changed Finding Duplicate Documents - Using a hash function to find duplicate documents

Time Based Queries1. Time Based Queries - using dates and times to limit search results 2. Timing a Query - profiling how long a query takes

XML document kindsTEI documentsText Encoding Initiative. 1. TEI Concordance - How to build a TEI-based concordance 2. TEI Document Timeline - Using Simile Timeline to visualize a TEI document

DocBook Documents1. DocBook to HTML 2. DocBook to PDF 3. DocBook to ePub

OpenOffice1. OpenOffice to HTML

Office Open XML1. Office Open XML

XQuery

5

XML Schemas1. XML Schema to Instance 2. XML Schema to XForms 3. XML Schema to SVG

Processing Special Characters1. Special Characters - dealing with newlines and other special characters.

XQuery and other languagesMusicXML1. Using Intermediate Documents Analysing MusicXML documents 2. MusicXML to Arduino

Language ComparisonsPython1. XQuery and Python

SQL1. XQuery SQL Module - Calling SQL from within your XQuery 2. XQuery from SQL - Using XQuery to access a classic Relational database - Employee/Department/Salary

RDF/OWL1. List OWL Classes - A simple XQuery script that will display all the OWL classes in an OWL file

Language combinationExcel1. Excel and XML

JavaScript1. 2. 3. 4. Navigating Collections - basic AJAX Employee Search - basic AJAX Incremental Search of the Chemical Elements - AJAX DOJO data - basic JSON

SQL1. XML to SQL

XQuery

6

XHTML + Voice1. Simple RSS reader 2. XHTML + Voice Twitter Radio for Opera

XSLT1. XQuery and XSLT Executing an XSLT transform from within XQuery

Data MashupsAuthentication1. Basic Authentication - Logging in to a remote web server using HTTP Basic Authentication 2. Digest Authentication - Logging in to a remote web server using HTTP Digest Authentication 3. OAuth - A standard for protecting a set of user-owed data within a web service

Wikipedia interaction1. 2. 3. 4. Wikipedia Page scraping Wikipedia Lookup Wikipedia Events RSS Wiki weapons page

Wikibook applications1. Wikibook index page 2. Wikibook list of code links

Visualization1. 2. 3. 4. Graph Visualization Dataflow diagrams Sequence Diagrams Example Sequencer - Step-by-step tutorial

Google ChartsAlthough the Google Charts functions only work when you are connected to the Internet, these examples show that XQuery is an ideal tool for converting XML data into charts. 1. 2. 3. 4. Google Charts Using XML and XQuery to generate Google Charts using REST Google Chart Sparkline - A demonstration of how to create a chart using the Google Charts API Google Chart Bullet Bar - A demonstration of how to a dashboard bullet bar using the Google Charts API Histogram of File Sizes - An XQuery report that generates a histogram of file sizes

There are also sample XForms that can be used to create front-ends in the XForms Tutorial and Cookbook [2]

XQuery

7

Digital DashboardsDigital dashboards are single screens that compress a great deal of information into a single web page. This section will leverage many of the Google Charts examples from the prior section. 1. Dashboard Architecture - How to design dashboards that have fast response times

Page ScrapingPage scraping is the process of extracting well-formed XML data from any HTML web page. When creating mashup applications this is also known as the harvesting process. 1. 2. 3. 4. 5. 6. 7. 8. Overview of Page Scraping Techniques Page scraping and Yahoo Weather UK shipping forecast BBC Weather Forecast Page scraping and Mashup Simple RSS reader Multiple page scraping and Voting behaviour Link gathering

9. REST interface definition 10. Caching and indexes

Mapping1. 2. 3. 4. 5. Google Geocoding String Analysis#Location_Mapping Mapping Car Registrations Flickr GoogleEarth Nationalgrid and Google Maps SMS tracker

Timelines1. Creating a Timeline - Creating a simple timeline view of events 2. Timelines of Resource - Using creation and modification dates to create timelines 3. TEI Document Timeline - Creating a timeline of all dates within a single TEI document

The Semantic Web1. DBpedia with SPARQL - Football teams 2. DBpedia with SPARQL and Simile Timeline - Album Chronology Creating a timeline of album releases using data from Wikipedia 3. DBpedia with SPARQL - Stadium locations 4. The Emp-Dept case study 1. XML to RDF 2. SPARQL Tutorial 3. SPARQL interface 5. Graphing Triples 6. SPARQLing Country Calling Codes 7. Southampton Pubs 8. Alphabet Poster

XQuery 9. Simile Exhibit Browser visualizations using the Simile JavaScript libraries 10. Latent Semantic Indexing Finding the semantic distance between documents

8

Development Tools1. Sitemap for Content Management System XQuery functions can easily perform many common web site content management functions 2. Uptime monitor/ use XQuery to monitor a remote web service 3. XQuery IDE - XQuery Integrated development environment 4. Image Library - using an XQuery to preview your images 5. XML Schema to Instance - XQuery function to generate a sample XML instance from an XML Schema file (.xsd) 6. Lorum Ipsum text - generating sample text for inserting into test page layouts 7. XQuery and XML Schema - Generating an XML instance document 8. Generating XQDocs - Automating the generation of XQuery documentation for Modules and Functions 9. XqUSEme [3] - Firefox extension to allow XQueries including against the loaded document (even against originally non-XML (poorly formed) HTML).

Validation1. Validating a document - Validate a document with an XML Schema 2. Validation using a Catalog - Using a Catalog file to validate documents 3. Validating a hierarchy -

Path Analysis1. All Paths - A report of all paths in a document or collection 2. All Leaf Paths - A report of all leaf paths in a document or collection

Security1. 2. 3. 4. Login and Logout - How to log users in and log them out URL Driven Authorization How to use URL rewriting to check for valid users Digital Signatures - How to use a custom module to use the XML Digital Signature standards Changing Permissions on Collections and Resources - how to change permissions on collections and resources

Case Studies1. 2. 3. 4. 5. 6. 7. 8. Fizzbuzz Project Euler Topological Sort Slideshow Sudoku Pachube feed World Temperature records - conversion of text data formats to XML, indexing and data presentation UWE StudentsOnline

XQuery

9

eXist db specific Functions and ConfigurationConfigurationInstalling modules1. Installing the XSL-FO module

Setting HTTP Headers1. Setting HTTP Headers

ModulescompressionFunction Reference [4] 1. Get zipped XML file 2. Unzipping an Office Open XML docx file - Uncompressing and storing a docx file

ftp clientThis module allows you to interact with a remote FTP server on a remote system. It includes functions for listing, getting and putting files. 1. FTP Client

httpclientFunction Reference [5] 1. Digest Authentication 2. UK shipping forecast

luceneFunction Reference [6] Help [7] 1. Lucene_Search

mailFunction Reference [8] 1. Sending E-mail 2. Basic Feedback Form

XQuery

10

math1. Using the Math Module

requestFunction Reference [9] Function examples [10] 1. 2. 3. 4. 5. 6. Getting URL Parameters/ Getting POST Data/ Checking for Required Parameters Manipulating URIs Parsing Query Strings Adder simple client-server interaction

schedulerFunction Reference [11] Help [12] 1. XQuery Batch Jobs

sequencesFunction Reference [13] 1. Sequences Module - three additional functions (map, fold and filter)

sessionFunction Reference [14] 1. Basic Session Management - the basics of session management including getting a setting session variables

subversionFunction Reference [15] 1. Subversion - how to update a subversion repository from within XQuery using the subversion client

transformFunction Reference [16] 1. String_Analysis

utilFunction Reference [17] 1. 2. 3. 4. 5. 6. 7. Registered Modules : util:registered-modules() Registered Functions : util:registered-functions() Dynamic Module Loading : util:import-module(), util:eval() Higher Order Functions : util:function(), util:call() Timing Fibonacci algorithms : util:function(), util:call(), util:system-time() XMP data : util:binary-doc(), util:binary-to-string(), util:parse() Basic Authentication : util:string-to-binary(), httpclient:get()

XQuery

11

validationFunction Reference [18] Help [19] 1. Validating a document

xmldbFunction Reference [20] 1. Saving_and_Updating_Data 2. Splitting_Files

xqdocFunction Reference [21] 1. Generating xqDoc-based XQuery Documentation

xslfoXSL-FO (Formatted Objects) is a way of converting XML into PDF. Function Reference [22] 1. 2. 3. 4. 5. Installing the XSL-FO module - setting up your XSL-Module within eXist Generating PDF from XSL-FO files - generating PDF from a FO file XSL-FO Tables - adding tables to your PDF XSL-FO Images - adding images to your PDF XSL-FO SVG - adding SVG images to your PDF

Triggers1. Using Triggers to Log Events - how to set up a trigger to log store, update and remove events on a collection 2. Using Triggers to assign identifiers - how to use triggers to assign identifiers to new documents or new nodes 3. Sending E-mail Email is one way to notify when a trigger has fired

XQuery Updates1. Inserting and Updating Attributes 2. Updates and Namespaces - How updates can change serialization

XQuery

12

URL Rewriting1. URL Rewriting Basics How to make your URLs look nice

Apache Ant Tasks1. Reindex a Collection

General guidance eXist Crib sheet

AppendixesSystems that Support XQueryUsing native and hybrid XML databases that implement XQuery 1. BaseX - Native open source XML Database with visual frontend 2. DataDirect XQuery - Java XQuery engine supporting relational, EDI, flat files and XML input/output 3. eXist - Open source native XML database 4. DB2 pureXML - DB2 9.1 includes the pureXML feature 5. MarkLogic Server - MarkLogic Server commercial XML Content Server 6. Microsoft SQL Server 2005 7. NetKernel - NetKernel 8. Oracle Berkeley DB XML - Open source embedded storage management 9. Oracle XML DB - Oracle Server 11g includes the XML DB (XDB) feature 10. Sedna - Open source native XML Database 11. Stylus Studio - XQuery mapping/editing/debugging, ships with Saxon (and SA) and DataDirect XQuery 12. EMC xDB - EMC Documentum xDB commercial native XML database 13. XQilla - Open source XQuery library and command line utility 14. Zorba - Open source XQuery engine C++ implementation with C, Java, Php, Python, Ruby library bindings and command line utility 15. Qizx - Open source and pro XQuery engine Java implementation

XQuery

13

Debugging XQuery1. Gotchas - some pitfalls 2. Ah-has/ - some ah-ha moments

Other sourcesFunction Libraries1. FunctX XQuery Function Library [23] by Priscilla Walmsley

Discussion Groups1. XQuery General [24]

Indexes Page index [25] - generated Index of Application Areas - edited Key to symbols: indicates an XQuery/Best practice

References[1] http:/ / creativecommons. org/ licenses/ by-sa/ 2. 5/ [2] http:/ / en. wikibooks. org/ wiki/ XForms/ Google_Charts [3] https:/ / addons. mozilla. org/ en-US/ firefox/ addon/ 5515 [4] http:/ / demo. exist-db. org/ exist/ functions/ compression [5] http:/ / demo. exist-db. org/ exist/ functions/ httpclient [6] http:/ / demo. exist-db. org/ exist/ functions/ lucene [7] http:/ / exist-db. org/ lucene. html [8] http:/ / demo. exist-db. org/ exist/ functions/ mail [9] http:/ / demo. exist-db. org/ exist/ functions/ request [10] http:/ / www. cems. uwe. ac. uk/ xmlwiki/ eXist/ request/ requestProperties. xq?a=6& b=7#xxxxx [11] http:/ / demo. exist-db. org/ exist/ functions/ scheduler [12] http:/ / www. exist-db. org/ scheduler. html [13] http:/ / demo. exist-db. org/ exist/ functions/ sequences [14] http:/ / demo. exist-db. org/ exist/ functions/ session [15] http:/ / demo. exist-db. org/ exist/ functions/ svn [16] http:/ / demo. exist-db. org/ exist/ functions/ transform [17] http:/ / demo. exist-db. org/ exist/ functions/ util [18] http:/ / demo. exist-db. org/ exist/ functions/ validation [19] http:/ / www. exist-db. org/ validation. html [20] http:/ / demo. exist-db. org/ exist/ functions/ xmldb [21] http:/ / demo. exist-db. org/ exist/ functions/ xqdoc [22] http:/ / demo. exist-db. org/ exist/ functions/ xslfo [23] http:/ / www. xqueryfunctions. com/ xq/ [24] http:/ / news. gmane. org/ gmane. text. xml. xquery. general [25] http:/ / www. cems. uwe. ac. uk/ xmlwiki/ util/ wikiindex. xq?book=XQuery

Advanced Search

14

Advanced SearchMotivationYou have multiple fields that you would like to search on. You want to allow users to optionally search on specific fields and perform a boolean "AND" when multiple fields are used. For example you may have a database of people. Each person has a first name, last name, e-mail and phone. You want to allow users to search on any single field or multiple fields together. If two fields are entered only records that match both fields will be returned.

MethodWe will use a standard HTML form with multiple input and selection fields. We will check each incoming search request for each parameter and if the parameter is not null we will concatenate a single query with many predicates and then evaluate it using the util:eval() function.

Example XML Data SetIn the following example we will use an XML file that contains list of people. The format will be the following: 123 John Smith (123) 456-7890 [email protected] faculty 456 Sue Jones (123) 654-0123 [email protected] staff

Background on PredicatesIf you have a single "where clause" (called a predicate) you can always this predicate to the end of an XPath expression. For example the following FLWOR expression will return all person records in the system: for $person in collection('/db/apps/directory')//person return $person You can now restrict this to only include faculty by adding a predicate:

Advanced Search for $person in collection('/db/apps/directory')//person[type='faculty'] return $person You can now search for all faculty with a first name of "mark" buy just adding an additional predicate:for $person in collection('/db/apps/directory')//person[type='faculty'][firstName='mark'] return $person

15

Sample Search Form

Sample HTML code for advanced search formThe following is an HTML form section for this form. First Name:
Last Name:
E-Mail:
Phone:
Primary Type: - Select - Staff Faculty

Advanced Search Students
When the user adds a name of "John" to the first name field and selects a type of "staff" and then the submit query button is pressed the following is an example of the URL created by this form:advanced-search.xq?firstname=John&lastname=&email=&phone=&type=staff&Submit=Submit+Query

16

Note that most of the fields are null. Only firstname and type have a value to the right of the equal sign.

Sample Search ServiceThe search service will have the following code sections.

Getting the URL parametersThe following code fragment will get the URL parameters from the incoming URL request and assign them to XQuery variables. let let let let let $firstname := lower-case(request:get-parameter('firstname', '')) $lastname := lower-case(request:get-parameter('lastname', '')) $email := lower-case(request:get-parameter('email', '')) $phone := lower-case(request:get-parameter('phone', '')) $type := lower-case(request:get-parameter('type', ''))

Note that each of the incoming parameters is first converted to lowercase before any comparisons are done.

Building the Predicate StringsWe are now ready to start building our predicates. Since many of the fields will be empty we will only construct a predicate if the variable exists. let $firstname-predicate := if ($firstname) then concat('[lower-case(firstname/text())', " = '", $firstname, "']") else () let $lastname-predicate := if ($lastname) then concat('[lower-case(lastname/text())', " = '", $lastname, "']") else () let $email-predicate := if ($email) then concat('[lower-case(email/text())', " = '", $email, "']") else () let $phone-predicate := if ($phone) then concat("[contains(phone/text(), '", $phone, "')]") else () let $type-predicate := if ($type) then concat('[type/text()', " = '", $type, "']") else ()

For the firstname, lastname, and email we are comparing the incoming parameter with the lowercase string in the XML file. With the phone number we are using the contains() function to return all records that have a string somewhere in the phone number. The type is using an exact match since both the case of the data and keyword are

Advanced Search known precisely. The most challenging aspect of this program is learning how to get the order of the quotes correct. In general I use single quotes for enclosing static strings unless that string itself must contain a single quote. Then we use double quotes. The most difficult part is to assemble a string such as [type/text() = 'staff'] and to remember to put the single quotes around the word staff. If you can figure this out the rest will be easy. If you are having trouble you can also break the concat into multiple lines: concat( '[type/text()', " = '", $type, "']" ) Where each line clearly must start and end with the same type of quote.

17

Concatenating the QueryTo create an eval string we just need to create a single long string starting with the collection and add each of the predicates. If there was no argument the predicate strings will be null. let $eval-string := concat ("collection('/db/apps/directory/data')//person", $firstname-predicate, $lastname-predicate, $email-predicate, $phone-predicate, $type-predicate )

The query with just a lastname and type would then look like this: collection('/db/apps/directory/data')//person[lower-case(firstname/text()) = 'John'][lower-case(type/text()) = 'faculty'] Note that some advanced system will modify the order of the predicates based on the most likely to narrow the search. Since there are fewer records with the first name John than there are faculty it is always more efficient to put the first name before the type. This means that fewer nodes need to be moved from hard disk into RAM and the query will execute much faster.

Executing the QueryThe execution of the query is done by passing the eval string to the util:eval function. let $persons := util:eval($eval-string)

Displaying the ResultsWe are now ready to display all of the results. We do this by creating a FLWOR statement for each person and returning a element for each hit. The elements each have single link with the lastname, firstname and type as the link content. When the user clicks on each link an item viewer is used and the ID of the person is passed to the item viewer.

Advanced Search for $person in $persons let $id := $person/id/text() let $lastname := $person/lastname/text() let $firstname := $person/firstname/text() order by $lastname, $firstname return {$lastname}, {$person//firstname/text()} {' '} {$person/type/text()}

18

NGram Searchingin your conf.xml module make sure the following line is uncommented:

Here is the page on NGram elements in your collection.xconf file: NGram Configuration File [1] After you edit then reindex. You can now use any of the following functions: NGram Functions [2]

AcknowledgmentsThis example has been provided by Eric Palmer and his staff at the University of Richmond, USA.

References[1] http:/ / exist-db. org/ ngram. html [2] http:/ / demo. exist-db. org/ exist/ functions/ ngram

All Leaf Paths

19

All Leaf PathsMotivationYou want to generate a list of all leaf paths in a document or document collection. This process is very useful to get to know a new data set. Specifically you will find that the leaf elements in an XML file carry much of the data in a data-style markup. These leaf elements frequently are used to carry the most semantics or meaning within the document. They for the basis for a semantic inventory of the document. That is each leaf element should be able to be associated with a data definition. Leaf elements are also good targets for indexing within your index configuration file.

MethodWe will use the functx leaf-elements() function functx:leaf-elements($nodes*) xs:string* This function takes as input, one or more nodes and returns an array of strings.

Example OutputFor the demo play Hamlet that is included in the eXist demo set the file /db/shakespeare/plays/hamlet.xml will generate the following output: PLAY TITLE FM P PERSONAE PERSONA PGROUP GRPDESCR SCNDESCR PLAYSUBT ACT SCENE STAGEDIR SPEECH SPEAKER LINE

Source Code to leaf-elementsdeclare namespace functx = "http://www.functx.com"; declare function functx:leaf-elements ($root as node()?) as element()* { $root/descendant-or-self::*[not(*)] };

All Leaf Paths This query uses the descendant-or-self::* function with the predicate [not(*)] to qualify only elements that do not have child nodes.

20

Example XQueryxquery version "1.0"; declare namespace functx = "http://www.functx.com"; declare function functx:distinct-element-names($nodes as node()*) as xs:string* { distinct-values($nodes/descendant-or-self::*/local-name(.)) }; let $doc := doc('/db/shakespeare/plays/hamlet.xml') let $distinct-element-names := functx:distinct-element-names($doc) let $distinct-element-names-count := count($distinct-element-names) return { for $distinct-element-name in $distinct-element-names order by $distinct-element-name return {$distinct-element-name} }

Adding AttributesYou can also run a query that will get all the distinct attributes. Attributes are all considered leaf data types since they can never have child elements. declare function functx:distinct-attribute-names($nodes as node()*) xs:string* { distinct-values($nodes//@*/name(.)) }; as

This query says in effect to "get all the all the distinct attribute names in the input nodes". For the MODS demo file: doc('/db/mods/01c73f2b05650de2e6124d9d113f40be.xml') You will get the following attributes: 1. type 2. encoding 3. authority

All Leaf Paths

21

ReferencesDocumentation [1] on xqueryfunctions.com web site.

References[1] http:/ / www. xqueryfunctions. com/ xq/ functx_leaf-elements. html

All PathsMotivationYou want to generate a list of all unique path expressions to a document. This process is very useful to quickly get familiar with a new data set. It is also important to make sure that your document-style transforms are accessing all the elements. This process can also be used as a basis for generating index files for a new data set.

Example OutputPaths the list of unique paths for a sample file from the Shakespeare Demos on the eXist demo system at /db/shakespeare/plays/hamlet.xml would generate the following results. PLAY PLAY/TITLE PLAY/FM PLAY/FM/P PLAY/PERSONAE PLAY/PERSONAE/TITLE PLAY/PERSONAE/PERSONA PLAY/PERSONAE/PGROUP PLAY/PERSONAE/PGROUP/PERSONA PLAY/PERSONAE/PGROUP/GRPDESCR PLAY/SCNDESCR PLAY/PLAYSUBT PLAY/ACT PLAY/ACT/TITLE PLAY/ACT/SCENE PLAY/ACT/SCENE/TITLE PLAY/ACT/SCENE/STAGEDIR PLAY/ACT/SCENE/SPEECH PLAY/ACT/SCENE/SPEECH/SPEAKER PLAY/ACT/SCENE/SPEECH/LINE PLAY/ACT/SCENE/SPEECH/STAGEDIR PLAY/ACT/SCENE/SPEECH/LINE/STAGEDIR

Note that these path expressions are sorted in document order, that is the order that the path first appeared in a document. So you can see that the cast list in the PERSONAE appear before the ACT/SCENE elements. The output can also be sorted in alphabetical order.

All Paths

22

MethodWe will use the functx libraries. In particular the function: functx:distinct-element-paths($nodes) takes as its input a node and returns a sequence of strings of the path expressions. See Documentation on xqueryfunctions.com [1]

distinct-element-paths functionxquery version "1.0"; declare namespace functx = "http://www.functx.com"; declare function functx:path-to-node($nodes as node()*) as xs:string* { $nodes/string-join(ancestor-or-self::*/name(.), '/') }; declare function functx:distinct-element-paths($nodes as node()*) as xs:string* { distinct-values(functx:path-to-node($nodes/descendant-or-self::*)) }; declare function functx:sort($seq as item()*) as item()* { for $item in $seq order by $item return $item }; let $in-xml := collection("NAMEOFCOLLECTION") return functx:sort(functx:distinct-element-paths($in-xml))

The heart of this query is the single expression: ancestor-or-self::*/name(.) Which says in effect "get me the element names of all the nodes in the document". The next step is to turn this list into a list of distinct element paths. This is done by the function functx:distinct-element-paths()

All Paths

23

Working with a single test documentuse the document()

Working with a document collectionuse collection() function

AcknowledgmentsDavid Elwell posted this suggestion on the open-exist list on July 22 of 2010

References[1] http:/ / www. xqueryfunctions. com/ xq/ functx_distinct-element-paths. html

Alphabet PosterThis toy programme creates alphabet posters using images from Wikipedia, located via dbpedia. It is described in a blog entry [1]

Script(: This script creates a picture alphabet based on a list of words.

The pictures are from wikipedia, found via dbpedia.

This was created for alphabet.

Charlie Taylor (age 5 ) for his animal

@parameter @parameter

title - The title string for the poster alphabet - list of comma-separated word , unordered

@parameter cols - the number of columns in the table layout @parameter action : poster - generate the poster, editor generate

the editor for the data @author Chris Wallace @date 2008-10-22

:) declare namespace r = "http://www.w3.org/2005/sparql-results#";

declare variable $alphabet := request:get-parameter("alphabet","Ant,Bat"); declare variable $words := tokenize(normalize-space($alphabet)," *, *"); declare variable $title := request:get-parameter("title","Charlie's Animal Alphabet");

declare variable $cols := xs:integer(request:get-parameter("cols",4)); declare variable $action := request:get-parameter("action","edit");

Alphabet Poster

24

declare variable

$query := "

PREFIX : PREFIX foaf: SELECT * WHERE { :Hedgehog } "; foaf:depiction ?img.

declare function local:execute-sparql($query as xs:string) let $sparql :=

{

concat("http://dbpedia.org/sparql?format=xml&default-graph-uri=http://dbpedia.org&query=", encode-for-uri($query) ) return }; doc($sparql)

declare function local:picture($animal as xs:string )

as xs:string {

let $queryx := replace($query,"Hedgehog",replace($animal," ","_")) let $result:= local:execute-sparql($queryx) return string($result//r:result[1]//r:uri) };

declare function local:cell ($animal as xs:string , $picture as xs:string) as element(td) { let $letter := substring($animal,1,1) return {$letter} is for {$animal}

};

Alphabet Posterdeclare function local:poster() as element(div) { {$title}

25

{let $letters := for $animal in $words let $picture := local:picture($animal) order by $animal return local:cell($animal,$picture) let $nrows := xs:integer(ceiling(count($letters) div $cols)) return {for $row in (1 to $nrows) return {for $col in (1 to $cols) let $letter := $letters[position()= ($row - 1 ) * $cols + $col] return if ($letter) then $letter else } } } };

declare function local:editor() as element(form) { Title of Alphabet Number of Columns Alphabet words, unordered, separated by
{$alphabet} }; ,

declare option exist:serialize "method=xhtml media-type=text/html";

Alphabet Poster Alphabet Poster - {$action} { if ($action = "poster") then ( [edit] , local:poster() ) else if ($action="edit")

then local:editor() else () }

References[1] http:/ / thewallaceline. blogspot. com/ 2008/ 10/ grandson-charlie-age-nearly-6-rang. html

Auto-generation of Index Config Files

27

Auto-generation of Index Config FilesMotivationYou want to automatically generate a index configuration file based on instance or XML schema data. Creation of an index configuration file is difficult for new users. To help new users get started it is frequently benefitial to generate a sample collection.xconf file for these users based on simple analysis of sample instance data or XML Schemas that are provided by the users.

Index TypesThere are several types of indexes you may want to create. Range indexes are very useful when you have identifiers or you want to sort results based on element content. Fulltext indexes are most frequently used of language text that contains full sentences with punctuation.

FullText IndexesThe following is some example code on how one might do this. Lucene fulltext indexes are most useful when they index fulltext sentences. One approach is to scan an instance document for full sentences looking for longer strings with punctuation. Although a full implementation would involve the inclusion of a "Natural Language Processor" library such as Apache UIMA, we can begin with some very simple rules. Here are some sample steps in the process for non-mixed-text content. Mixed text can also be done but the steps are more complex: 1. 2. 3. 4. get a list of all elements in a sample index file classify the elements according to if they have simple or complex content if they have simple content, look for sentences (spaces and puncuation) for each element that has fulltext create a lucene index

Sample Code for Namespace GenerationThis creates an index on with every namespace that is used in the collection. let $defaultNamespaces := for $value in distinct-values( for $doc in collection($dataLocation) let $ns := namespace-uri($doc/*) return if ($ns) then $ns else () ) return element ns { $value } let $index1 := "" let $index4 := for $ns in $defaultNamespaces let $prefix := concat('ns',index-of($defaultNamespaces,$ns)) return concat('') let $index5 := "" let $index := util:parse(string-join(($index1,$index2,$index3,$index4,$index5),"")) let $status := xmldb:store($indexLocation,"collection.xconf",$index) let $result :=xmldb:reindex($dataLocation)

28

BackgroundXQuery and Functional ProgrammingXQuery is an example of a functional programming language. Like other functional languages, XQuery variables are immutable, meaning that you can set them once but never change them after that. XQuery functions do not have "side effects" meaning that they do not change data that is not specifically passed to them. Functional programming has recently gained popularity with the rise of the MapReduce algorithms recently popularized by Google. Google's ability to leverage tens of thousands of CPUs in its data center has shown that functional languages are in many ways superior to procedural languages. But many of the benefits of functional programming go back to mathematical formalisms of the 1930s, including the lambda calculus and the -recursive functions. Although the XQuery 1.0 W3C specification does not allow a function to be passed as an argument to a function, most implementations such as eXist support this, so technically the eXist implementation of XQuery is a true functional language but the W3C standard is not. However, XQuery 1.1 is to allow function items as data[1] while A history of functional programming is available at Functional Programming [2]. This article has an excellent historical background on functional programming and why functional programs are ideal for a server environment where reliability is critical.

Background

29

XQuery as a w3c StandardIn 1998 Jonathan Robie and Joe Lapp (then the principal architect of WebMethods) created a new query language designed specifically to query XML files called XQL In 1998, two query languages, XQL and XML-QL got a lot of interest within the W3C and a working group for XML-based querying languages was formed. In 1998 the World Wide Web consortium hosted a conference on query languages[3]. This conference gathered XML and query language experts from around the world and from many fields. 66 "Position Papers" were presented. The result was a very large knowledge base of use cases and proposals that began as a basis for a future standardized query language. The working group selected around 90 use cases and compared the ability of seven advanced query languages to execute them. None of the seven were perfect. Each had some defects. The working group took the best part of each of the seven languages and created the XQuery standard. The XSLT language reached recommendation status in 1999. But there were many people who felt that XSLT was too difficult to learn, and because of the XML syntax, it was very unfamiliar for many software developers. People with an SQL background had a difficult time understanding how to learn XSLT.

XQuery and SQLStudies have shown that people familiar with SQL can quickly learn XQuery. Once developers understand the structure of the FLWOR statement, many SQL concepts such as sorting and selecting distinct values are easily learned.

XQuery and XSLTMany developers once considered XSLT template-style transforms ideal for transforming documents and XQuery ideal for querying more structured XML data such as a collection of book metadata. Recent work with typeswitch-style transforms have shown that XQuery modules and functions can be used to create document-style transforms that rival most XSLT functions. And because many XQuery systems leverage document indexes they can be considerably faster than XSLT transforms that were never designed to use indexed XML structures.

ReferencesW3C Papers from 1998 on XML Query Languages [4][1] [2] [3] [4] http:/ / www. w3. org/ TR/ xquery-11/ #id-inline-func http:/ / en. wikibooks. org/ wiki/ Computer_programming/ Functional_programming http:/ / www. w3. org/ TandS/ QL/ QL98/ Overview. html http:/ / www. w3. org/ TandS/ QL/ QL98/ pp. html

Basic Authentication

30

Basic AuthenticationMotivationYou want to use a very basic login process over a secure network such as a secure Intranet or over an SSL connection.

MethodWe will used the base64 encoding and decoding tools to generate the right strings. xquery version "1.0"; let $user := 'Aladdin' let $password := 'open sesame' let $credentials := concat($user, ':', $password) let $encode := util:string-to-binary($credentials) return {$user} {$password} {$encode} Returns the following: Aladdin open sesame QWxhZGRpbjpvcGVuIHNlc2FtZQ==

Sample HTTP GET using Basic Authenticationxquery version "1.0"; declare function local:basic-get-http($uri,$username,$password) { let $credentials := concat($username,":",$password) let $credentials := util:string-to-binary($credentials) let $headers := return httpclient:get(xs:anyURI($uri),false(), $headers) }; let $host := "http://localhost:8080" let $path := "/exist/rest/db/apps/terms/data/1.xml" let $uri := concat($host, $path)

Basic Authentication let $user := 'my-login' let $password := 'my-password' return local:basic-get-http($uri,$username,$password)

31

References http://en.wikipedia.org/wiki/Basic_access_authentication Wikipedia Entry on Basic Authentication

Basic Feedback FormMotivationYou want to gather feedback from visitors.

ImplementationA simple HTML form gathers suggested improvements and an email address. The suggestion is emailed to one of the authors and an acknowledgment sent to the submitter. Here the default send-mail client on the eXist implementation at UWE, Bristol is used.

XQuery scriptxquery version "1.0";

(: A simple Feedback form using the eXist mail module :)

import module namespace mail="http://exist-db.org/xquery/mail"; declare option exist:serialize "method=xhtml media-type=text/html";

let $comment:= normalize-space(request:get-parameter("comment","")) let $email := normalize-space(request:get-parameter("email","")) return Feedback on the XQuery Wikibook Feedback on the XQuery Wikibook Please let us know how this Wikibook could be improved.

Your email address {if ($email ne "" and $comment ne "") then let $commentMessage :=

Basic Feedback Form{$email} [email protected] Wikibook Feedback {$comment} let $ackMessage := {$email} [email protected] Wikibook Feedback Many thanks for your feedback - we appreciate your interest in this collaborative work. let $sendcomment := mail:send-email($commentMessage,(),()) let $sendack := mail:send-email($ackMessage,(),()) return if ($sendcomment and $sendack) then Feedback You suggested that the XQuery Wikibook could be improved by:
{$comment}.
Thanks for the feedback. else Something went wrong - please try again else if ($comment ne "") then Please provide an email address so that we can let you know of progress on your suggestion. else () }

32

Feedback Form [1]

References[1] http:/ / www. cems. uwe. ac. uk/ xmlwiki/ eXist/ mail/ feedback. xq

Basic Search

33

Basic SearchMotivationYou want to create a basic HTML search page and search service.

MethodWe will create two files. One is an HTML form and the other is a RESTful search service that takes a single parameter from the URL which is the search query. The search service will search a collection of XML files. Here is the base path to our test search collection: /db/test/search The data to be searched will be in the following collection: /db/test/search/data In "Browse Collections" in the Admin interface, create the collection "test"; create the collection "search" under it; lastly, create the collection "data" under "search". Upload the two XML documents listed under "Sample Data" to "data"; upload "search-form.xq" and "search.xq" to "search" (instead of uploading, you can Save to URL, using oXygen, or use the Webstart client).

Search Form/db/test/search/search-form.xqWe will create a basic HTML form that has just one input field for the query. declare option exist:serialize "method=xhtml media-type=text/html indent=yes"; let $title := 'Basic Search Form' return {$title} {$title} Keyword Search:

Basic Search Note that the action will pass the value from the form to a RESTful service. The only parameter will be "q", the query string.

34

Search ServiceThe following file should be placed in /db/test/search/search.xq

/db/test/search/search.xqxquery version "1.0"; declare option exist:serialize "method=xhtml media-type=text/html indent=yes"; let $title := 'Simple Search RESTful Service' let $data-collection := '/db/test/search/data' (: get the search query string from the URL parameter :) let $q := request:get-parameter('q', '') return {$title} Search Results Searching for: {$q} in collection: {$data-collection} { for $fruit in collection($data-collection)/item[fruit/text() = $q] return {data($fruit)} }

Running your SearchTo test your search service from a URL, copy the following into the browser navigation toolbar: http:/ / localhost:8080/ exist/ rest/ db/ test/ search/ search. xq?q=apple You should see the following result:

To drive this service from a form, click the following link or copy it into your browser navigation toolbar:

Basic Search http:/ / localhost:8080/ exist/ rest/ db/ test/ search/ search-form. xq

35

Sample Data for /db/test/search/data/db/test/search/data/1.xml apple

/db/test/search/data/2.xml banana

Basic Session ManagementMotivationYou want to associate some behavior of your web application with a users's login session.

MethodThere are several functions provided by eXist and other web servers to manage information associated with a login session. xquery version "1.0"; let $session-attributes := session:get-attribute-names() return {for $session-attribute in $session-attributes return {$session-attribute} } Before you add any session attributes this might return only a single variable such as:

Basic Session Management _eXist_xmldb_user xquery version "1.0"; (: set the group and role :) let $set-dba-group := session:set-attribute('group', 'dba') let $set-role-editor := session:set-attribute('role', 'editor') let $session-attributes := session:get-attribute-names() return {for $session-attribute in $session-attributes return {$session-attribute} } This will return the following attributes: group role _eXist_xmldb_user These attributes will remain associated with the user until the user logs out or their session times out, typically after 15 minutes of inactivity. One sample use of session attributes is to keep track of user interface preferences. For example if a user wants to have their data sorted by a person's zip code you can add that to their session variable. let $set-sort := session:set-attribute('sort', 'zip-code')

36

BBC Weather Forecast

37

BBC Weather ForecastBBC Weather forecastsSome weather data is available from the BBC as RSS feeds. Currently this includes the current conditions [1] and the 3-day forecast [2]. Lacking a standard set of tags fro weather properties, the conditions are expressed in a string and string parsing is needed to access the elemental data. For other forecasts such as the 24-hr and 5 day which are not available as RSS we must scrape the HTML page. One approach to this task is this Yahoo Pipe [3] which converts the page to an RSS feed. However the data would be more useful converted to XML elements.

Dates and timesIn all these pages and feeds there is a problem to assign a date to a forecast or observation. Dates are often omitted or expressed as a day-of-the week. This leads to complications in processing both RSS and HTMl pages.

24-hour forecastThis script uses the eXist module httpclient to get the HTML, parses the HTML and generates an XML file. This XML could then be transformed via XSLT to a viewable page.

InterfaceThis script has two parameter: region - required - a numeric code unique to the BBC (? code list) area - optional - a sub region , typically the beginning of the postcodedeclare namespace h ="http://www.w3.org/1999/xhtml";

declare function local:day-of-week($date) { ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat') [ xs:integer(($date - xs:date('1901-01-06')) div xs:dayTimeDuration('P1D')) mod 7 +1] };

let $area := request:get-parameter("area",()) let $region := request:get-parameter("region","2") let $url := concat ("http://news.bbc.co.uk/weather/forecast/",$region, "?state=fo:B", if (exists($area)) then concat("&area=",$area) let $doc := httpclient:get(xs:anyURI($url),false(),()) let $currentDate := current-date() let $currentTime := current-time() let $dow := local:day-of-week($currentDate) return element forecasts { element region {$region}, if (exists($area)) then element area {$area} else () , element source {"BBC"}, else ())

BBC Weather Forecastfor $row in $doc/httpclient:body//h:table/h:tbody/h:tr

38

let $raw-time :=normalize-space($row/h:td[1]) let $time := if (contains($raw-time," ")) then substring-before($raw-time," ") else $raw-time let $time := xs:time(concat($time,":00")) let $pdow := if (contains($raw-time,"(")) then substring-before(substring-after($raw-time,"("),")") else $dow let $date := if ($pdow ne $dow) return element forecast { element date {$date}, element time {$time}, element dow {$pdow}, element summary {string($row/h:td[2]//h:p[@class="sum"])}, element imageurl {string($row/h:td[2]//h:div[@class="summary"]//h:img/@src)}, element maxTemp{ attribute units {"degc"} , $row/h:td[3]//h:span[@class="cent"]/text()}, element maxTemp {attribute units {"degf"} , $row/h:td[3]//h:span[contains(@class,"fahr")]/text()}, element windDirection {string($row/h:td[4]//h:span[contains(@class,"wind")]/@title)}, element windSpeed {attribute units {"mph"} , substring-before($row/h:td[4]//h:span[contains(@class,"mph")], "mph")}, element windSpeed {attribute units {"kph"} ,substring-before($row/h:td[4]//h:span[contains(@class,"kph")], "km/h")}, element humidity {attribute units {"%"}, normalize-space(substring-before($row/h:td[5]//h:span[contains(@class,"hum")], "%"))}, element pressure { attribute units {"mb"} , normalize-space(substring-before($row/h:td[5]//h:span[@class="pres"], "mB"))}, then $currentDate + xs:dayTimeDuration("P1D") else $currentDate

element visibility {normalize-space($row/h:td[5]//h:span[contains(@class,"vis")])} } }

24 hour forecast for Bristol [4]

References[1] [2] [3] [4] http:/ / newsrss. bbc. co. uk/ weather/ forecast/ 3/ ObservationsRSS. xml http:/ / newsrss. bbc. co. uk/ weather/ forecast/ 3/ Next3DaysRSS. xml http:/ / pipes. yahoo. com/ pipes/ pipe. edit?_id=1HlcTL8F3hGF7NSlPxJ3AQ http:/ / www. cems. uwe. ac. uk/ xmlwiki/ weather/ bbc24hforecast. xq?region=3

Benefits

39

BenefitsBenefits of XQueryThe principal benefits of XQuery are: Expressiveness - XQuery can query many different data structures and its recursive nature makes it ideal for querying tree and graph structures Brevity - XQuery statements are shorter than similar SQL or XSLT programs Flexibility - XQuery can query both hierarchical and tabular data Consistency - XQuery has a consistent syntax and can be used with other XML standards such as XML Schema datatypes XQuery is frequently compared with two other languages, SQL and XSLT, but has a number of advantages over these.

Advantages over SQLUnlike SQL, XQuery returns not just tables but arbitrary tree structures. This allows XQuery to directly create XHTML structures that can be used in web pages. XQuery is for XML-based object databases, and object databases are much more flexible and powerful than databases which store in purely tabular format. Unlike XSLT, XQuery can be learned by anyone familiar with SQL. Many of the constructs are very similar such as: Ordering Results: Both XQuery and SQL add an order by clause to the query. Selecting Distinct Values: Both XQuery and SQL have easy ways to select distinct values from a result set Restricting Rows: Both XQuery and SQL have a WHERE X=Y clause that can be added to an XQuery Another big advantage is that XQuery is essentially the native query language of the World Wide Web. One can query actual web pages with XQuery, but not SQL. Even if one uses SQL-based databases to store HTML/XHTML pages or fragments of such pages, one will miss many of the advantages of XQuery's simple tag/attribute search (which is akin to searching for column names within column names).

Advantages over XSLTUnlike XSLT, XQuery can be quickly learned by anyone familiar with SQL. XSLT has many patterns that are unfamiliar to many procedural software developers. Also, whereas XSLT is good for using as a static means to convert one type of document to another, for example RSS to HTML, XQuery is a much more dynamic querying tool, useful for pulling out sections of data from large documents and/or large number of documents.

The Debate about XQuery vs. XSLT for Document TransformationThere has been a debate of sorts about the merits of the two languages for transforming XML: XSLT and XQuery. A common misconception is that "XQuery is best for querying or selecting XML, and XSLT is best for transforming it." In reality, both methods are capable of transforming XML. Despite XSLT's longer history and larger install base, the "XQuery typeswitch" method of transforming XML provides numerous advantages. Most people who need to transform XML hear that they need to learn a language called XSLT. XSLT, whose first version was published by the W3C in 1999, was a huge innovation for its time and, indeed, remains dominant. It was one of the very first languages dedicated to transforming XML documents, and it was the first domain-specific language (DSL) to use advanced theories from the world of functional programming to create very reliable, side-effect free transformations. Many XML developers still feel strong indebted to this groundbreaking language, since it helped them see a new model of software development: one focused around the transformation of models

Benefits and empowering them to fuse both the requirements and documentation of a transformation routing into a single, modular program. On the other hand, learning XSLT requires overcoming a very substantial learning curve. XSLT's difficulty is due, in part, to one of the key design decisions by its architects: to express the transformation rules using XML itself, rather than creating a brand new syntax and grammar for storing the transformation rules. XSLT's unique approach to transformation rules also contributes to the steepness of the learning curve. The learning curve can be overcome, but it is fair to say that this learning curve has created a opening for an alternative approach. XQuery has filled this demand for an alternative among a growing community of users: they find XQuery has a lower learning curve, it meets their needs for transforming XML, and, together with XQuery's other advantages, it has become a compelling "all-in-one" language. Like XSLT, XQuery was created by the W3C to handle XML. But instead of expressing the language in XML syntax, the architects of XQuery chose a new syntax that would be more familiar to users of server-side scripting languages such as PHP, Perl, or Python. XQuery was designed to be similar to users of relational database query languages such as SQL, while still remaining true to functional programming practices. Despite its relative youth (XQuery 1.0 was only released in 2007 when XSLT had already reached its version 2.0), XQuery was born remarkably mature. XML servers like eXist-db and MarkLogic were already using XQuery as their language for querying XML and performing web server operations (obviating the need for learning PHP, Perl, or Python). So, in the face of the XSLT community's contention that "XSLT is best for transforming documents and XQuery is best for querying databases", this community of users was surprised to find that XQuery has entirely replaced their need for XSLT. They have come to argue unabashedly that they prefer XQuery for this purpose. How does XQuery accomplish the task of transforming XML? The primary technique in XQuery for transforming XML is a little-known expression added by the authors of XQuery, called "typeswitch." Although it is quite simple, typeswitch enables XQuery to perform nearly the full set of transformations that XSLT does. A typeswitch expression quickly looks at a node's type, and depending on the node's type, performs the operation you specify for that type of node. What this means is that each distinct element of a document can have its own rule, and these rules can be stored in modular XQuery functions. This humble addition to the XQuery language allows developers to transform documents with complex content and unpredictable order - something commonly believed to be best reserved for the domain of XSLT. Despite the differences in syntax and approach to transformation, a growing community has actually come to see the XQuery typeswitch expression as a valid, even superior, way to store their document transformation logic. By structuring a set of XQuery functions around the typeswitch expression, you can achieve the same result as XSLT-style transforms while retaining the benefits of XQuery: ease of learning and integration with native XML databases. Even more important for those users of native XML databases, the availability of typeswitch means that they only need to learn a single language for their database queries, web server operations, and document transformations. These XQuery typeswitch routines have proved easy to build, test, and maintain - some believe easier than XSLT. XQuery typeswitch has given these users a high degree of agility, allowing them to master XQuery fully rather than splitting their time and attention between XQuery and XSLT. That said, there is still a large body of legacy XSLT transforms that work well, and there are XSLT developers who see little benefit from transitioning to a typeswitch-style XQuery. Both are valid approaches to document transformation. A natural tension has arisen between the proponents of XQuery typeswitch and XSLT, each promoting what they are most comfortable with and believe to be superior. In practice you might be best served by trying both techniques and determining what style is right for you and your organization. Without presuming a background or interest in XSLT, this article and its companion article help you to understand the key patterns for using XQuery typeswitch for your XML transformation needs.

40

Caching and indexes

41

Caching and indexesMotivationThe views of the data about individual teams or groups needs to be supplemented with indexes to the resources for which those views are appropriate. Generating the indexes on demand is one approach but loads the SPARQL server. Given the batch nature of the DBpedia extract, it makes more sense to cache the index data and use the cache to generate an index page. (triggering the cache refresh is another problem!)

Non-caching approachThe following script generates an index page with links to the HTML view and the timeline views of a artist album.declare option exist:serialize "method=xhtml media-type=text/html"; declare variable $query := " PREFIX skos: PREFIX p: SELECT * WHERE { ?group } "; skos:subject .

declare function local:clean($text) { let $text:= util:unescape-uri($text,"UTF-8") let $text := replace($text,"\(.*\)","") let $text := replace($text,"_"," ") return $text };

let $category := request:get-parameter("category","") let $categoryx := replace($category,"_"," ") let $queryx := replace($query,"Rock_and_Roll_Hall_of_Fame_inductees",$category) let $sparql := concat("http://dbpedia.org/sparql?default-graph-uri=",escape-uri("http://dbpedia.org",true()), "&query=",escape-uri($queryx,true()) ) let $result return {$categoryx} { for $row in $result/table//tr[position()>1] let $resource := substring-after($row/td[1],"resource/") let $name := local:clean($resource) order by $name return := doc($sparql)

Caching and indexes{$name} HTML Timeline }

42

Index examples Rock and Roll Groups [1]

Caching ApproachTwo scripts are needed - one to generate the data to cache, the other to generate the index page. The approach is illustrated with an index to Rock and Roll groups based on the Wikipedia category Rock and Roll Hall of Fame inductees.

Generate the index dataThis script generates an XML file. A further development would store the XML directly to the database but it could also be saved manually to the appropriate location. It is parameterised by a category.declare variable $query := " PREFIX skos: PREFIX p: SELECT * WHERE { ?group } "; skos:subject .

declare function local:clean($text) { let $text:= util:unescape-uri($text,"UTF-8") let $text := replace($text,"\(.*\)","") let $text := replace($text,"_"," ") return $text };

declare function local:table-to-seq($table ) { let $head := $table/tr[1] for $row in $table/tr[position()>1] return

Caching and indexes{ for $cell at $i in $row/td return element {$head/th[position()=$i]} {string($cell)} } };

43

let $category := request:get-parameter("category","Rock_and_Roll_Hall_of_Fame_inductees") let $queryx := replace($query,"Rock_and_Roll_Hall_of_Fame_inductees",$category) let $sparql := concat("http://dbpedia.org/sparql?default-graph-uri=",escape-uri("http://dbpedia.org",true()), "&query=",escape-uri($query,true()) ) let $result := doc($sparql)/table

let $groups := local:table-to-seq($result) return {for $group in $groups let $resource := substring-after($group/group,"resource/") let $name := local:clean($resource) order by $name return }

Note: I guess a better approach would be to use triples here, saved to a local triple store.

HTML index pageThis script, groupList, uses the cached index data declare option exist:serialize "method=xhtml media-type=text/html"; let $list := //ResourceList[@category="Rock_and_Roll_Hall_of_Fame_inductees"] return Rock Groups {for $declare option exist:serialize "method=xhtml media-type=text/html"; lresource in $list/resource order by $resource/@name return {string($resource/@name)} HTML

Caching and indexes Timeline }

44

ExecuteRoll and Roll groups [2]

References[1] http:/ / www. cems. uwe. ac. uk/ xmlwiki/ RDF/ groupIndex. xq?category=Rock_and_Roll_Hall_of_Fame_inductees [2] http:/ / www. cems. uwe. ac. uk/ xmlwiki/ RDF/ groupList. xq

Chaining Web FormsMotivationYou want to create a series of web pages that pass information from one page to the next. This is very typical in web application development for example in the creation of "wizards" that ask the user for a series of questions on separate web pages.

MethodsWe will use three methods to demonstrate this: on the client using URL parameters and hidden form fields on the client in cookies on the server using sessions

Using URL Parameters and Hidden Form FieldsIn this method we will use a series of HTML forms in successive pages. Each page will gather some information and pass this information on the the next form by adding additional parameters to the URL. We will use the request:get-parameter functions to get the key-value pairs from the URL. Our first form will ask the user for their name. The second will ask them their favorite color. Here is and example of the first form: question-1.html Question 1: Your Name Question 1

Chaining Web Forms Please enter your first name:
The URL is passed to the second form and we will use the request:get-parameter() function to get the value from the URL. Here is the XQuery function for question 2. question-2.xqxquery version "1.0"; declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes"; let $name := request:get-parameter('name', '') let $title := 'Question 2: Enter Your Favorite Color' return {$title} {$title} Hello {$name}. Please enter your favorite color:

45

Note that we are storing the incoming name in a hidden input field in the form. The value of the hidden field must take the value of the incoming {$name} parameter. The last page just gets the two input parameters and displays them in an HTML page. If you look at the URL it will be of the format: result.xq?name=dan&color=blue result.xq xquery version "1.0"; declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes"; let $name := request:get-parameter('name', '') let $color := request:get-parameter('color', '')

Chaining Web Forms let $title := 'Result' return {$title} {$title} Hello {$name}. Your favorite color is {$color} Discussion This method is the preferred method since it does not require the client browser to support cookies. It also does not require the users to have a login a manage sessions. Sessions have the disadvantage that if the user gets interrupted half way through the process their session information will be lost and all the data they entered will need to be re-entered. Note that although the first "name" parameter is not visible in the second form, the value is visible in the URL. So the term "hidden" does not apply to the URL, only the form.

46

Using CookiesIn this example we will use the following functions for setting and getting cookies: response:set-cookie($name as xs:string, $value as xs:string) empty() request:get-cookie-value($cookie-name as xs:string) xs:string? The first form is identical to the example above. But thexquery version "1.0"; declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes"; (: get the input and set the name cookie :) let $name := request:get-parameter('name', '') let $set-cookie := response:set-cookie('name', $name) let $title := 'Question 2: Enter Your Favorite Color' return {$title} {$title} Hello {$name}. Please enter your favorite color:

Chaining Web Forms

47

Our first form will set the first cookie value and our second form will read the name cookie's value. xquery version "1.0"; declare option exist:serialize "method=xhtml media-type=text/html omit-xml-declaration=yes indent=yes"; let $name := request:get-cookie-value('name') let $color := request:get-parameter('color', '') let $title := 'Result From Cookies' return {$title} {$title} Hello {$name}. Your favorite color is {$color} Discussion Using cookies can be complex and you must be very careful that your cookies are not changed by another application from the same domain. Your design must also consider the fact that browsers and users disable cookies.

Using SessionsThe last method is to use server session values to store the key-value data. This will be very similar to the last example but we will use the eXist Session [1] module functions to set and get the values. Here are the two calls we will need: session:set-attribute($name as xs:string, $value as item()*) empty() session:get-attribute($name as xs:string) xs:string* You only need to make a change to a single line of the 2nd form. Just change the lines to the following: (: get the name and set the session :) let $name := request:get-parameter('name', ) let $set-session := session:set-attribute('name', $name) and in the final result script just get the data from the session: let $name := session:get-attribute('name')

Chaining Web Forms Discussion Using sessions can also be complex if you are new to session management. There are many rules that govern session timeouts and both the web server and database server may need to be configured to take your users needs into account. Session management may also not appropriate for public web sites that have policies against collection information on the web server.

48

Trade off AnalysisThere are many points to consider. Storing information in URLs has many advantages since user can start a multi-step form and come back later to finish. As long as they do not shut down their browser the URL parameters will remain. Cookies will remain on the client until the user takes some action to remove them. These are very useful when you do not want to have a person re-enter data for each session. Cookies tend to be ideal for storing users preferences when you do not have the ability to store them on the server. Sessions are most useful when you have users authenticate with a login but data is lost when the users log out or their session times out.

References[1] http:/ / demo. exist-db. org/ functions/ session

Changing Permissions on Collections and ResourcesMotivationYou want to change permissions on a set of collections and resources.

MethodThere are two functions we will use: For collections: xmldb:chmod-collection($collection, $perm) and for resources: xmldb:chmod-resource($collection, $resource, $perm) The $perm is a decimal number. As of 1.5 you can use the function xmldb:string-to-permissions("rwurwu---") to get this decimal number.

Sample to get decimal values for guest permissionsxquery version "1.0"; {xmldb:string-to-permissions("rwurwu---")} {xmldb:string-to-permissions("rwurwur--")} {xmldb:string-to-permissions("rwurwurw-")}

Changing Permissions on Collections and Resources{xmldb:string-to-permissions("rwurwurwu")}

49

Returns the following 504 508 510 511

Recursive Script to Remove All Guest Permissionsxquery version "1.0"; declare function local:chmod-collection($collection) { xmldb:chmod-collection($collection, xmldb:string-to-permissions("rwurwu---")), for $child in xmldb:get-child-collections($collection) return local:chmod-collection(concat($collection, "/", $child)) }; system:as-user('my-login', 'password', ( local:chmod-collection("/db/collection"), for $doc in collection("/db/collection") return xmldb:chmod-resource(util:collection-name($doc), util:document-name($doc), xmldb:string-to-permissions("rwurwu---")) ) )

Warning, this breaks several features. You must run many functions as non-guest.

Compare two XML files

50

Compare two XML filesMotivationYou want to compare two XML files. If the files are the same you want to return a true and if not you want to return a false. Note if you want to see the differences see the ../XML Differences example.

MethodWe will use the xdiff:compare() function that comes built in to eXist. To use this you pass two nodes to the compare function: xdiff:compare($node1 as node(), $node2 as node())

Sample Source CodeAssume you have two different XML files xquery version "1.0"; import module namespace xdiff="http://exist-db.org/xquery/xmldiff" "java:org.exist.xquery.modules.xmldiff.XmlDiffModule"; let $doc1 := '/db/apps/xml-diffs/data/diff1.xml' let $doc2 := '/db/apps/xml-diffs/data/diff2.xml' return diff of 1,1: {xdiff:compare(doc($doc1), doc($doc1))} diff of 1,2: {xdiff:compare(doc($doc1), doc($doc2))} diff of 2,2: {xdiff:compare(doc($doc2), doc($doc2))} The result will be: diff of 1,1: true diff of 1,2: false diff of 2,2: true

at

Compare with XQuery

51

Compare with XQueryMethodsWe will use a variety of functions that iterate through the lists. For each example we will perform some comparison with the second list.

Simple iteration and test for missing elementsIn this first example, we will use a simple for loop to go through each item on a linear list. We then will check to see if that item is anywhere on the second list (regardless of order). If it is on the second list we will display the item from the first list. If not we will output "missing". This is useful if you want to find out if a local collection is missing files from some remote collection. xquery version "1.0"; (: Compare of two linear lists :) let $list1 := a b c d

let $list2 := a c e return { for $item1 in $list1/item let $item-text := $item1/text() return {if ($list2/item/text()=$item-text) then ($item1) else {$item-text} } } Note that the conditional expression:

Compare with XQuery if ($list2/item/text() = $item-text) Tests to see if the $item-text is anywhere in list2. If it occurs anywhere this expression will return true().

52

Sample Results a b c d Note that this will not report any items on the second list that are missing from the first list.

Using Quantified ExpressionsThis can be rewritten using XQuery quantified expressions. There are two reasons for this. First the XQuery optimizer can frequently run quantified expressions much faster and some people feel they are easier to read. See XQuery/Quantified Expressions for more details. In this second example the list assignments are the same but we will only display the items from list 1 that are missing from list 2. { for $item1 in $list1/item return if (some $item2 in $list2/item satisfies $item2/text() = $item1/text()) then () else $item1 } This returns: b d We are now ready to modularize this missing function so that we can pass any two lists to find missing elements.

Compare with XQuery

53

Creating a Missing XQuery FunctionOut next step is to create an XQuery function that compare any two lists and returns the items in the second list that are not in the first list. declare function local:missing($list1 as node()*, $list2 as node()*) as node()* { for $item1 in $list1/item let $item-text := $item1/text() return if (some $item2 in $list2/item satisfies $item2/text() = $item1/text()) then () else $item1 };

We can rewrite the output function to use this function: {local:missing($list1, $list2)} {local:missing($list2, $list1)} Note that the order of the lists has been reversed in the second call to the missing() function. The second pass looks for items on list2 that are not on list1. Running this query generates the following output: b d e

Compare with XQuery

54

Creating HTML Difference ListsWe can use CSS to style the output of these reports.

Screen Image

HTML Diff Report using CSS

Sample DataThis example uses full words of items to show text highlighting: let $list1 := apples bananas carrots kiwi

let $list2 := apples carrots grapes The following function uses HTML div and span elements and adds class="missing" to each div that is missing. The CSS file will highlight this background. declare function local:missing($list1 as node()*, $list2 as node()*) as node()* { for $item1 in $list1/item return if (some $item2 in $list2/item satisfies $item2/text() = $item1/text()) then {$item1/text()} else {attribute {'class'} {'missing'}} {$item1/text()}

Compare with XQuery }; We then use the following CSS file to highlight the differences. Each missing element must have class="missing" attribute for the missing element to be highlighted in this report. body {font-family: Ariel,Helvetica,sans-serif; font-size: large;} h2 {padding: 3px; margin: 0px; text-align: center; font-size: large; background-color: silver;} .left, .right {border: solid black 1px; padding: 5px;} .missing {background-color: pink;} .left {float: left; width: 190px} .right {margin-left: 210px; width: 190px} Missing Items Report List 1 {for $item in $list1/item return {$item/text()}} List 2 {for $item in $list2/item return {$item/text()}}
List 1 Missing from 2 {local:missing($list1, $list2)} List 2 Missing from 1 {local:missing($list2, $list1)}

55

CollationIf the lists are in sorted order, or can be sorted into order, an alternative approach is to recursively collate the two lists. The core algorithm looks like: declare function local:merge($a, $b as item()* ) as item()* { if (empty($a) and empty($b)) then () else if (empty ($b) or $a[1] lt $b[1]) then ($a[1], local:merge(subsequence($a, 2), $b)) else if (empty($a) or $a[1] gt $b[1]) then ($b[1],local:merge($a, subsequence($b,2))) else (: a and b matched :) ($a[1], $b[1], local:merge(subsequence($a,2), subsequence($b,2)))

Compare with XQuery };

56

With the example above, we can merge two lists.

let $list1 := apples bananas carrots kiwi

let $list2 := apples carrots grapes return {local:merge($list1/item,$list2/item) } Execute [1] The actions on merge will depend on the application and the algorithm can be modified to output only mismatched items on one or other list, and handle matching items appropriately. For example, to display the merged list as HTML, we might modify the algorithm to:declare function local:merge($a, $b if (empty($a) and empty ($b)) then () else if (empty ($b) or $a[1] lt $b[1]) then ({$a[1]/text()}, local:merge(subsequence($a, 2), $b)) else if (empty ($a) or $a[1] gt $b[1]) then else }; ({$b[1]/text()},local:merge($a, subsequence($b,2))) ({$a[1]/text()}, local:merge(subsequence($a,2), as item()* ) as item()* {

subsequence($b,2)))

Execute [2]

Compare with XQuery

57

References[1] http:/ / www. cems. uwe. ac. uk/ xmlwiki/ Basics/ collate1. xq [2] http:/ / www. cems. uwe. ac. uk/ xmlwiki/ Basics/ collate3. xq

Creating a TimelineMotivationYou want to create a timeline of event data. Timelines show events in a horizontal scrolling view.

MethodWe will use the JavaScript client Timeline widgets provided by the Simile-Widgets project will be using the timeline 2.2.0 API calls.[1]

. In this example we

To do this we need to transform a list of event dates into the proper formats and then create an HTML page that includes calls to the Simile JavaScript libraries. Steps 1. View sample Event XML File format 2. View HTML template that loads XML file 3. Create XQuery Function that generates the HTML template and loads the appropriate XML data file Our first example will use a list of non-Duration Events (Instant Events). We will explore duration events and other events in a future chapter. We will then create a simple XQuery module with a single function that loads a simple timeline.

Sample XML File Using Standard XML Date FormatsMost XML dates use ISO 8601 coding. To use this format you must put in a date format attribute in the data file. First Day January, 2009 First Day of the Feb, 2009 Note that the data file must specify the ISO8601 date formats that are used as the XML date format.

HTML Driver TemplateThe sample HTML file shows how this XML file is loaded using the Timeline.loadXML() function.

Timeline Template

Creating a Timeline This page uses Javascript to show you a Timeline. Please enable Javascript in your browser to see the full page. Thank you.

59

Sample ImageThis will produce the following example:

Sample Timeline Output For Two Events

Sample XML Event File Using Non-Standard XML Date Formats First Day of the New Year First Day of the Feb

References[1] http:/ / code. google. com/ p/ simile-widgets/ wiki/ Timeline

Creating XQuery Functions

60

Creating XQuery FunctionsMotivationYou want to avoid duplication of XQuery code or create more modular XQuery programs.

MethodUse XQuery functions to encapsulate any chunk of XQuery code with a function wrapper. Any time you see a grouping of XQuery or XML code in your XQuery program that you would like to standardize, it is good design to start creating your own XQuery functions.

Static ContentStatic content is content that is fixed and is not changed by the use of parameters. XQuery functions are ideal for storage of static content libraries. For example, if all your HTML pages have the same block of code that has your logo and header text, you can create a simple XQuery function that encodes this functionality. Here is the HTML code you want to standardize on: Acme Widgets Inc. declare function local:header() as node() { Acme Widgets Inc. }; When you want to reference this you just call the function by placing it in your HTML page and enclosing it in curly braces: Sample Web Page {local:header()} Note that these functions names are preceded by "local:". This is the default namespace of a function invoked only in the same XQuery main module. If you want to store your functions in a separate file, you can do so. Such a file is called a "library module". To make use of the functions in this module, you need to "import" the module in the prolog of your query. The benefit of storing your code in functions and modules is that if you ever need to make a change to a function, you only have to make the change in one location, rather than in the many locations where you've copied and pasted the same code.

Creating XQuery Functions The following file, which we will save as webpage.xqm, is an example of this (note also the addition of a footer function): module namespace webpage='http://www.example.com/webpage'; declare function webpage:header() as node() { Acme Widgets Inc. }; declare function webpage:footer() as node() { Acme Widgets Inc. }; The module begins with a declaration of the module's namespace. Here we use an arbitrary namespace, "webpage".

61

Static Page AssemblyTo use this function module you must import the module at the top of your XQuery file (the following "import module" expression assumes your XQuery file is in the same directory as the module file, webpage.xqm): xquery version "1.0"; import module namespace webpage='http://www.example.com/webpage' at 'webpage.xqm'; let $title := 'Sample Web Page' return {$title} {webpage:header()} {$title} Content goes here. {webpage:footer()} Example [1]

Creating XQuery Functions

62

Dynamic ContentUnlike static content, dynamic content can be modified by including parameters into the function. One very common approach is to use a "page-assembler" function that includes parameters such as the document title and content. Here is an example of this function.

Dynamic Page Assembler Functionxquery version "1.0"; declare function webpage:assemble-page($title as xs:string, $content as node() as node()) { {$title} {webpage:header()} {$title} {$content} {webpage:footer()} }; Your web pages now can all reference a central page assembler like the following. import m