Getting Started with the WebSphere Application Server Feature Pack for XML

advertisement
Front cover
Getting Started with the
WebSphere Application Server
Feature Pack for XML
Use XPath 2.0, XSLT 2.0, and XQuery 1.0
in WebSphere applications
Help improve application
performance and reliability
Help improve developer
productivity
Khurram Faraaz
Dan Matthews
Swarajit Roy
ibm.com/redbooks
Redpaper
International Technical Support Organization
Getting Started with the WebSphere Application Server
Feature Pack for XML
June 2010
REDP-4654-00
Note: Before using this information and the product it supports, read the information in “Notices” on
page vii.
First Edition (June 2010)
This edition applies to the WebSphere Application Server Feature Pack for XML Version 1.0.
This document created or updated on June 21, 2010.
© Copyright International Business Machines Corporation 2010. All rights reserved.
Note to U.S. Government Users Restricted Rights -- Use, duplication or disclosure restricted by GSA ADP Schedule
Contract with IBM Corp.
Contents
Notices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . vii
Trademarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . viii
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
The team who wrote this paper . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ix
Now you can become a published author, too! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .x
Comments welcome. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .x
Stay connected to IBM Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .x
Chapter 1. The basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 Specifications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.2 IBM XML API. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
1.3 Setting up the build and execution environments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.3.1 Setting up client applications for build and execution environments. . . . . . . . . . . . 3
1.3.2 Setting up build and execution environments for server-based applications . . . . . 6
1.4 Building an application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.4.1 Creating XFactory and XExecutable instances. . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
1.4.2 Compiling XExecutables at run time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.4.3 Precompiling XExecutables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.5 Overview of the XPath 2.0 and XQuery 1.0 data model . . . . . . . . . . . . . . . . . . . . . . . . 11
1.5.1 Sequences and Items . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.5.2 Node types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.5.3 Atomic Values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.6 Static and dynamic contexts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.6.1 Static contexts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.6.2 Dynamic contexts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.7 Resolvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.7.1 XSourceResolver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.7.2 XCollectionResolver . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.7.3 Unparsed text resolvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.7.4 Result resolvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
1.7.5 Handling errors with the XMessageHandler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.7.6 Schema and schema resolvers. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
1.8 Namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
1.9 Using external variables with XPath or XQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.9.1 Declaring external variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
1.9.2 Binding external variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
1.10 Using external parameters with XSLT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.11 Using external functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
1.12 Building and executing the examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
1.12.1 Using the examples as client applications from the command line. . . . . . . . . . . 24
1.12.2 Using the examples as client applications from
Rational Application Developer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
1.12.3 Using the examples as server applications in
Rational Application Developer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
1.12.4 Creating the databases for the examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack
for XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
© Copyright IBM Corp. 2010. All rights reserved.
iii
2.1 XPath overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 Using XPath functions to access input data . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.2 Accessing XML data with XPath expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2 XPath 2.0 examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1 Using XPath 2.0 expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.2 Using XPath expressions on an XML file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.3 Using XPath expressions on an XML file and working with namespaces. . . . . . .
2.2.4 Reading XML data from a DB2 database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.5 Writing XML data to a DB2 database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
36
37
41
42
43
46
48
50
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature
Pack for XML . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
3.1 XQuery 1.0 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.2 XQuery schema and types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
3.3 Constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3.1 Direct constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
3.3.2 Computed constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4 FLWOR expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4.1 The for and let clauses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
3.4.2 The where clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
3.4.3 The order by clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.4.4 The return clause . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.5 Conditional expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
3.6 XQuery modules and prologs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.6.1 Query body . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.6.2 Prolog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
3.7 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.7.1 SimpleXQueryExecutor. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
3.7.2 XQueryNamespace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
3.7.3 NavigatingXSequence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
3.7.4 UsingDOMResult . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.7.5 CachingResults . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3.7.6 ExternalFunctionXQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
3.7.7 DerbyXQuery and DB2XQuery . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
3.8 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Chapter 4. Using the XSLT features of the WebSphere Application Server Feature Pack
for XML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
4.1 XSLT overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.2 XSLT 2.0 examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
4.2.1 Setting up the Java project in Rational Application Developer 7.5.5
with the thin client . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.2.2 Transforming a simple XML using XSLT. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
4.2.3 Multiple output documents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
4.2.4 Built-in support for grouping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
4.2.5 Date and time formatting. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
4.2.6 Character maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
4.2.7 Regular expression support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.2.8 Schema-aware XSLT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
4.2.9 User-defined functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
4.2.10 XHTML output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
Appendix A. Example code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
XQuery examples. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
iv
Getting Started with the WebSphere Application Server Feature Pack for XML
Java programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
Resolvers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
Appendix B. Additional material . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Locating the web material . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Using the web material. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to use the web material. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
121
121
121
121
Related publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
IBM Redbooks publications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Online resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
XPath 2.0 resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
XSLT 2.0 resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
XQuery resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
How to get Redbooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Help from IBM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
123
123
123
123
124
125
125
125
Contents
v
vi
Getting Started with the WebSphere Application Server Feature Pack for XML
Notices
This information was developed for products and services offered in the U.S.A.
IBM may not offer the products, services, or features discussed in this document in other countries. Consult
your local IBM representative for information on the products and services currently available in your area. Any
reference to an IBM product, program, or service is not intended to state or imply that only that IBM product,
program, or service may be used. Any functionally equivalent product, program, or service that does not
infringe any IBM intellectual property right may be used instead. However, it is the user's responsibility to
evaluate and verify the operation of any non-IBM product, program, or service.
IBM may have patents or pending patent applications covering subject matter described in this document. The
furnishing of this document does not give you any license to these patents. You can send license inquiries, in
writing, to:
IBM Director of Licensing, IBM Corporation, North Castle Drive, Armonk, NY 10504-1785 U.S.A.
The following paragraph does not apply to the United Kingdom or any other country where such
provisions are inconsistent with local law: INTERNATIONAL BUSINESS MACHINES CORPORATION
PROVIDES THIS PUBLICATION "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR
IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Some states do not allow disclaimer of
express or implied warranties in certain transactions, therefore, this statement may not apply to you.
This information could include technical inaccuracies or typographical errors. Changes are periodically made
to the information herein; these changes will be incorporated in new editions of the publication. IBM may make
improvements and/or changes in the product(s) and/or the program(s) described in this publication at any time
without notice.
Any references in this information to non-IBM Web sites are provided for convenience only and do not in any
manner serve as an endorsement of those Web sites. The materials at those Web sites are not part of the
materials for this IBM product and use of those Web sites is at your own risk.
IBM may use or distribute any of the information you supply in any way it believes appropriate without incurring
any obligation to you.
Information concerning non-IBM products was obtained from the suppliers of those products, their published
announcements or other publicly available sources. IBM has not tested those products and cannot confirm the
accuracy of performance, compatibility or any other claims related to non-IBM products. Questions on the
capabilities of non-IBM products should be addressed to the suppliers of those products.
This information contains examples of data and reports used in daily business operations. To illustrate them
as completely as possible, the examples include the names of individuals, companies, brands, and products.
All of these names are fictitious and any similarity to the names and addresses used by an actual business
enterprise is entirely coincidental.
COPYRIGHT LICENSE:
This information contains sample application programs in source language, which illustrate programming
techniques on various operating platforms. You may copy, modify, and distribute these sample programs in
any form without payment to IBM, for the purposes of developing, using, marketing or distributing application
programs conforming to the application programming interface for the operating platform for which the sample
programs are written. These examples have not been thoroughly tested under all conditions. IBM, therefore,
cannot guarantee or imply reliability, serviceability, or function of these programs.
© Copyright IBM Corp. 2010. All rights reserved.
vii
Trademarks
IBM, the IBM logo, and ibm.com are trademarks or registered trademarks of International Business Machines
Corporation in the United States, other countries, or both. These and other IBM trademarked terms are
marked on their first occurrence in this information with the appropriate symbol (® or ™), indicating US
registered or common law trademarks owned by IBM at the time this information was published. Such
trademarks may also be registered or common law trademarks in other countries. A current list of IBM
trademarks is available on the Web at http://www.ibm.com/legal/copytrade.shtml
The following terms are trademarks of the International Business Machines Corporation in the United States,
other countries, or both:
DB2®
developerWorks®
IBM®
pureXML®
Rational®
Redbooks®
Redpaper™
Redbooks (logo)
WebSphere®
®
The following terms are trademarks of other companies:
Java, and all Java-based trademarks are trademarks of Sun Microsystems, Inc. in the United States, other
countries, or both.
Windows, and the Windows logo are trademarks of Microsoft Corporation in the United States, other
countries, or both.
UNIX is a registered trademark of The Open Group in the United States and other countries.
Linux is a trademark of Linus Torvalds in the United States, other countries, or both.
Other company, product, or service names may be trademarks or service marks of others.
viii
Getting Started with the WebSphere Application Server Feature Pack for XML
Preface
The IBM® WebSphere® Application Server V7 Feature Pack for XML delivers support for the
Worldwide Web Consortium (W3C) XML standards XSLT 2.0, XPath 2.0, and XQuery 1.0.
The implementation of these standards in the Feature Pack for XML provide developers with
advanced capabilities for building XML applications. These capabilities simplify development
and can help you enhance your use of XML data in applications. The Feature Pack for XML
supports Java™ applications that connect to WebSphere Application Server through an XML
thin client.
This IBM Redpaper™ publication provides an introduction to the technology implemented
with the Feature Pack for XML and provides an extensive list of websites and documentation
that you can use to increase your knowledge of the subject.
The team who wrote this paper
This paper was produced by a team of specialists from around the world working at the
International Technical Support Organization (ITSO), Raleigh Center.
Khurram Faraaz is an IBM Certified Database Administrator for DB2® 9 for
Linux®, UNIX®, and Windows®. He joined IBM in 2006 and has since
worked in the DB2 for Linux, UNIX, and Windows XML FVT team. During
this time, apart from his daily FVT tasks, he has been involved in developing
XML industry bundles and has co-authored two articles on DB2 pureXML®.
He is also an ISTQB Certified tester.
Dan Matthews is a Software Engineer in IBM Hursley in the U.K. He has 10
years of experience as a developer with IBM WebSphere Application
Server. He has worked at IBM for 17 years. His areas of expertise include
J2EE, Web services, transactions and WS-Policy.
Swarajit Roy is an Advisory IT Architect working for IBM Global Business
Service India. He has 10 years of experience working in the IT industry and
has spent the last 5 years working as an Application IT Architect for IBM
India. His areas of expertise include the architecture, design, and
development of J2EE and WebSphere Portal applications. Swarajit holds a
Bachelor of Mechanical Engineering degree from Jadavpur University, India
and Executive Program in Business Management (EPBM), IIM Calcutta,
India. He is also certified in WebSphere Portal, Service Oriented
Architecture and Design, and XML related technologies.
Thanks to the following people for their contributions to this project:
Carla Sadtler
International Technical Support Organization, Raleigh Center
Andrew Spyker
IBM US
© Copyright IBM Corp. 2010. All rights reserved.
ix
Neil Graham
IBM Canada
Susan Malaika
IBM US
Lisa Bradley, AIM Early Customer Programs
IBM US
Now you can become a published author, too!
Here’s an opportunity to spotlight your skills, grow your career, and become a published
author—all at the same time! Join an ITSO residency project and help write a book in your
area of expertise, while honing your experience using leading-edge technologies. Your efforts
will help to increase product acceptance and customer satisfaction, as you expand your
network of technical contacts and relationships. Residencies run from two to six weeks in
length, and you can participate either in person or as a remote resident working from your
home base.
Find out more about the residency program, browse the residency index, and apply online at:
ibm.com/redbooks/residencies.html
Comments welcome
Your comments are important to us!
We want our papers to be as helpful as possible. Send us your comments about this paper or
other IBM Redbooks® publications in one of the following ways:
򐂰 Use the online Contact us review Redbooks form found at:
ibm.com/redbooks
򐂰 Send your comments in an email to:
redbooks@us.ibm.com
򐂰 Mail your comments to:
IBM Corporation, International Technical Support Organization
Dept. HYTD Mail Station P099
2455 South Road
Poughkeepsie, NY 12601-5400
Stay connected to IBM Redbooks
You can stay connected to our publications through the following websites:
򐂰 Find us on Facebook:
http://www.facebook.com/IBMRedbooks
򐂰 Follow us on Twitter:
http://twitter.com/ibmredbooks
x
Getting Started with the WebSphere Application Server Feature Pack for XML
򐂰 Look for us on LinkedIn:
http://www.linkedin.com/groups?home=&gid=2130806
򐂰 Explore new IBM Redbooks publications, residencies, and workshops with the IBM
Redbooks weekly newsletter:
https://www.redbooks.ibm.com/Redbooks.nsf/subscribe?OpenForm
򐂰 Stay current on recent IBM Redbooks publications with RSS Feeds:
http://www.redbooks.ibm.com/rss.html
Preface
xi
xii
Getting Started with the WebSphere Application Server Feature Pack for XML
1
Chapter 1.
The basics
The IBM WebSphere Application Server Version 7.0 Feature Pack for XML provides
developers with key XML technology to support XML data in WebSphere applications. The
Feature Pack for XML can help you to improve developer productivity, as well as the reliability
of applications that use XML data.
Without the feature pack, WebSphere Application Server version 7.0 contains support for
JAXP, implemented by the open source software library Xalan from the Apache Software
Foundation. This technology implements the XPATH and XSLT languages for processing XML
at the version 1.0 specification levels. The Feature Pack for XML delivers support for the
following versions of the XML processing languages:
򐂰 XPath 2.0
򐂰 XSLT 2.0
򐂰 XQuery 1.0
It also includes backwards-compatibility modes for the earlier versions of XPath and XSLT if
required.
The Feature Pack for XML provides the IBM XML Application Programming Interface
(IBM XML API). This API invokes a runtime engine that is capable of executing XPath 2.0,
XSLT 2.0, and XQuery 1.0 as well as manipulating the returned XML data. The Feature Pack
for XML also includes the IBM Thin Client for XML with WebSphere Application Server. The
thin client allows access to the XML API and runtime functionality.
Note that there are no APIs, JAR files or classes shared between the Feature Pack for XML
and the pre-existing JAXP and Xalan APIs. As a result, existing applications using the Xalan
or JAXP APIs are not affected by the feature pack in any way.
To download the Feature Pack for XML, see:
http://www.ibm.com/websphere/was/xml
© Copyright IBM Corp. 2010. All rights reserved.
1
1.1 Specifications
The Feature Pack for XML supports the following specifications to WebSphere Application
Server applications:
򐂰 Extensible Stylesheet Language Transformations (XSLT) 2.0
http://www.w3.org/TR/xslt20/
This specification includes programming language that is used to transform XML into a
new XML format or into another presentation-oriented format, such as HTML, XHTML, or
SVG. For more information about this standard, go to XSL Transformations (XSLT) Version
2.0.
򐂰 XML Path Language (XPath) 2.0
http://www.w3.org/TR/xpath20/
This specification includes programming language that is designed to allow developers to
select nodes from an XML document.
򐂰 XML Query Language (XQuery) 1.0
http://www.w3.org/TR/2007/REC-xquery-20070123/
This specification includes query language built with the intent of enabling access to
collections of XML documents in a way that bridges retrieval of both structured and
unstructured data. XQuery 1.0 improves your ability to query large amounts of data stored
in XML.
1.2 IBM XML API
So why publish a new API? Well, quite a lot has changed under the covers. The new versions
of these languages include more than just extended functionality. They are also based on a
new data model, which necessitates a new API. The new API delivered in the Feature Pack
for XML provides direct access to that underlying data model, which allows data to be
processed using the data model itself, without the need to use other representations of the
data, for example by using DOM, SAX, or StAX, although those APIs are supported.
Furthermore, the new APIs provide better thread-safety built in at the design stage.
The feature pack delivers the following JAR files, which contain the new API, run time, and
tooling:
򐂰 com.ibm.xml.thinclient_1.0.0.jar
The com.ibm.xml.thinclient_1.0.0.jar file is intended for use by thin clients executing
outside the WebSphere Application Server server environment. It is located at:
WAS_install_root/feature_packs/xml/runtimes
and
RAD_install_root\runtimes\base_v7\feature_packs/xml/runtimes
For thin client applications that use the XML APIs, you need to add this JAR file to the Java
build path to build the application and to the Java class path to execute it.
򐂰 com.ibm.xml.jar
The com.ibm.xml.jar file provides the Feature Pack for XML functionality to the
application server run time itself. It is located at:
WAS_install_root/feature_packs/xml/plugins
2
Getting Started with the WebSphere Application Server Feature Pack for XML
This JAR file is also shipped with the IBM Rational® Application Developer for WebSphere
Feature Pack for XML. It can be found at:
RAD_install_root\runtimes\base_v7_stub\plugins
You can find the Javadoc for the XML APIs in the doc.zip archive. For a WebSphere
Application Server installation, this archive is located in the following directory:
WAS_install_root//feature_packs/xml/docs
For a Rational Application Developer installation, this archive is located in the following
directory:
RAD_install_root\runtimes\base_v7_stub\docs
1.3 Setting up the build and execution environments
To build and run applications that use the XML APIs, either add the
com.ibm.xml.thinclient_1.0.0.jar or the com.ibm.xml.jar file to the Java class path that is
used to build or run the application.
1.3.1 Setting up client applications for build and execution environments
To build client applications that use the XML APIs in Rational Application Developer, add the
com.ibm.xml.thinclient_1.0.0.jar or the com.ibm.xml.jar file to the Java build path of the
project. For the purposes of this example, we use the com.ibm.xml.thinclient_1.0.0.jar
file and the doc.zip file, which are available from a WebSphere Application Server
installation.
To set up client applications:
1. In the Package Explorer view, right-click the project that includes the client application,
and select Properties  Java Build Path. Go to the Libraries tab in the right-hand
window.
2. Click Add External JARs, as shown in Figure 1-1 on page 4.
Chapter 1. The basics
3
Figure 1-1 Java Build Path for the project
3. Locate and select the com.ibm.xml.thinclient_1.0.0.jar file on the file system in the
JAR Selection window, as shown in Figure 1-2. Click Open.
Figure 1-2 Select the thin client JAR file
4
Getting Started with the WebSphere Application Server Feature Pack for XML
4. Optionally, you can set the Javadoc location for the XML API.
In the Java Build Path Properties window, expand the JAR file that you just added to the
Libraries tab. Select Javadoc location as shown in Figure 1-3, and then click Edit.
Figure 1-3 Add the Javadoc location file
5. In the edit window (Figure 1-4 on page 6), complete the following steps:
a. Select the “Javadoc in archive” option.
b. Enter the location of the doc.zip file in the “Archive path” field.
c. Enter javadoc in the “Path within archive” field.
d. Click OK.
Chapter 1. The basics
5
Figure 1-4 Specify the Javadoc location
6. Back on the Properties window, click OK to complete the task.
By default the class path that is used to run the application includes the default class path for
the project that includes the Java Build Path that you already modified. No extra configuration
is required to run the applications.
1.3.2 Setting up build and execution environments for server-based
applications
You can set up the environment to build applications in server-based projects, such as
dynamic web projects, identically to the environment for client based applications. Of course,
to run the application in a server runtime environment, no additional steps are required,
provided that you have installed the Feature Pack for XML on the runtime environment itself.
However, you can follow the steps that we provide here to configure the Feature Pack for XML
for a server-based project:
1. From an appropriate view, for example the Package Explorer, right-click the project, and
select Properties.
2. Select Project Facets in the left-hand window, and then select XML Transformations
and Query, as shown in Figure 1-5 on page 7.
6
Getting Started with the WebSphere Application Server Feature Pack for XML
Figure 1-5 Set the server properties
3. Click OK to complete the task.
This procedure configures the Java build path and the Javadoc in one easy step.
1.4 Building an application
This section covers the basics of using the IBM XML APIs in an application program. It uses a
simple example program, XMLFEPHelloWorld, to illustrate these concepts.
1.4.1 Creating XFactory and XExecutable instances
The starting point for writing a Java application that uses the Feature Pack for XML is the
XFactory class. New instances of the XFactory class are created with the static method
XFactory.newInstance(). When instantiated, instances of this class are used to construct
instances of many of the Java objects that form the XML API.
Chapter 1. The basics
7
Example 1-1 shows a code snippet taken from the XMLFEPHelloWorld example program.
Example 1-1 Code snippet showing XFactory class
XFactory xFactory = XFactory.newInstance();
XPathExecutable xpe = xFactory.prepareXPath("self::node()");
StreamSource source = new StreamSource(new StringReader("<HelloWorld/>"));
XSequenceCursor result = xpe.execute(source);
result.exportSequence(new StreamResult(System.out));
The basic pattern shown in Example 1-1 demonstrates how to:
1. Construct an instance of the XFactory.
2. Use the instance of the XFactory to create an instance of an XExecutable, in this case an
XPathExecutable.
3. Execute the XExecutable, in this case against a Source object.
4. (optionally) Process the results.
In this example the XPathExecutable is prepared as an interpreted executable and executed
using the interpreter at run time, which is the default behavior. Alternatively, XExecutables can
be precompiled, resulting in faster execution. There are trade-offs to be considered between
the different approaches.
1.4.2 Compiling XExecutables at run time
The simplest way to generate compiled XExecutable objects is to compile them at run time,
although using this approach does mean that the cost of compilation is born at run time. To
use this method, create an instance of the XStaticContext, use the setUseCompiler method
passing in a boolean value of true, and pass the XStaticContext instance as a parameter on
the method that prepares the XExecutable. Example 1-2 shows a code snippet taken from the
XMLFEPHelloWorldCompiledAtRuntime example program that prepares the
XPathExecutable as a compiled executable at run time.
Example 1-2 Prepare the XPathExecutable as a compiled executable at run time
XFactory xFactory = XFactory.newInstance();
XStaticContext xStaticContext = xFactory.newStaticContext();
xStaticContext.setUseCompiler(true);
XPathExecutable xpe = xFactory.prepareXPath("self::node()");
StreamSource source = new StreamSource(new StringReader("<HelloWorld/>"));
XSequenceCursor result = xpe.execute(source);
result.exportSequence(new StreamResult(System.out));
1.4.3 Precompiling XExecutables
XExecutables can be precompiled at build time, generating the .class files. This approach
has the advantage that the overhead of preparing the XExecutable is incurred when the code
is built rather than at run time. However, a separate step is required to build and package the
generated classes.
8
Getting Started with the WebSphere Application Server Feature Pack for XML
Executing a precompiled XExecutable
The code snippet in Example 1-3 shows a precompiled XExecutable that is loaded using the
XCompilationFactory.
Additional material: You can find this sample in the download material taken from the
XMLFEPHelloWorldPreCompiled example.
Example 1-3 Loading a precompiled XExecutable
XFactory xFactory = XFactory.newInstance();
XCompilationFactory xCompilationFactory = xFactory.getCompilationFactory();
XCompilationParameters parameters =
xCompilationFactory.newCompilationParameters("HelloWorldPreCompiled");
parameters.setPackageName("precompiled");
XPathExecutable xpe = xCompilationFactory.loadXPath(parameters);
StreamSource source = new StreamSource(new StringReader("<HelloWorld/>"));
XSequenceCursor result = xpe.execute(source);
result.exportSequence(new StreamResult(System.out));
The basic pattern shown in Example 1-3 demonstrates how to:
1. Construct an instance of the XFactory.
2. Use the instance of the XFactory to create an instance of an XCompilationFactory.
3. Use the XCompilationFactory to create an instance of the XCompilationParameters class
specifying the base name of the precompiled classes.
4. Specify additional parameters.
5. Use the appropriate load method on the XCompilationFactory passing in the
XCompilationParameters as the parameter, which returns the precompiled XExecutable.
This example loads an XPathExecutable that uses the loadXPathExecutable method and
returns the precompiled XPathExecutable.
6. Execute the XExecutable, in this case against a Source object. Note that the execution
method for precompiled XExecutables is no different from that for an interpreted
XExecutable.
7. (optionally) Process the results.
When the load method is called on the XCompilationFactory, the run time attempts to load the
precompiled class files from the class path using the classloader. Specifying a directory using
the setDirectoryName method on the XCompilationParameter has no effect on this
procedure. The class path must be set accordingly.
Generating precompiled XExecutables
XExecutables can be precompiled using command-line tools, Ant tasks, or a Java application.
Precompiling from the command line
The command-line tools for the Feature Pack for XML are located in the following directory:
WAS_install_root/feature_packs/xml/tools
Chapter 1. The basics
9
There are command-line tools for generating precompiled XExecutables for each language:
򐂰 compileXPath
򐂰 compileXSLT
򐂰 compileXQuery
Running a command-line tool with no parameters generates the help for that tool. The help
shows that are many options that you can specify. For our discussion, we look at four of these
parameters that are sufficient for precompiling the HelloWorldPreCompiled XPathExecutable
example. The parameters are common to all three tools. In this example, we use the
compileXPath tool because we are compiling an XPathExecutable.
For this example, you can use the following command:
C:\XMLFEPSRC\src>c:\WebSphere\AppServer\feature_packs\xml\tools\compileXPath.bat
-out HelloWorldPreCompiled -pkg precompiledcommandline xpath\root-name.xp
The parameters specified in the command are as follows:
򐂰 The -out parameter specifies the base name that is used for the generated class files.
򐂰 The -pkg parameter specifies the package name that is used for all generated class files.
򐂰 The final parameter is the file path to the source for the XExecutable, in this case the
XPath source. If the file path is a relative path, then it is relative to the current working
directory.
The directory in which to place the generated class files is unspecified in this case. If
unspecified, the default directory is the current working directory.
Precompiling using Ant
The Feature Pack for XML includes the following predefined Ant tasks:
򐂰 compileXPath
򐂰 compileXSLT
򐂰 compileXQuery
Similar to the command-line tools, the Ant tasks provide a range of parameters for configuring
the task. For our discussion, we includes the basics necessary to precompile the HelloWorld
example.
Example 1-4 shows an example Ant build file, HelloWorldAntPreCompile.xml, used to build
the HelloWorldPreCompiled XPathExecutable example.
Example 1-4 Precompiling using Ant
<?xml version="1.0" encoding="UTF-8"?>
<project name="HelloWorldAnt" default="HelloWorldAntPreCompile" basedir=".">
<property name="HelloText" value="Running Ant for HelloWorld"/>
<property name="build" location="bin"/>
<target name="HelloWorldAntPreCompile">
<echo>${HelloText}</echo>
<taskdef name="compileXPath"
classname="com.ibm.xml.xapi.ant.TaskCompileXPath"/>
<compileXPath>
<out>HelloWorldPreCompiled</out>
<pkg>precompiledant</pkg>
<dir>${build}</dir>
<inputfile>src/xpath/root-node.xp</inputfile>
10
Getting Started with the WebSphere Application Server Feature Pack for XML
</compileXPath>
</target>
</project>
The Ant task shown in Example 1-4 on page 10 uses the following parameters:
򐂰
򐂰
򐂰
򐂰
<out>
<pkg>
<dir>
<inputfile>
With the exception of <inputfile>, these parameters are the same as described in
“Precompiling from the command line” on page 9.
The <inputfile> parameter specifies the expression to be compiled. In the command-line
example, this expression was the value passed in as the last parameter to the command.
To execute this Ant build file, you need to set the com.ibm.xml.thinclient_1.0.0.jar or
com.ibm.xml.jar file on the class path for the Ant task. You also need Ant configured on your
system.
Precompiling using Java
You can also compile XExecutables using a Java application with the XCompilationFactory.
The basic pattern is as follows:
1. Obtain an instance of the XCompilationFactory from the XFactory.
2. Create an instance of the XCompilationParameters class from the XCompilationFactory,
specifying the XExecutable class name on the newCompilationParameters method call.
3. Set additional parameters using the setter methods on the XCompilationParameters
instance,
4. Invoke the compile method on the XCompilationFactory, specifying the source of the
expression and the XCompilationParameters.
Example 1-5 shows a code snippet from the XMLFEPHelloWorldGeneratePreCompiled
example program:.
Example 1-5 Precompiling using Java
XFactory xFactory = XFactory.newInstance();
XCompilationFactory xCompilationFactory = xFactory.getCompilationFactory();
XCompilationParameters parameters =
xCompilationFactory.newCompilationParameters("HelloWorldPreCompiled");
parameters.setPackageName("precompiled");
xCompilationFactory.compileXPath("self::node()", parameters);
1.5 Overview of the XPath 2.0 and XQuery 1.0 data model
XPath2.0, XQuery 1.0, and XSLT 2.0 share a common data model, XDM. The data model
describes all valid inputs, outputs, and intermediary values (for example when assigning the
value of an XPath 2.0 expression to a variable) that can be processed. Moreover, the
languages themselves are closed with respect to the data model; that is, XPath 2.0, XSLT 2.0,
and XQuery 1.0 expressions can all be described in XDM.
Chapter 1. The basics
11
1.5.1 Sequences and Items
XDM defines a concept called a Sequence, which is an ordered list of 0 or more Items.
Sequences cannot be nested as sub-sequences inside other Sequences. If combined, the
result is a single (flattened) Sequence.
Items that are added to Sequences maintain their identity and, thus, can appear multiple
times in the same Sequence or in multiple sequences. XDM makes no distinction between an
Item and a Sequence that contains only that Item. The two entities are considered to be
equivalent. Items can either be Nodes or Atomic Values.
The old data model’s equivalent of the Sequence was the Node Set. A Node Set could only
contain a list of Nodes. The more flexible XDM Sequences can contain Items as well as
Nodes. The Node types have also changed and become more flexible, allowing XML
fragments as well as documents to be modelled. As a result, XDM can model all input, output,
intermediary results and the expressions for the languages themselves, something that was
not possible using the old data model.
1.5.2 Node types
XDM defines the following Node types:
򐂰
򐂰
򐂰
򐂰
򐂰
򐂰
򐂰
Document
Element
Attribute
Namespace
Processing Instruction
Comment
Text
All XML documents and fragments can be expressed as a tree of these Node types.
Users of XPath 1.0 will be familiar with Nodes, which were introduced in XPath 1.0 data
model. The Node types in XDM are very similar to the old data model but are not identical.
The XPath 1.0 data model includes a Root Node, which is replaced in XDM with a Document
Node. The nodes are similar but different. A Document Node is more permissive than a Root
Node. For example, a Root Node can be empty, have multiple children, and can have Text
Nodes as children. Another notable difference is that XDM also allows Element Nodes without
parents.
1.5.3 Atomic Values
Items can also be Atomic Values. An Atomic Value is a value that is in the value space of one
of the following atomic types:
򐂰 A primitive data type as defined in the XML Schema Part 2: Datatypes Second Edition
specification, which is available at:
http://www.w3.org/TR/xmlschema-2/
򐂰 The predefined types defined in the XDM specification itself
򐂰 A type derived by restriction from another atomic type
12
Getting Started with the WebSphere Application Server Feature Pack for XML
1.6 Static and dynamic contexts
The specifications for XPath2.0, XSLT 2.0, and XQuery 1.0 introduce the concepts of static
and dynamic context.
1.6.1 Static contexts
A static context is simply a mechanism for providing information to the run time that is used
when performing static analysis of the expression, for example when the expression is
prepared or compiled before it is executed. This concept is realized in the Feature Pack for
XML by the XStaticContext interface. An instance of the XStaticContext class can be created
using the static method XFactory.newStaticContext() as follows:
XFactory xFactory = XFactory.newInstance();
XStaticContext xStaticContext = xFactory.newStaticContext();
XExecutables are prepared using one of the prepare methods on the XFactory interface. To
prepare an XExecutable against a static context, call the variant of the desired prepare
method that accepts an XStaticContext instance as a parameter. Each prepare method has
such a variant.
XPathExecutable xpe = xFactory.prepareXPath("self::node()", xStaticContext);
XExecutables are compiled using one of the compile methods on the XCompilationFactory
interface. To compile an XExecutable against a static context, call the variant of the desired
compile method that accepts an XStaticContext instance as a parameter, each compile
method has such a variant.
xCompilationFactory.compileXPath("self::node()", xStaticContext, parameters);
Note that because the XStaticContext encapsulates the additional data that is required to
prepare or compile an XExecutable, such data is not held as state within the XFactory or
XCompilationFactory instances themselves. Therefore, the XFactory and
XCompilationFactory instances can be used concurrently with different sets of such data far
more readily than their equivalents in some earlier XPath, XSLT, and XQuery APIs.
1.6.2 Dynamic contexts
A dynamic context is simply a mechanism for providing information to the run time that is used
when evaluating (executing) the expression. This concept is realized in the Feature Pack for
XML by the XDynamicContext interface. Instances of the XDynamicContext class can be
created using the static method XFactory.newDynamicContext(). It is an optional parameter
that can be specified whenever an execute method is called on an XExecutable.
XDynamicContext dynamicContext = xFactory.newDynamicContext();
XSequenceCursor sc = xpe.execute(dynamicContext);
Note that because the XDynamicContext encapsulates the additional data that is required to
execute an XExecutable, such data is not held as state within the XExecutable instances
themselves. Therefore, the XExecutable instances can be used concurrently with different
sets of such data far more easily than some of their equivalents in some earlier XPath, XSLT,
and XQuery APIs.
We show examples of how to use the XStaticContext and XDynamicContext to configure
resolvers, declare namespaces, and declare and bind external variables and functions in this
Chapter 1. The basics
13
chapter. For a complete understanding of the APIs, see the Feature Pack for XML Information
Center at:
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.xmlf
ep.multiplatform.doc/info/ae/ae/welcome_fepxml.html
1.7 Resolvers
The XPath, XSLT and XQuery languages provide various ways to reference different types of
source and result documents. In many cases, the Feature Pack for XML provides a default
behavior that might well be adequate, but users might want to override this behavior with
customized behavior. To this end, the Feature Pack for XML provides a set of interfaces that
can be implemented by a developer and registered with the Feature Pack for XML run time to
provide the desired behavior.
1.7.1 XSourceResolver
The XSourceResolver interface can be implemented by a developer to provide customized
behavior for resolving source documents. The interface consists of the single method
getSource(), which accepts two parameters and returns the resolved source through an
object of type javax.xml.transform.Source.
Source getSource(String uri, String base)
The first parameter is a String representation of the URI of the source, which can be relative
or absolute. The second parameter is a String representation of the base URI of the
expression, if available, otherwise the file path of the current working directory is used as the
value for the base URI.
If the XSourceResolver returns a null value from the getSource method, then the run time
attempts to resolve the resource with the default source resolution behavior. The default
behavior for source-resolution is to interpret relative URIs in terms of the base URI. Absolute
URIs are processed as-is.
The run time might require source documents to be resolved when expressions are prepared
and compiled and when expressions are evaluated.
Using an XSourceResolver at prepare time
XSLT contains the directives xsl:import and xsl:include that allow a style sheet to be
composed by combining multiple source files that make up the expression itself. These
directives contain an href attribute that specifies the URI identifying the document to be
included or imported.
To prepare source that includes such directives, any imported or included source files must
be resolved so that the combined style sheet can be prepared. Therefore, the resolution of
imported and included source is performed at prepared time.
Note that although the XQuery specification contains an optional mechanism to import library
modules, which can contain functions and variable definitions that are referenced by XQuery
code, the Feature Pack for XML does not support the use of XQuery library modules.
14
Getting Started with the WebSphere Application Server Feature Pack for XML
To override the default source-resolution behavior at prepare time, developers can write their
own implementation of the XSourceResolver interface and register it with the XStaticContext
using the setSourceResolver method, as shown in Example 1-6.
Example 1-6 Using an XSourceResolver at prepare time
XFactory xFactory = XFactory.newInstance();
XStaticContext xStaticContext = xFactory.newStaticContext();
SimpleSourceResolver sourceResolver = new SimpleSourceResolver();
xStaticContext.setSourceResolver(sourceResolver);
Only one instance of the XSourceResolver can be registered with the XStaticContext at a
time. If the setSourceResolver method is called with a null parameter, then the default source
resolution behavior is restored.
Using an XSourceResolver at evaluation time
The XQuery 1.0 and XPath 2.0 built-in function fn:doc() and the XSLT built-in function
fn:document() provide mechanisms to access source documents through their URIs. Source
documents accessed with these functions are resolved when the expression is evaluated.
To override the default source-resolution behavior at evaluation time, developers can write
their own implementation of the XSourceResolver interface and register it with the
XDynamicContext using the setSourceResolver method as shown in Example 1-7.
Example 1-7 Using an XSourceResolver at evaluation time
XDynamicContext dynamicContext = xFactory.newDynamicContext();
dynamicContext.setSourceResolver(sourceResolver);
XSequenceCursor sequenceCursor = xExecutable.execute(dynamicContext);
Only one instance of the XSourceResolver can be registered with the XDynamicContext at a
time. If the setSourceResolver method is called with a null parameter, then the default source
resolution behavior is restored. Note that XSourceResolvers registered through the
XStaticContext.setSourceResolver method are not invoked at evaluation time.
1.7.2 XCollectionResolver
The XQuery 1.0 and XPath 2.0 built-in function fn:collection() can be used to resolve a
collection of documents through a string representing the URI of the collection.
The XCollectionResolver interface must be implemented by a developer to provide
customized behavior for resolving collections. By default, if no XCollectionResolver is
registered, calls to fn:collection() result in a recoverable error and an empty sequence is
returned. The interface consists of a single method getCollection, which accepts two
parameters and returns the resolved collection through an XSequenceCursor.
XSequenceCursor getCollection(String uri, String base)
The first parameter is a String representation of the URI of the collection, which can be
relative or absolute. The second parameter is a String representation of the base URI of the
expression, if available. Otherwise, the file path of the current working directory is used as the
value for the base URI.
The collection resolver is not intended to resolve document URIs. In such cases, developers
need to use the fn:doc() function and XSourceResolver interface. Note that the
XSequenceCursor should be positioned at the first item in the cursor before it is returned.
Chapter 1. The basics
15
Collections of documents accessed in this manner are always resolved when the expression
is evaluated. Therefore, the XCollectionResolver is registered with the XDynamicContext
using the setCollectionResolver method as shown in Example 1-8.
Example 1-8 Registering the XCollectionResolver
XDynamicContext dynamicContext = xFactory.newDynamicContext();
dynamicContext.setCollectionResolver(collectionResolver);
XSequenceCursor sequenceCursor = xExecutable.execute(dynamicContext);
1.7.3 Unparsed text resolvers
You can use the XSLT built-in function, unparsed-text to read an external source as unparsed
text using the URI specified as a parameter and returning the unparsed text as an xs:string.
The default behavior for resolving the external source is to resolve absolute URIs as-is, and to
resolve relative URIs relative to the base URI of the static context, if it exists, else against the
current working directory.
To override the default behavior, a developer can implement the XUnparsedTextResolver
interface and register with the dynamic context. The XUnparsedTextResolver interface
consists of a single method:
String getResource(String uri, String encoding, String base)
In this method:
򐂰 The first parameter is a String representation of the external resource, which can be
relative or absolute.
򐂰 The second parameter is the encoding of the resource, if specified in the call to
unparsed-text. Otherwise, its value is null.
򐂰 The third parameter is a String representation of the base URI of the expression, if
available. Otherwise, the file path of the current working directory is used as the value for
the base URI.
The method returns the unparsed text as a java.lang.String object.
Resources accessed in this manner are always resolved when the expression is evaluated.
Therefore, the XUnparsedTextResolver is registered with the XDynamicContext using the
setUnparsedTextResolver method as shown in Example 1-9.
Example 1-9 Registering the XUnparsedTextResolver
XDynamicContext dynamicContext = xFactory.newDynamicContext();
dynamicContext.setUnparsedTextResolver(unparsedTextResolver);
XSequenceCursor sequenceCursor = xExecutable.execute(dynamicContext);
1.7.4 Result resolvers
XSLT provides the xsl:result-document instruction to redirect output from an executable to
an output URI. The default behavior for resolving such result documents is to resolve absolute
URIs as-is and to resolve relative URIs relative to the base URI of the static context, if it
exists, else against the current working directory.
16
Getting Started with the WebSphere Application Server Feature Pack for XML
To override the default behavior, a developer can implement the XResultResolver interface
and register with the dynamic context. The XResultResolver interface consists of a single
method, getResult():
Result getResult(String href, String base)
The first parameter is a String representation of the href parameter specified in the
xsl:result-document instruction, a URI, which can be relative or absolute. The second
parameter is a String representation of the base URI of the expression, if available.
Otherwise, the file path of the current working directory is used as the value for the base URI.
The method returns a javax.xml.transform.Result object to represent the result document.
The run time supports the Result types DOMResult, SAXResult, StAXResult, StreamResult,
and XSequenceCursorResult.
Redirection to output result documents always occurs when the expression is evaluated.
Therefore, the XResultResolver is registered with the XDynamicContext using the
setResultResolver method as shown in Example 1-10.
Example 1-10 Registering the XResultResolver
XDynamicContext dynamicContext = xFactory.newDynamicContext();
dynamicContext.setResultResolver(resultResolver);
XSequenceCursor sequenceCursor = xExecutable.execute(dynamicContext);
1.7.5 Handling errors with the XMessageHandler
When preparing or evaluating expressions, errors can occur. By default, error messages are
printed to System.err, and if the message is fatal then an XProcessException is thrown back
to the application. To override the default behavior, a developer can implement the
XMessageHandler interface and register it with the XFactory interface using the
setMessageHandler method. Alternatively, the XMessageHandler can be registered with the
XStaticContext or XDynamicContext interfaces, using their setMessageHandler methods, to
change the behavior on individual prepare and execute invocations respectively. In such
cases, the message handlers registered with the contexts are called in preference to the
XMessageHandler that is registered with the XFactory.
The XMessageHandler interface contains a single method, report():
void report(XMessageHandler.MsgType level, String message, XSourceLocation
location, Throwable cause, XSequenceCursor errorItems)
The report method provides a substantial amount of information about the error that has
occurred through the input parameters. Developers are free to perform whatever processing
is required in the report method, such as writing errors to a log, ignoring warnings, or other
such actions. If the desired behavior for a given error is to cause the current prepare or
execute to cease and fail, then an unchecked exception can be thrown from the method.
1.7.6 Schema and schema resolvers
XML source can reference XML schema, against which the XML source can be validated for
schema compliance. The Feature Pack for XML provides the ability to verify such XML source
against the XML schema. Furthermore, XPath, XQuery, and XSLT expressions can also be
evaluated in a schema-aware fashion. For example, the XQuery typeswitch expression can
evaluate the type of an element based on its annotated type derived from schema.
Chapter 1. The basics
17
To enable both schema validation and schema-aware evaluation of expressions two steps are
necessary.:
1. Schema validation must be enabled on the XFactory instance that is used to prepare,
compile and evaluate the expression using the setValidating method as follows:
XFactory factory = XFactory.newInstance();
factory.setValidating(XFactory.FULL_VALIDATION);
2. The schema source must be made available to the run time.
Schema can be made available to the run time in a variety of ways. XML Schema can be
registered directly with the XFactory using the following methods:
򐂰 registerSchema(Source schemaSource)
򐂰 registerSchemas(List<? extends Source> schemas) methods
The run time supports source types of DOMSource, SAXSource, StAXSource, and
StreamSource.
Example 1-11 shows a schema being directly registered with the XFactory.
Example 1-11 Registering a schema with the XFactory
XFactory factory = XFactory.newInstance();
factory.setValidating(XFactory.FULL_VALIDATION);
URL schemaURL = XQueryNamespace.class.getResource("/schema/ExtendedDefect.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
factory.registerSchema(schemaSource);
XML source documents, schema registered directly with the XFactory, and XSLT source
containing xsl:import-schema declarations might all reference schema that are not already
registered with the XFactory. In these cases, the Feature Pack for XML provides a default
mechanism for trying to access the schema:
򐂰 When unregistered schemas are referenced by an XML source document, the base URI of
the source document is used to resolve the schema.
򐂰 When unregistered schemas are referenced by a preregistered XML schema, the base
URI of the preregistered schema document is used to resolve the schema.
򐂰 When the schema is referenced by an xsl:import-schema declaration in XSLT then the
base URI specified on the declaration is used to resolve the schema.
Note that unregistered schemas that are referenced by schema registered with the XFactory
are resolved at prepare time, whereas unregistered schemas referenced by XML source are
resolved at execution time.
If the default behavior is insufficient, then the XSchemaResolver interface provides a
mechanism to customize the behavior for resolving the referenced, unregistered schemas.
To override the default behavior, as developer can implement the XSchemaResolver interface
and register with the XFactory instance that is used to prepare or compile and evaluate the
expression. The XSchemaResolver interface consists of a single method:
List<? extends Source> getSchema(String namespace, List<String> locations, String
baseURI)
18
Getting Started with the WebSphere Application Server Feature Pack for XML
This method uses the following parameters:
򐂰 The first parameter is the target namespace of the schema, which is null if the schema has
no target namespace (when no namespace will be specified in the reference to the
schema).
򐂰 The second parameter is a List of String objects that denote the schema locations.
򐂰 The third parameter is a String representation of the base URI whose value was derived
as described previously.
The method returns a java.util.List of objects of a type derived from
javax.xml.transform.Source, representing the sources associated with the input schema
locations.
The XSchemaResolver must be registered with the instance of the XFactory used to prepare
and evaluate the expression using the setSchemaResolver method, as shown in
Example 1-12. Do not forget to turn on schema validation.
Example 1-12 Resolving the XSchemaResolver
XFactory factory = XFactory.newInstance();
factory.setValidating(XFactory.FULL_VALIDATION);
factory.setSchemaResolver(schemaResolver);
Note that by default schemas that are resolved at evaluation time are not registered with the
XFactory itself and are re-resolved each time an execute method is called. As of Fix Pack 3,
the XQueryExecutable and XSLTExecutable interfaces provide a registerImportedSchemas
method. This method, which takes no parameters, causes the imported schemas to be
registered with the XFactory that created the XExecutable, resulting in better performance.
1.8 Namespaces
In general names in XML, XPath, XSLT, and XQuery are QNames, that is values with a local
name defined within the context of a namespace. To reference such QNames, the
namespace to which the QName belongs must be declared to the Feature Pack for XML run
time. Certain expression languages provide a native mechanism in the language itself. For
example, in XQuery, you can use a namespace declaration in an XQuery prolog. XQuery also
defines a set of default namespace declarations that are predefined automatically in the
available set of namespaces.
In addition to these mechanisms, the XStaticContext interface provides the
declareNamespace method. Within the expression languages, QNames are represented by a
namespace prefix and the local name. For example, the element name xmlsamp:DefectType
refers to a QName with local name DefectType in the namespace that is associated with the
namespace prefix xmlsamp.
Namespace declarations provide the association between the namespace prefix and the
namespace. Thus, the declareNamespace method takes two parameters:
򐂰 The namespace prefix
򐂰 The namespace that is associated with the prefix
The following example declares the namespace http://com.ibm.xml.samples and its
association with the prefix xmlsamp using the API:
xStaticContext.declareNamespace("xmlsamp", "http://com.ibm.xml.samples");
Chapter 1. The basics
19
When referencing QName values within an expression language, the prefix is optional, and
when not specified, a default namespace value is used. The default value depends on the
context in which the QName is used. If the QName represents a function name, then the
default function namespace is used. If the QName represents an element or element type
then the default element namespace is used. If the default namespace is “” (null), then the
QName is not associated with a namespace.
For XPath and XQuery, the default function namespace is:
“http://www.w3.org/2005/xpath-functions”
The default element or element type namespace is “” (null). You can change these default
values with the setDefaultFunctionNamespace and setDefaultElementTypeNamespace
methods respectively.
For XSLT, the default function namespace is the standard function namespace as defined in
the XSLT 2.0 Specification, which is available at:
http://www.w3.org/2005/xpath-functions
The default element namespace is the value specified in the xsl:xpath-default-namespace
attribute. XSLT does not use values specified by the setDefaultFunctionNamespace and
setDefaultElementTypeNamespace methods.
1.9 Using external variables with XPath or XQuery
The XPath and XQuery languages support the concept of external variables, allowing
expressions to process external data held outside of an input document. The Feature Pack for
XML supports the declaration and binding of external variables through the XStaticContext
and XDynamicContext APIs.
1.9.1 Declaring external variables
The Feature Pack for XML provides methods on the XStaticContext that allow variable
declarations to be made externally from the XPath or XQuery expression itself. Such external
variables are scoped to the entire expression. Declaring a variable reserves the variable
name so that it can be referenced inside the expression and associates it with a type.
Declaring variables is optional; however, declaring variables is a good practice because it
allows certain errors to be detected statically when the expression is prepared. If a variable is
not declared, then it is assumed to have a type of a sequence of zero or more items.
When declaring a variable that is a single item, the following method is used:
declareVariable(QName name, QName type)
The type specified must either be a built-in type or a global type that has been declared in a
schema registered with XFactory. If the type is a non-atomic type, then the variable is treated
as having the element(*, type) type. The following example code shows a variable
declaration for the variable with QName "band" of type xs:string. Note that the
XTypeConstants interface provides a set of predefined QNames for the built-in types.
XStaticContext staticCtx = factory.newStaticContext();
staticCtx.declareVariable(new QName("band"), XTypeConstants.STRING_QNAME);
When declaring a variable that has a sequence type, the following method is used:
declareVariable(QName name, XSequenceType)
20
Getting Started with the WebSphere Application Server Feature Pack for XML
The XSequenceTypeFactory method can be used to generate the XSequenceType
parameter. Example 1-13 shows an example of a variable declaration for the variable
“musicians” that is a sequence of zero or more items of type xs:string.
Example 1-13 External variable declaration
XSequenceTypeFactory sequenceTypeFact = factory.getSequenceTypeFactory();
staticCtx.declareVariable(new QName("musicians"),
sequenceTypeFact.atomic(XTypeConstants.STRING_QNAME,
XSequenceType.OccurrenceIndicator.ZERO_OR_MORE));
Note in XQuery, external variables can be declared in the XQuery prolog itself.
1.9.2 Binding external variables
After you declare a variable, you need to set a value for it before evaluating the expression.
This action is referred to as binding a value to a variable. Because the values of variables are
a runtime property, these values are associated with the dynamic context and are resolved at
run time. Failure to bind a value for a variable results in an error when the expression
references the variable at execution time.
To bind a value to a variable, the Feature Pack for XML provides several overloaded methods
on the XDynamicContext interface. The bind and bindSequence methods each take the
QName of the variable to be bound as the first parameter and the value to be bound as the
second parameter. Values that are a single item are bound using the bind methods, whereas
values that are a sequence are bound using the bindSequence method.
Variables that are a single item of atomic type are bound using one of the bind methods on
the XDynamicContext interface that takes one of the Java types used as a standard mapping
of built-in types to Java types as the second parameter. For example, the following code
snippet binds the band variable declared in 1.9.1, “Declaring external variables” on page 20:
XDynamicContext dynamicContext = factory.newDynamicContext();
dynamicContext .bind(new QName("band"),"Jazz");
There are three other variants of the bind method that take the org.w3c.dom.Node,
javax.xml.transform.Source object or an XItemView type for the second parameter. These
methods can be used to bind a single item value to a variable that is global type that has been
declared in a schema registered with XFactory. XItemView types can also be used for atomic
types.
Binding a value to a variable that is a sequence of atomic types is done using one of the
bindSequence methods on the XDynamicContext interface that takes an array of one of the
Java types used as a standard mapping of built-in types to Java types as the second
parameter. For example the following code snippet binds a sequence of strings, mapped to an
array of java.langString objects in Java, to the musicians variable:
dynamicCtx.bindSequence(new QName("musicians"), new
String[]{"John","Johnnie","Johnson","Jon"});
There is also a variant of the bindSequence method that takes an XSequenceCursor as the
second value parameter. This variant can be used to bind sequences of items whose type
can be either an atomic type or a global type that has been declared in a schema registered
with XFactory.
Note that external variables are referenced inside the expression just like any other variable;
no special syntax is required.
Chapter 1. The basics
21
1.10 Using external parameters with XSLT
Parameters in XSLT are declared as global parameters in the XSLT style sheet itself. To bind
external values to the parameters, you use exactly the same bind and bindSequence
methods on the XDynamicContext API as for binding values to variables for XQuery and
XPath.
1.11 Using external functions
External functions are instance methods on a Java object instance or static methods on a
Java class. They can be invoked from XPath, XQuery, and XSLT expressions. External
functions are made available to the expression either by a declaration in the native expression
language itself, where such a declaration method exists as it does in XQuery, or through the
XStaticContext API. Functions are identified by their QName and their arity (the number of
parameters in the function declaration). Overloading of function names is allowed for
functions with the same QName provided their arity differs. Overloading is not allowed based
on parameter types.
External functions must always be declared, unlike external variables. External functions are
declared on the XStaticContext API using one of the two polymorphic declareFunction
methods.
To declare an external function where the return and parameter values of the function are
single items, use the following method:
declareFunction(QName name, QName type, QName[] argTypes)
where:
򐂰 The name parameter is the QName for the external function.
򐂰 The type parameter is the QName for the type of the return value.
򐂰 The argTypes parameter is an array of QNames of the types of the arguments of the
external function.
The code snippet in Example 1-14 declares an external function, getTelephoneNumberExt, in
the namespace http://xmlfep.external.function. The function takes a single parameter of
type xs:string and returns a value of xs:integer.
Example 1-14 Declaring an external function that takes a single parameter
XStaticContext staticContext = factory.newStaticContext();
staticContext.declareNamespace("external", "http://xmlfep.external.function");
QName getTelephoneNumberQName = new QName("http://xmlfep.external.function",
"getTelephoneNumberExt");
staticContext.declareFunction(getTelephoneNumberQName
, XTypeConstants.INTEGER_QNAME
, new QName [] {XTypeConstants.STRING_QNAME});
To declare an external function where any of the return or parameter values are sequences,
use the following method:
declareFunction(QName name, XSequenceType type, XSequenceType[] argTypes)
22
Getting Started with the WebSphere Application Server Feature Pack for XML
Note that a single item is equivalent to a sequence containing exactly that single item. Thus,
this method can be used whenever the return values and parameters are a mixture of items
and sequences.
For example, the code snippet in Example 1-15 declares an external function
processSequence in the namespace. The function takes a single parameter that is a
sequence of items of type xs:string and returns a sequence of exactly one items (that is, a
single item) of type xs:string.
Example 1-15 Declaring an external function that uses sequences of items
XSequenceTypeFactory sequenceTypeFact = factory.getSequenceTypeFactory();
QName processSequenceQName = new QName("http://xmlfep.external.function",
"processSequence");
XSequenceType returnSequence =
sequenceTypeFact.atomic(XTypeConstants.STRING_QNAME,
XSequenceType.OccurrenceIndicator.ONE);
XSequenceType[] argumentSequenceArray = new
XSequenceType[]{sequenceTypeFact.atomic(XTypeConstants.STRING_QNAME,
XSequenceType.OccurrenceIndicator.ONE_OR_MORE)};
staticContext.declareFunction(processSequenceQName, returnSequence,
argumentSequenceArray);
To execute an expression that calls an external function, the implementation of the function
must be bound to the function name previously declared using one of the declareFunction
methods on the XDynamicContext API.
To bind an external function that is a static method on a Java class, use the following method:
bindFunction(QName name, Method method)
where:
򐂰 The name parameter is the QName of the function
򐂰 The method parameter is the java.lang.reflect.Method that implements the function.
To bind an external function that is an instance method on an instance of a Java object, use
the following method:
bindFunction(QName name, Method method, Object instance)
where:
򐂰 The name parameter is the QName of the function
򐂰 The method parameter is the java.lang.reflect.Method that implements the function.
򐂰 The instance parameter is the object instance on which to invoke the instance method.
The code snippet in Example 1-16 shows the getTelephoneNumber method on an instance of
the ExternalDirectoryFunction class being bound to the external function name declared
earlier in Example 1-14 on page 22.
Example 1-16 Binding the implementation to an external function name
Method getTelephoneNumberMethod =
ExternalDirectoryFunction.class.getMethod("getTelephoneNumber", Integer.class);
ExternalDirectoryFunction externalDirectoryInstance = new
ExternalDirectoryFunction();
Chapter 1. The basics
23
dynamicContext.bindFunction(getTelephoneNumberQName, getTelephoneNumberMethod,
externalDirectoryInstance);
1.12 Building and executing the examples
Download material: The XMLFEPHelloWorld program is available in the additional
materials available for this paper. See Appendix B, “Additional material” on page 121 for
information about downloading this material.
Source code for the examples referenced in this paper is provided in the
XQuery\examplesrc.zip file in the download materials for this paper. To use the examples,
download the .zip file and extract the contents into a new directory. We refer to this
directory as XMLFEPEXAMPLES throughout this paper.
The XMLFEPEXAMPLES project contains two directories:
򐂰 The src subdirectory contains the Java source code for the example programs.
򐂰 The WebContent subdirectory contains JSPs that can be used to execute the examples
in a server environment.
The XMLFEPEXAMPLES directory also contains the following Ant build files:
򐂰 Ant users can compile the example programs using the XMLFeaturePackExamples.xml
Ant build file.
򐂰 Ant users can use the HelloWorldPrecompileAnt.xml Ant build file to generate the
precompiled HelloWorld XPath executables.
1.12.1 Using the examples as client applications from the command line
An Ant file is provided in the additional materials to build the examples from the command
line. To use the Ant file to build the examples:
1. Add the com.ibm.xml.thinclient_1.0.0.jar file to the class path.
2. Configure Ant by setting the ANT_HOME environment variable to the Ant installation
directory and adding the Ant bin directory to the PATH environment variable.
3. To compile the examples, change to the XMLFEPEXAMPLES directory and execute the
XMLFeaturePackExamples Ant file using the ant command:
ant -buildfile XMLFeaturePackExamples.xml
4. To package the files into a JAR file, run the same Ant file specifying the target package:
ant -buildfile XMLFeaturePackExamples.xml package
This generates a JAR file in the XMLFEPEXAMPLES\lib directory called xmlfepexamples.jar.
5. Add the xmlfepexamples.jar file to the class path.
6. You can now run the HelloWorld and XQuery examples from the command line in the
XMLFEPEXAMPLES directory using the java command. For example, to execute the
XMLFEPHelloWorld, enter the following command on the command line:
java basics.XMLFEPHelloWorld
24
Getting Started with the WebSphere Application Server Feature Pack for XML
The XMLFEPHelloWorldPreCompiled example
To run the XMLFEPHelloWorldPreCompiled example, you need to first precompile the
HelloWorldPreCompiled XPathExecutable and then package it in the xmlfepexamples.jar
file.
Precompiling the example
To precompile the HelloWorldPreCompiled XPathExecutable, you can run the
HelloWorldPreCompileAnt.xml Ant buildfile or the XMLFEPHelloWorldGeneratePreCompiled
Java program as outlined in “Generating precompiled XExecutables” on page 9.
򐂰 To run the HelloWorldPreCompileAnt task from the command line, enter the following
command:
ant -buildfile HelloWorldPreCompileAnt.xml
The Ant build file compiles the XPathExecutable into a package called precompiledant.
򐂰 To run the XMLFEPHelloWorldGeneratePreCompiled Java program from the command
line, enter the following command:
java basics.XMLFEPHelloWorldGeneratePreCompiled
The Java program uses the package name precompiled.
򐂰 To generate the compiled XPathExecutable using the command-line tool, enter the
following command, where WAS_install_root is the WebSphere Application Server
installation directory:
WAS_install_root\feature_packs\xml\tools\compileXPath.bat -out
HelloWorldPreCompiled -pkg precompiledcommandline xpath\root-name.xp
The command uses the package name precompiledcommandline.
After compiling the XPathExecutable, regenerate the xmlfepexamples.jar file with the
XMLFeaturePackExamples Ant build file.
By default, the HelloWorldPreCompiled program loads the XPathExecutable contained in the
package precompiled. You can change the default by specifying the package name as a
parameter to the HelloWorldPreCompiled program.
Adding the database JAR files to the class path
To execute the XQuery examples that use either the Derby or DB2 databases, first create the
databases as described in “Creating the databases for the examples” on page 33. When this
task completes, then you can run the database examples.
If you are running the Derby database examples, you must add the derbyclient.jar file to
the Java class path. This JAR file is located in the WebSphere Application Server installation
directory in the derby\lib subdirectory.
If running the DB2 examples, you must add the db2jcc4.jar file to the Java class path.
Note: If you are writing applications that take advantage of the integration of the Feature
Pack for XML and DB2 pureXML, your project needs to reference the following DB2
specific JAR files:
򐂰 db2jcc_license_cu.jar
򐂰 db2jcc.jar
Chapter 1. The basics
25
1.12.2 Using the examples as client applications from
Rational Application Developer
The first step in using the examples from Rational Application Developer is to create the Java
project in the workspace:
1. Create a Java Project in the workspace by selecting the File  New, Java Project.
2. On the New Java Project panel, enter the project name. Select Create project from
existing source, and enter the value of XMLFEPEXAMPLES as the directory. Click Next.
3. Next, configure the Java Build Path and Javadoc for the project. Select the Libraries tab,
and click Add external JARs.
4. Select the com.ibm.xml.thinclient_1.0.0.jar file on the file system in the JAR Selection
window, and click Open.
5. To set the Javadoc location for the XML API, expand the
com.ibm.xml.thinclient_1.0.0.jar file in the Libraries tab. Select Javadoc location,
and click Edit. Then, follow these steps:
a. Select the “Javadoc in archive” option, and enter the location of the doc.zip file in the
“Archive path” field.
b. Enter javadoc in the “Path within archive” field.
c. Click OK.
6. Click Finish.
26
Getting Started with the WebSphere Application Server Feature Pack for XML
Running applications
Next, run the application from the workspace:
1. To run one of the example applications, expand the src directory structure inside the
project.
2. Use one of the following options to run the application:
– If the application does not take an input parameter, right-click the application’s .java
file, and select Run As  Java Application, as shown in Figure 1-6.
Figure 1-6 Run the client in the workspace
Chapter 1. The basics
27
– Alternatively, if the application takes a parameter:
i. Right-click the application’s .java file, and select Run As  Run Configurations.
ii. Either select an existing Java Application run configuration or create a new one by
right-clicking Java Application item and selecting New.
iii. Select the Arguments Tab, and enter the parameter in the “Program arguments” tab,
as shown in Figure 1-7.
Figure 1-7 Run the client in the workspace with parameters
Running the XMLFEPHelloWorldPreCompiled example
To run the XMLFEPHelloWorldPreCompiled example, you first need to generate the
precompiled XPathExecutable that the program loads and executes by running the
XMLFEPHelloWorldGeneratePreCompiled Java application or by running the
HelloWorldPreCompileAnt.xml Ant build file.
When running the Ant build file, you must add the XML JAR file to the Java class path:
1. Right-click the Ant build file in the workspace, and select Run As  Ant Build.
2. On the Edit Configuration panel, click the Classpath tab.
3. Select User Entries, and then click Add External JARs (Figure 1-8 on page 29).
4. Select the com.ibm.xml.thinclient_1.0.0.jar file.
5. Click Run to run the Ant build file.
28
Getting Started with the WebSphere Application Server Feature Pack for XML
Figure 1-8 Run Ant in the workspace
Note that the HelloWorldPreCompileAnt build file compiles the XPathExecutable into a
package called precompiledant but that the XMLFEPHelloWorldGeneratePreCompiled Java
program uses the package name precompiled. By default, the HelloWorldPreCompiled
program loads the XPathExecutable from the precompiled package. You can change the
default by specifying the package name as a parameter to the HelloWorldPreCompiled
Chapter 1. The basics
29
program. The XPathExecutable is compiled into the bin directory of the current project, which
by default is on the Java class path.
Preparing for the database examples
To execute the XQuery examples that use either the Derby or DB2 databases, complete the
following steps:
1. Create the databases as discussed in “Creating the databases for the examples” on
page 33.
2. Add the database JAR files to the class path for the application project.
– If running the Derby database examples, add the derbyclient.jar file located in the
WAS_install_root/derby/lib directory to the Java class path.
– If running the DB2 examples, add the db2jcc4.jar file to the Java class path.
You can change the Java class path either by modifying the Java Build Path for the project
or by modifying the class path defined in the Run Configuration for the application.
1.12.3 Using the examples as server applications in
Rational Application Developer
First, create a Dynamic Web Project in the workspace:
1. Select File  New  Dynamic Web Project.
If you do not see the Dynamic Web Project option, select File  New  Other 
Dynamic Web Project.
2. On the New Dynamic Web Project page, shown in Figure 1-9:
a. Enter the project name.
b. Select Add project to an EAR.
c. Select WebSphere Application Server v7.0 as the target run time.
d. Select Default Configuration for WebSphere Application Server v7.0 as the
configuration.
e. Click Finish.
30
Getting Started with the WebSphere Application Server Feature Pack for XML
Figure 1-9 New web project
Next, import the example files:
1. Right-click the new dynamic web project, and select Import.
2. Select General  File System.
3. Enter the XMLFEPEXAMPLES directory in the “From directory” field. Make sure that all the
source files are selected, and click Finish.
4. Configure the XML JAR file on the build path as described in “Setting up build and
execution environments for server-based applications” on page 6.
Then, run the example application on the server:
1. Expand the WebContent directory in the dynamic web project, right-click one of the JSP
files, and select Run As  Run on Server.
2. If you have not configured a server run time, you can do so by selecting Manually define
a new server. We assume that you have configured an appropriate WebSphere v7.0 run
time in the workspace.
3. Select Choose an existing server, and select the preconfigured server run time. You can
select the “Always use this server when running this project” option to avoid this dialog box
opening every time you run one of the JSPs.
Chapter 1. The basics
31
Figure 1-10 shows the invoked JSP.
Figure 1-10 Running the sample application on the server
Preparing for the Derby database example
Before invoking the Derby.jsp file to run the Derby database examples on the server, create
the database as described in “Creating the Derby database” on page 33. Then, configure a
data source on the server with the following characteristics:
JNDI name for the data source:
Database name:
Database type:
JDBC provider:
XMLFEPDERBYDS
XMLFEPDB
Derby
Derby Network Server Using Derby Client 40
Preparing for the DB2 database example
Before invoking the DB2.jsp file to run the DB2 database examples on the server, create the
database as described in “Creating the DB2 database” on page 33. Then, configure a data
source on the server with the following characteristics:
JNDI name:
Database name:
Database type:
JDBC provider:
32
XMLFEPDB2DS
XMLFEPDB
DB2
DB2 Using IBM JCC Driver
Getting Started with the WebSphere Application Server Feature Pack for XML
Configure the DB2 data source to use an authentication alias configured with a user ID and
password that has access to the DB2 database. You can create authentication aliases using
the WebSphere Application Server administrative console. Select Security  Global
Security  JAAS - J2C authentication data.
1.12.4 Creating the databases for the examples
The examples use a database called XMLFEPDB. You can create this database using Derby
(included in WebSphere Application Server) or DB2. This section describes how to set up the
database using each database product.
Creating the Derby database
The database samples for Derby require a Derby Network Server database on the server
local host port 1527 (the default server and port for a local Derby Network Server) with
database name XMLFEPDB. You can modify the samples to use an embedded database
driver or a remote database if required. Follow these steps:
1. Start the Derby Network Server by running the startNetworkServer.bat file located in
WAS_install_root\derby\bin\networkServer.
2. Then run the ij.bat command from the same directory.
3. After you have started ij, enter the following commands:
connect 'jdbc:derby://localhost:1527/XMLFEPDB;create=true';
disconnect;
exit;
4. Compile and run the CreateDerbyTables example application to create the tables in the
database.
5. Then, use the LoadDataIntoDerby example application to populate the tables with
example data.
6. Add the derbyclient.jar file to the application’s Java class path.
Creating the DB2 database
The database samples for DB2 require a DB2 server on server local host port 50000, which is
the default configuration of a local DB2 server. Ensure that the database server is started.
Change into the bin directory of the DB2 installation directory and run the db2cmd.exe file.
Switch to the newly started DB2CLP window, and enter the following command:
db2 create database XMLFEPDB
Now that the database is created, you can compile and run the CreateDB2Tables example
application to create the tables in the database and then the LoadDataIntoDB2 example
application to populate the tables with example data. Note that you must add the db2jcc4.jar
file to the Java class path to run the applications.
Chapter 1. The basics
33
34
Getting Started with the WebSphere Application Server Feature Pack for XML
2
Chapter 2.
Using the XPath features of the
WebSphere Application Server
Feature Pack for XML
XPath is an expression language that allows the processing of values conforming to the data
model defined in XQuery/XPath Data Model (XDM). This chapter provides an introduction to
the XPath 2.0 features that are available in the Feature Pack.
© Copyright IBM Corp. 2010. All rights reserved.
35
2.1 XPath overview
An XPath is built using an expression. The language provides several expressions that can be
constructed from keywords, symbols, and operands. XPath is a case sensitive language.
XPath is used to navigate through the hierarchical structure of an XML document; it operates
on the abstract logical structure of an XML document. The result of an XPath expression can
be a selection of nodes from the input documents, an atomic value, or more generally any
sequence that is allowed by the data model.
The primary purpose of XPath is to address the nodes of XML 1.0 or XML 1.1 trees. XPath
operates on the abstract, logical structure of an XML document, rather than its surface
syntax. XPath is designed to be embedded in a host language such as XSLT 2.0 or XQuery.
XPath has a natural subset that can be used to test whether a node matches a pattern. The
expression context for a given expression consists of all the information that can affect the
result of the expression. The static context of an expression is the information that is available
during static analysis of the expression, prior to its evaluation. The dynamic context of an
expression is defined as information that is available at the time the expression is evaluated.
2.1.1 Using XPath functions to access input data
XPath has a set of functions that provide access to input data. These functions provide a way
in which an expression can reference a document or a collection of documents. One way for
an expression to access input data is by calling one of the following input functions,
򐂰 The fn:doc function takes a string containing a URI. If that URI is associated with a
document in available documents, fn:doc returns a document node whose content is the
data model representation of the given document; otherwise it raises a dynamic error.
򐂰 The fn:collection function with one argument takes a string containing a URI. If that URI is
associated with a collection in available collections, fn:collection returns the data model
representation of that collection; otherwise it raises a dynamic error.
򐂰 The fn:collection function with zero arguments returns the default collection, an
implementation-dependent sequence of nodes.
36
Getting Started with the WebSphere Application Server Feature Pack for XML
2.1.2 Accessing XML data with XPath expressions
Figure 2-1 shows an example of XML data.
XPath Concepts
<dept bldg="101">
<employee id="901">
<name>John Doe</name>
<phone>408 555 1212</phone>
<office>344</office>
</employee>
<employee id="902">
<name>Jane Doe</name>
<phone>408 555 9919</phone>
<office>216</office>
</employee>
</dept>
bldg=101
id=901
Each node
has a path
dept
/
/dept
/dept/employee
/dept/employee/@id
/dept/employee/name
/dept/employee/phone
/dept/employee/phone/text()
(...)
employee
employee
name
phone
office
John Doe
408-555-1212
344
id=902
name
phone
office
Jane Doe
408-555-9918
216
Figure 2-1 XML data example
The example shows the following information:
򐂰 The node <dept> is the root node and it has an attribute called bldg.
򐂰 The child node <employee> is under the root node, which in turn has child nodes <name>,
<phone>, and <office> respectively.
򐂰 The element <employee> has an id attribute.
The hierarchical representation of the XML data is also shown in the upper, right corner of
Figure 2-1. If, for example, we want to access the element <phone> the corresponding XPath
expression would be as follows:
/dept/employee/phone
Similarly, if we were to access the text in a node, the XPath expression would be as follows:
/dept/employee/phone/text()
This expression makes the phone number available in the phone element.
The following examples of node tests can be used in XPath expressions:
򐂰 node() matches any node.
򐂰 text() matches any text node.
򐂰 comment() matches any comment node.
򐂰 element() matches any element node.
򐂰 schema-element(person) matches any element node whose name is person (or is in the
substitution group headed by person), and whose type annotation is the same as (or is
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
37
derived from) the declared type of the person element in the in-scope element
declarations.
򐂰 element(person) matches any element node whose name is person, regardless of its type
annotation.
򐂰 element(person, surgeon) matches any non-nilled element node whose name is person,
and whose type annotation is surgeon or is derived from surgeon.
򐂰 element(, surgeon) matches any non-nilled element node whose type annotation is
surgeon (or is derived from surgeon), regardless of its name.
򐂰 attribute() matches any attribute node.
򐂰 attribute(price) matches any attribute whose name is price, regardless of its type
annotation.
򐂰 attribute(, xs:decimal) matches any attribute whose type annotation is xs:decimal (or is
derived from xs:decimal), regardless of its name.
򐂰 document-node() matches any document node.
򐂰 document-node(element(book)) matches any document node whose content consists of a
single element node that satisfies the kind test element(book), interleaved with zero or
more comments and processing instructions.
Figure 2-2 shows XPath expressions in the first column and the results of the XPath
expression in the second column. The results are based on the XML document in the upper,
left corner. The at sign (@) is used to specify an attribute in an XPath expression. For
example, the XPath expression /dept/@bldg evaluates to 101.
XPath:
Simple XPath Expressions
• Use fully qualified paths to specify elements/attributes
• "@" is used to specify an attribute
• Use "text()" to specify the text node under an element
XPath
Result
/dept/@bldg
101
/dept/employee/@id
901
/dept/employee/name
902
<name>John Doe</name>
/dept/employee/name/text()
<name>Jane Doe</name>
John Doe
<dept bldg="101">
<employee id="901">
<name>John Doe</name>
<phone>408 555 1212</phone>
<office>344</office>
</employee>
<employee id="902">
<name>Jane Doe</name>
<phone>408 555 9919</phone>
<office>216</office>
</employee>
</dept>
Jane Doe
Figure 2-2 Simple XPath expressions
38
Getting Started with the WebSphere Application Server Feature Pack for XML
You can use the asterisk (*) and the forward slash (//) characters as wildcard characters in
XPath expressions. Figure 2-3 illustrates their use.
XPath:
Wildcards
<dept bldg="101">
<employee id="901">
<name>John Doe</name>
<phone>408 555 1212</phone>
<office>344</office>
</employee>
<employee id="902">
<name>Jane Doe</name>
<phone>408 555 9919</phone>
<office>216</office>
</employee>
</dept>
• * matches any tag name
• // is the "descendent-or-self" wildcard
XPath
Result
/dept/employee/*/text()
John Doe
408 555 1212
344
Jane Doe
408 555 9918
216
/dept/*/@id
901
902
//name/text()
John Doe
Jane Doe
/dept//phone
<phone>408 555 1212</phone>
<phone>408 555 9918</phone?
Figure 2-3 Using wildcards
Using predicates
A predicate consists of an expression, called a predicate expression, enclosed in square
brackets. A predicate serves to filter a sequence, retaining some items and discarding others.
We can have multiple predicates in one XPath expression. Figure 2-4 illustrates the use of
predicates.
XPath:
Predicates
• Predicates are enclosed in square brackets [...]
• Can have multiple predicates in one Xpath
• Positional predicates: [n] selects the n-th child
<dept bldg="101">
<employee id="901">
<name>John Doe</name>
<phone>408 555 1212</phone>
<office>344</office>
</employee>
<employee id="902">
<name>Jane Doe</name>
<phone>408 555 9919</phone>
<office>216</office>
</employee>
</dept>
XPath
Result
/dept/employee[@id="902"]/name
<name>Jane Doe</name>
/dept[@bldg="101"]/employee[office >"300"]/name
<name>John Doe</name>
//employee[office="344" or office="216"]/@id
901
902
/dept/employee[2]/@id
902
Figure 2-4 XPath predicates
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
39
The following example shows a predicate expression:
/gpx/wpt[@lat <= 45.0 and @lat >= 30.0 and @lon >= -125.0 and @lon <=-75.0]
In this example, the predicate expression checks for a specific entry in the XML document,
where the latitude is less than or equal to 45.0, the latitude is greater than or equal to 30.0,
the longitude is greater than or equal to -125.0, and the longitude is less than or equal to
-75.0.
Current and parent contexts
Figure 2-5 shows how to use the current context (“.”) and the parent context (“..”) in XPath
expressions. The figure shows the data that is used by the expression at the top, with the
expression and results in the table below it.
XPath:
The Parent Axis
• Current context: "."
• Parent context: ".."
<dept bldg="101">
<employee id="901">
<name>John Doe</name>
<phone>408 555 1212</phone>
<office>344</office>
</employee>
<employee id="902">
<name>Jane Doe</name>
<phone>408 555 9919</phone>
<office>216</office>
</employee>
</dept>
XPath
Result
/dept/employee/name[../@id="902"]
<name>Jane Doe</name>
/dept/employee/office[."300"]
<office>344</office>
/dept/employee[office > "300"]/office
<office>344</office>
/dept/employee[name="John Doe"]/../@bldg
101
/dept/employee/name[.="John Doe"]/../../@bldg
101
Figure 2-5 Parent axis
40
Getting Started with the WebSphere Application Server Feature Pack for XML
Using namespaces
Figure 2-6 shows the usage of namespaces in XPath expressions. In this example, dep is the
prefix used for the namespace http://www.employee.com/dept*. You must use this prefix in
the XPath expression.
XPath:
Namespaces
• Add prefixes to XPath steps!
• Could also use *: as a wildcard
XPath
<dep:dept xmlns:dep="http://www.employee.com/d ept"
bldg="101>
<dep:employee id="901">
<dep:name>John Doe</dep:name>
<dep:phone>408 555 1212</dep:phone>
<dep:office>344</dep:office>
</dep:employee>
<dep:employee id="902">
<dep:name>Jane Doe</dep:name>
<dep:phone>408 555 9919</dep:phone>
<dep:office>216</dep:office>
</dep:employee>
</dep:dept>
Resul t
/dept/employee/nam e
/dep :dept/d ep:employee/d ep:n ame
<name>Jan e Do e</name>
<name>Jo hn Doe< /name>
/dep :dept/d ep:employee/@id
901
902
Figure 2-6 Namespaces
We use the declareNamespace method to bind a given namespace to a prefix, and this prefix
is later used in the XPath expression. Example 2-1 shows how to declare a namespace and
bind it to a prefix using the declareNamespace method of the object which is of type
XStaticContext.
Example 2-1 Declaring a name space
XStaticContext sc1 = factory.newStaticContext();
sc1.setUseCompiler(true);
sc1.declareNamespace("gpx", "http://www.topografix.com/GPX/1/1");
2.2 XPath 2.0 examples
The examples in this section illustrate the basic use of the Feature Pack for XML API. In the
examples, note the following set of common steps for using XPath:
1. Create a factory for executables and context items. The com.ibm.xml.xapi.XFactory class
is the main factory class for creating executables for XPath, XQuery, and XSLT.
2. Create an executable (all have common base class). Using the new instance of XFactory,
we create the com.ibm.xml.xapi.XPathExecutable. It can be reused to evaluate an XPath
expression on multiple XML input documents.
3. Create the XML input for the executable. These simple examples use both a simple XML
input created in the application and the use of an XML file as input.
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
41
4. Execute the executable. In the examples, we execute the expression and store the results
in an XSequenceCursor.
5. Navigate and print the results.
2.2.1 Using XPath 2.0 expressions
Example 2-2 shows a sample program that demonstrates how to work with XPath 2.0
expressions.
The following example gets the value of the id element in the XML input using an XPath
expression. It creates the factory and then creates an XPath executable for the expression.
The XML data is assigned to a String variable called xml. It executes the XPath expression,
stores the results in an XSequenceCursor, and finally prints the result.
Example 2-2 Sample program with XPath 2.0 expressions
// The following is a basic example of
// preparing and executing an interpreted XPath expression.
import com.ibm.xml.xapi.XFactory;
import com.ibm.xml.xapi.XPathExecutable;
import com.ibm.xml.xapi.XSequenceCursor;
import java.io.ByteArrayInputStream;
import javax.xml.transform.stream.StreamSource;
public class GetEmployeeId {
public static void main(String s[])
{
try {
// Create a string for the XPath expression.
String expression = "/employee/id";
// Create the factory
XFactory factory = XFactory.newInstance();
// Create an XPath executable for the expression.
XPathExecutable xPathExecutable = factory.prepareXPath(expression);
// Create the input XML source
String xml = "<employee><name>Khurram
Faraaz</name><id>324517</id><dept>Information Management</dept></employee>";
// Execute the expression and store the results in an XSequenceCursor
XSequenceCursor xSequenceCursor = xPathExecutable.execute(new StreamSource(new
ByteArrayInputStream(xml.getBytes())));
// Print out the result.
if (xSequenceCursor != null) {
do {
System.out.println(xSequenceCursor.getStringValue());
} while (xSequenceCursor.toNext());
}
42
Getting Started with the WebSphere Application Server Feature Pack for XML
}
catch(Exception e) {
e.printStackTrace();
}
}
}
The output for this program is:
324517
2.2.2 Using XPath expressions on an XML file
Example 2-3 shows a sample program that demonstrates how to work with XPath
expressions on an input XML file. The comments in the file explain what the code is doing.
Example 2-3 Using XPath with an input file
import
import
import
import
import
import
java.io.FileInputStream;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XPathExecutable;
com.ibm.xml.xapi.XSequenceCursor;
javax.xml.transform.Source;
javax.xml.transform.stream.StreamSource;
public class GetName {
public static void main(String s[]) {
try
{
// Basic XML Feature Pack API Usage.
// Create the factory.
XFactory factory = XFactory.newInstance();
// Could be from a StreamSource as well.
String xpathString = "/employee/name";
// Create an XPath executable.
XPathExecutable xpath = factory.prepareXPath(xpathString);
// Create the input source.
Source source= new StreamSource(new FileInputStream("file:///c/employee.xml"));
// Execute the XPath
XSequenceCursor sequence = xpath.execute(source);
// Print out the result
if (sequence != null) {
do {
System.out.println(sequence.getStringValue());
} while (sequence.toNext());
}
}
catch(Exception e)
{
System.out.println(e);
e.printStackTrace();
}
}
}
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
43
Example 2-4 shows the input XML file, employee.xml.
Example 2-4 The employee.xml file
<employee>
<name>Khurram</name>
<id>45985</id>
<age>27</age>
</employee>
The output of this program is:
Khurram
Additional examples
This example demonstrates the retrieval of XML data from an input file using a variety of
XPath expressions in the Java code.
Download materials: This sample is included in the additional materials that are available
for this paper. See Appendix B, “Additional material” on page 121 for information about
downloading this material. The sample consists of the following files:
򐂰 download_directory/XPath/GetEmpDetails.java
򐂰 download_directory/XPath/org.xml
Example 2-5 shows the input data, org.xml.
Example 2-5 Sample data in the org.xml file
<?xml version="1.0" standalone="yes"?>
<orgdata>
<employee age="29">
<name>Kumar </name>
<jobtitle>Software Engineer</jobtitle>
<eid>54321</eid>
<dept>Information Management</dept>
<deptid>123-ABC-NA</deptid>
</employee>
<employee age="36">
<name>Sharma</name>
<jobtitle>Project Manager</jobtitle>
<eid>54981</eid>
<dept>Operations</dept>
<deptid>918-NBA-CAN</deptid>
</employee>
<employee age="30">
<name>Hussain</name>
<jobtitle>Software Engineer</jobtitle>
<eid>53219</eid>
<dept>Information Management</dept>
<deptid>133-ADC-IN</deptid>
</employee>
</orgdata>
44
Getting Started with the WebSphere Application Server Feature Pack for XML
Example 2-6 shows the GetEmpDetails.java code. Several XPath expressions are
documented in the comments that can be substituted for the XPath expression (in bold).
Example 2-6 Example GetEmpDetails.java code to retrieve employee data
/ Example to demonstrate retrieval of XML data from an input file
// based on execution of specific XPath expressions from the Java code.
/*
Some of the XPath expressions that can be used in the following code example are,
1.
To retrieve names of all employee from input XML data (i.e. from org.xml)
/orgdata/employee/name/text()
2.
To retrieve department names of all employees.
/orgdata/employee/dept
3.
To retrieve jobtitle of all employees.
/orgdata/employee/jobtitle
4.
To retrieve jobtitle for employees whose age=30 years.
/orgdata/employee[@age=30]/jobtitle
5.
To retrieve names of all employees whose eid > 50000
/orgdata/employee/[eid > 50000]/name
*/
import
import
import
import
import
import
java.io.FileInputStream;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XPathExecutable;
com.ibm.xml.xapi.XSequenceCursor;
javax.xml.transform.Source;
javax.xml.transform.stream.StreamSource;
public class GetEmpDetails {
public static void main(String s[]) {
try
{
// Basic XML Feature Pack API Usage.
// Create the factory.
XFactory factory = XFactory.newInstance();
// Could be from a StreamSource as well.
String xpathString = "/orgdata/employee";
// Create an XPath executable.
XPathExecutable xpath = factory.prepareXPath(xpathString);
// Create the input source.
Source source= new StreamSource(new FileInputStream("file:///c/org.xml"));
// Execute the XPath
XSequenceCursor sequence = xpath.execute(source);
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
45
// Print out the result
if (sequence != null) {
do {
System.out.println(sequence.getStringValue());
} while (sequence.toNext());
}}
catch(Exception e)
{
System.out.println(e);
e.printStackTrace();
}
}
}
2.2.3 Using XPath expressions on an XML file and working with namespaces
Example 2-7 shows a sample program that takes an XML file as input and executes XPath
expressions on that input file. This program shows how to work with XPath expressions that
involve namespaces.
This example uses the declareNamespace method to bind a given namespace
(http://www.topografix.com/GPX/1/1 in this example) to a prefix, and this prefix (gpx in this
example) is used later in the XPath expression.
Example 2-7 XPath expressions and using namespaces
import
import
import
import
import
import
import
java.io.FileInputStream;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XPathExecutable;
com.ibm.xml.xapi.XSequenceCursor;
javax.xml.transform.Source;
com.ibm.xml.xapi.XStaticContext;
javax.xml.transform.stream.StreamSource;
public class GetElevation {
public static void main(String s[])
{
try {
// Basic XML Feature Pack API Usage
// Create the factory
XFactory factory = XFactory.newInstance();
//Declare name space and map it to prefix gpx.
XStaticContext sc1 = factory.newStaticContext();
sc1.setUseCompiler(true);
sc1.declareNamespace("gpx", "http://www.topografix.com/GPX/1/1");
// Could be from a StreamSource as well
//The following XPath expressions may also be used.
//String XPATH_GET_SUMMIT = "/gpx:gpx/gpx:wpt[gpx:sym="+"\"Summit\""+"]";
//String XPATH_GET_LATITUDE = "/gpx:gpx/gpx:wpt/@lat";
//String XPATH_GET_TYPE = "/gpx:gpx/gpx:wpt/gpx:type";
//String XPATH_GET_MINLAT = "/gpx:gpx/gpx:metadata/gpx:bounds/@minlat";
46
Getting Started with the WebSphere Application Server Feature Pack for XML
//String XPATH_GET_MAXLON = "/gpx:gpx/gpx:metadata/gpx:bounds/@maxlon";
String XPATH_GET_ELEVATION = "/gpx:gpx/gpx:wpt[@lon=-71.119025 and
@lat=42.209547]/gpx:ele";
// Create an XPath executable
XPathExecutable xpath = factory.prepareXPath(XPATH_GET_ELEVATION,sc1);
// Create the input source
Source source= new StreamSource(new
FileInputStream("file:///c/blue_hills11.xml"));
// Execute the XPath
XSequenceCursor sequence = xpath.execute(source);
// Print out the result
if (sequence != null) {
do {
System.out.println(sequence.getStringValue());
} while (sequence.toNext());
}
}
catch(Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
}
Example 2-8 shows the input XML file.
Example 2-8 The blue_hills11.xml file
<?xml version="1.0" standalone="yes"?>
<gpx version="1.1" creator="ExpertGPS 1.1.1 - http://www.topografix.com"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.topografix.com/GPX/1/1"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 ..\schemas\gpx.xsd">
<metadata>
<name><![CDATA[Blue Hills Reservation]]></name>
<desc><![CDATA[Riding in the Blue Hills is a mix of fast fire roads and
technical rock gardens. Oh, and there's a hill around every corner, too.
Watch out for horses on the fire roads, and pick up a mountain bike trail map at
the Headquarters trailhead. Trails marked in red are off-limits to bikes. Every
intersection in the Blue Hills is marked with a 4 digit number, shown on the map.
The Blue Hills are a great place to hike, as well!]]></desc>
<author>
<name> Foster</name>
</author>
<time>2002-04-19T02:47:17Z</time>
<keywords><![CDATA[blue hills, mountain biking, milton]]></keywords>
<bounds minlat="42.204420" minlon="-71.123630" maxlat="42.228312"
maxlon="-71.069634"/>
</metadata>
<wpt lat="42.209547" lon="-71.119025">
<ele>86.258400</ele>
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
47
<time>2001-06-24T20:59:47Z</time>
<name><![CDATA[LOOKOUT]]></name>
<desc><![CDATA[Lookout Rock]]></desc>
<sym>Summit</sym>
<type><![CDATA[rock]]></type>
</wpt>
<wpt lat="42.218051" lon="-71.112672">
<ele>114.041260</ele>
<time>2001-10-13T23:50:58Z</time>
<name><![CDATA[1072]]></name>
<desc><![CDATA[1072]]></desc>
<sym>Dot</sym>
<type><![CDATA[Dot]]></type>
</wpt>
...
</gpx>
The output from this program is:
86.258400
2.2.4 Reading XML data from a DB2 database
The basic steps for reading XML data are as follows:
1. Create a prepared statement.
2. Execute the prepared statement obtaining a result set.
3. Get an SQLXML object from the result set.
4. Read the SQLXML object using one of the supported get methods.
5. Free the SQLXML object.
The next example illustrates these steps. This sample program demonstrates how to retrieve
XML data that is stored in an XML column in DB2. To prepare the database used in this
application:
1. You should have DB2 version 9.7 installed on your system.
2. Create a database named CIDX:
CREATE DATABASE CIDX;
3. Create a table to store XML data into the XML column:
CREATE TABLE CUSTOMER ( DATA XML);
4. Insert XML data into the CUSTOMER TABLE:
insert into customer values('<employee><name>Khurram</name><dept>Information
Management</dept><role>Software Developer</role></employee>');
Example 2-9 shows the example program.
Example 2-9 Example code that reads data from a database
import
import
import
import
import
48
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XPathExecutable;
com.ibm.xml.xapi.XSequenceCursor;
javax.xml.transform.stream.StreamSource;
java.sql.Connection;
Getting Started with the WebSphere Application Server Feature Pack for XML
import
import
import
import
java.sql.DriverManager;
java.sql.PreparedStatement;
java.sql.ResultSet;
java.sql.SQLXML;
class RetrieveXML
{
static String server = "localhost";
static int portNo = 50003;
static String dbName = "cidx";
static String userName = "Administrator";
static String password = "mydb2";
public static void main (String s[])
{
try {
// Load the DB2 JDBC Type 4 Driver with DriverManager
Class.forName ("com.ibm.db2.jcc.DB2Driver");
}
catch (ClassNotFoundException e) {
e.printStackTrace ();
}
try {
// Basic XML Feature Pack API Usage
// Create the factory
XFactory factory = XFactory.newInstance();
String XPATH_GET_ELEMENT = "/employee/name";
// Create an XPath executable
XPathExecutable xpath = factory.prepareXPath(XPATH_GET_ELEMENT);
Connection con = null;
String url = "jdbc:db2://" + server + ":" + portNo + "/" + dbName;
con = DriverManager.getConnection (url, userName, password);
// This is to SELECT XML Data from CUSTOMER table.
String selStmt = "SELECT DATA from CUSTOMER";
PreparedStatement pstmt = con.prepareStatement (selStmt);
ResultSet resultSet = pstmt.executeQuery ();
resultSet.next ();
SQLXML xmldata = resultSet.getSQLXML("DATA");
StreamSource source = xmldata.getSource(StreamSource.class);
// Execute the XPath
XSequenceCursor sequence = xpath.execute(source);
// Print out the result
if (sequence != null) {
do {
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
49
System.out.println(sequence.getStringValue());
} while (sequence.toNext());
}
pstmt.close ();
resultSet.close ();
con.close ();
}
catch (Exception e) {
e.printStackTrace ();
}
}
2.2.5 Writing XML data to a DB2 database
This example shows how to insert XML data into an XML column in DB2. Note that this
example is not specific to the Feature Pack for XML, but we include it for completeness. After
data is inserted into the database, it can be queried using XQuery.
To write XML data into DB2 database using the JDBC 4.0 provider:
1. Create a prepared statement.
2. Create an SQLXML object from the connection.
3. Get access to the SQLXML object using one of the supported set methods.
4. Set the SQLXML object into the statement parameters.
5. Write to the access method of the SQLXML object.
6. Execute the statement.
7. Free the SQLXML object.
Example 2-10 illustrates these steps.
Example 2-10 Writing XML data to a database
import
import
import
import
import
import
import
javax.xml.transform.stream.StreamResult;
javax.xml.transform.Result;
java.sql.Connection;
java.sql.DriverManager;
java.sql.PreparedStatement;
java.sql.SQLXML;
java.io.*;
class InsertXML
{
static String server = "localhost";
static int portNo = 50003;
static String dbName = "cidx";
static String userName = "Administrator";
static String password = "ramzan123#";
public static void main (String s[])
{
try {
// Load the DB2 JDBC Type 4 Driver with DriverManager
50
Getting Started with the WebSphere Application Server Feature Pack for XML
Class.forName ("com.ibm.db2.jcc.DB2Driver");
}
catch (ClassNotFoundException e) {
e.printStackTrace ();
}
try {
Connection con = null;
String url = "jdbc:db2://" + server + ":" + portNo + "/" + dbName;
con = DriverManager.getConnection (url, userName, password);
//Create a Result Context Holder.
ResultContextHolder rch = new ResultContextHolder();
// This is an example of a simple UPDATE statement to UPDATE XML data stored in
DB2.
//String updStmt = "UPDATE CUSTOMER set DATA = XMLPARSE(DOCUMENT \'<data1>test
data1</data1>\')";
// Insert Statement to insert XML data into DB2.
String insrtStmt = "INSERT INTO CUSTOMER VALUES(XMLPARSE(DOCUMENT
\'<employee><name>John
Doe</name><id>43561</id><age>35</age><dept>Operations</dept></employee>\'))";
rch.inStatement = con.prepareStatement (insrtStmt);
SQLXML xml = con.createSQLXML();
rch.result = new StreamResult(xml.setBinaryStream());
rch.inStatement.executeUpdate();
System.out.println("XML data successfully inserted in CUSTOMER table");
rch.inStatement.close ();
con.close ();
}
catch (Exception e) {
e.printStackTrace ();
}
}
}
class ResultContextHolder {
PreparedStatement inStatement;
Result result;
}
Chapter 2. Using the XPath features of the WebSphere Application Server Feature Pack for XML
51
52
Getting Started with the WebSphere Application Server Feature Pack for XML
3
Chapter 3.
Using the XQuery features of the
WebSphere Application Server
Feature Pack for XML
XQuery 1.0 is a declarative language for querying XML data. The specification for XQuery 1.0
is developed by the World Wide Web Consortium (W3C), an open standards body. You can
find the specification, called XQuery 1.0: An XML Query Language, at:
http://www.w3.org/TR/xquery/
In the current version, XQuery 1.0 does not provide functionality to modify the XML data
source itself using create, update, or delete operations, although one of the requirements for
XQuery was that the design should not preclude such additions to the language.
The Feature Pack for XML provides support for XQuery 1.0. This chapter provides an
introduction to the use of XQuery in WebSphere Application Server applications.
© Copyright IBM Corp. 2010. All rights reserved.
53
3.1 XQuery 1.0
When querying XML data using XQuery it is often desirable to restructure the XML data. For
this purpose, XQuery provides the ability to transform XML, much the same as XSLT.
Although this function is not its primary purpose, some users, particularly those familiar with
using SQL to extract data from relational databases, might find the syntax of XQuery easier to
use than XSLT. Thus, although XSLT is generally used for transforming XML and XQuery is
used for querying XML data, both languages provide a substantial overlap in functionality.
The choice of which language to use can often come down to the language with which the
developer is most comfortable.
For more information about the requirements that XQuery 1.0 was designed to satisfy, see
the XML Query (XQuery) Requirements document published by the W3C at:
http://www.w3.org/TR/xquery-requirements/
XQuery 1.0 is a superset of XPath 2.0, and any valid XPath 2.0 expression can form part of
an XQuery expression. XPath2.0 and XQuery 1.0 share the same operators and functions as
defined in the XQuery 1.0 and XPath 2.0 Functions and Operators specification at:
http://www.w3.org/TR/xpath-functions/
They also share the same data model, the XQuery 1.0 and XPath 2.0 Data Model,
abbreviated to XDM, which is available at:
http://www.w3.org/TR/xpath-datamodel/
3.2 XQuery schema and types
XQuery is a strongly typed language based on the XML Schema Part 1: Structures Second
Edition Specification, which is available at:
http://www.w3.org/TR/xmlschema-1/
XML schemas describe a set of rules or constraints to which XML that references the schema
must comply. XQuery, just like XPath 2.0, allows schema to be imported, allowing schema
conformance to be verified and operations to be performed based on annotated types defined
in the imported schema. The XQuery type mechanism also allows for static analysis, inferring
types when needed and detecting type errors when XQuery expressions are prepared.
The Feature Pack for XML does not support schema imports made in the XQuery prolog.
Schemas can either be registered directly with the XFactory API using the registerSchema
and registerSchemas methods or resolved using an XSchemaResolver.
Example 3-1 shows the schema defects.xsd being registered with the XFactory. The default
behavior is not to perform schema validation, even if schemas are registered with the factory
or referenced in the XML source.
54
Getting Started with the WebSphere Application Server Feature Pack for XML
In Example 3-1, the factory.setValidating method is called to turn on schema validation. It
should be noted that schema validation is performed for source documents only, the output is
not validated.
Example 3-1 Schema defects.xsd being registered
XFactory factory = XFactory.newInstance();
URL schemaURL = Simpletype.class.getResource("/xmldata/defects.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
factory.registerSchema(schemaSource);
factory.setValidating(XFactory.FULL_VALIDATION);
If an errors occur while validating XML source against the schemas, a recoverable error is
raised when executing the XQuery. By default the Feature Pack for XML run time continues to
process the XQuery. The error handling behavior can be customized using the
XMessageHandler API.
XML source documents and schema registered with the XFactory can reference schema that
are not registered with the XFactory. In that case, the Feature Pack for XML provides a default
mechanism for accessing the schema. If the default behavior is insufficient, then the
XSchemaResolver interface provides a mechanism to customize the behavior for resolving
the referenced, unregistered schemas. Unregistered schemas that are referenced by schema
registered with the XFactory are resolved at prepare time. Unregistered schemas referenced
by XML source are resolved at execution time.
The XQuery typeswitch expression provides a mechanism for selecting an expression to
evaluate based on the dynamic type of an input value. The typeswitch expression contains an
expression called the operand expression in parenthesis that acts as the input value for which
the dynamic type is to be tested. The operand expression is followed by one or more
conditional case clauses and a mandatory default clause, which is selected if none of the
case clauses match. The typeswitch expression evaluates to the return value of the selected
case or default clause.
Example 3-2 shows a function that returns the contacts for two different elements,
xmlsampdef:Defect and xmlsampcomp:Component, based on the element QNames using a
typeswitch expression. Case and default clauses can specify an optional variable name to
bind to the input value, as is illustrated with the $a variable in the example. This is necessary
when the return expression references the input value, as in the case clauses in the example.
It is not required if the input value is not referenced in the return expression, as in the default
clause in the example.
Example 3-2 The typeswitch expression
declare function local:getContacts($x)
{
typeswitch ($x)
case $a as element(xmlsampdef:Defect) return
($a/xmlsamp:developer,$a/xmlsamp:tester)
case $a as element(xmlsampcomp:Component) return $a/xmlsamp:manager
default return fn:error()
};
We can re-write Example 3-2 to perform an element test based on annotated types derived
from the Post Schema Validation InfoSet (PSVI). In this case, we use
element(*,xmlsamp:DefectType) to indicate an element of the type, or of a type derived from,
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
55
xmlsamp:DefectType that can have any QName (for exact semantics, see section 2.5.4.3,
“Element Test” in the XQuery specification). See Example 3-3 on page 56.
Using annotated types allows full exploitation of schema types, for example derived types can
be identified and processed as such. However when using annotated type information, the
schema containing the type definitions must be available to the XQuery processor at prepare
time. Because schema validation is required for the use of annotated types, then the XFactory
must be set to use schema validation, otherwise the data model will not contain the annotated
type information and such annotated type based testing will not produce a positive match.
Example 3-3 Annotated Types derived from PSVI
declare namespace xmlsamp = "http://com.ibm.xml.samples";
declare namespace xmlsampcomp = "http://com.ibm.xml.samples.component";
declare function local:getContacts($x)
{
typeswitch ($x)
case $a as element(*, xmlsamp:DefectType) return
($a/xmlsamp:developer,$a/xmlsamp:tester)
case $a as element(*, xmlsampcomp:ComponentType) return $a/xmlsamp:manager
default return fn:error()
};
3.3 Constructors
XQuery provides constructors for the seven different node types defined in XDM. There are
two kinds of constructors:
򐂰 Direct constructors
򐂰 Computed constructors
3.3.1 Direct constructors
Direct constructors are provided for element nodes and their associated attribute nodes,
comments and processing instruction nodes. These are based on standard XML notation.
Example 3-4 shows an XQuery expression that uses direct constructors. In this case, the
sequence of constructed nodes are written directly to the output.
Example 3-4 Direct constructor example
<MyElement myAttribute="attValue">
<?example pi="this is a processing instruction element" ?>
<!-- This is a comment node. The parent is an element node that contains an
attribute node-->
</MyElement>
56
Getting Started with the WebSphere Application Server Feature Pack for XML
3.3.2 Computed constructors
Computed constructors are provided for all node types. The XQuery in Example 3-4 can be
rewritten using computed constructors as shown in Example 3-5.
Example 3-5 Computed constructor example
element MyElement { attribute myAttribute {"attValue"} ,
processing-instruction {"example"}{'pi="this is a processing
instruction element"'} ,
comment {"This is a comment node. The parent is an element node that
contains an attribute node"} }
3.4 FLWOR expressions
XQuery provides a new type of expression, the FLWOR (pronounced flower) expression.
FLWOR is an acronym for the constituent parts of the expression (the for, let, while, order
by, and return clauses). FLWOR expressions generate a sequence of bound variables, called
the tuple stream, in the for and let clauses of the expression. These clauses can then be
used when constructing the output of the query. FLWOR expressions are particularly useful
for reorganizing the structure of the XML (functionality also provided by XSLT) and for
performing joins between XML data from different sources or different parts of the same XML
source.
3.4.1 The for and let clauses
Every FLWOR expression contains at least one for or let clause. These clauses must
appear at the beginning of the expression and can appear in any order. The let clause binds
a variable to a sequence. A stand-alone let clause generates a tuple stream that contains
one tuple, the variable that is bound to the sequence. The for clause of the expression binds
a variable to each item in a sequence. The resulting tuple stream contains a tuple for each
binding of the variable to each of the items in the sequence.
The following XQuery contains a FLWOR expression with let and return clauses:
let $x := ('a', 'b')
return <let_result>{$x}</let_result>
Processing the expression yields the following result:
<let_result>a b</let_result>
Note that there is a single <let_result> element that contains the sequence bound to
variable x. The tuple stream contains a single tuple, the binding of x to the sequence ('a',
'b').
The following XQuery contains a FLWOR expression with for, let, and return clauses:
let $x := 1
for $y in ('a', 'b')
return <for_result>{$y}{$x}</for_result>
Processing the expression yields the following result:
<for_result>a1</for_result><for_result>b1</for_result>
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
57
The for clause iterates over each item in the sequence ('a', 'b') that is bound to the
variable y. The tuple stream generated by the for and let clauses contains two tuples:
򐂰 The first tuple contains the binding of variable y to item 'a' and the binding of variable x to
{1}.
򐂰 The second tuple contains the binding of variable y to the item 'b' and the binding of
variable x to {1}.
Because the for clause iterates over the tuple stream, each iteration constructs a
<for_result> element, which contains the value of variable y for that iteration. Note that the
values of the variable y are the items in the sequence, not the value of the sequence itself.
Also, note that for and let clauses can reference any variables currently in scope, including
variables bound in preceding for and let clauses. In the preceding example, we could have
bound variable x to the value of variable y in a let clause following the for clause. In that
case, the tuples in the tuple stream would have contained bindings of variable y with the same
values as the value of the binding for variable x in the same tuple.
If a for clause contains multiple variables, then the tuple stream over which it iterates
contains a tuple for every combination of item values to which the different variables are
bound. For example, consider the following XQuery expression:
for $x in ('a', 'b'), $y in (1, 2)
return <for_multi_result>{$x} {$y}</for_multi_result>
This expression yields the following result:
<for_multi_result>a1</for_multi_result>
<for_multi_result>a2</for_multi_result>
<for_multi_result>b1</for_multi_result>
<for_multi_result>b2</for_multi_result>
Note that the first variable in the for clause acts as the outer loop of the iteration. The for
clause in this example can be rewritten as two separate for clauses, one for each variable. To
maintain the order in which the tuples are processed, you need to keep the order of the for
clauses the same, meaning that the for clause for variable x need to precede the for clause
for variable y.
3.4.2 The where clause
A where clause provides a way of filtering what is returned from the FLWOR expression. The
where clause is optional. If present, there must be only one where clause per FLWOR
expression, and it must occur after all for and let clauses and before the return clause and,
if present, the order by clause. The where expression is evaluated for each tuple in the tuple
stream. If the where expression evaluates to true, then processing continues for that tuple. If it
evaluates to false, then that tuple is discarded.
For example, the following FLWOR expression contains a where clause that filters out tuples
from the tuple stream, where the variable x is bound to a value that does not meet the
condition x > 3:
for $x in (1, 2, 3, 4, 5)
where $x >3
return <where_result>{$x}</where_result>
58
Getting Started with the WebSphere Application Server Feature Pack for XML
Evaluating this expression yields the following result:
<where_result>4</where_result>
<where_result>5</where_result>
Note that the where clause can filter on multiple conditions using logical expressions, for
example where $x >1 and $x <5.
3.4.3 The order by clause
The order by clause allows the tuple stream to be re-ordered, so that results can be sorted
as specified by the clause. The order by clause is optional. If present, there must be only one
order by clause per FLWOR expression, and it must occur after all for and let clauses and
the where clause, if present, but before the return clause.
The following example uses the order by clause to specify that the output is generated in
alphabetical order, using the standard fn:upper-case library function to provide case
insensitivity (otherwise, the name khurram would appear last):
for $name in ('Swarajit', 'khurram', 'Dan')
order by fn:upper-case($name)
return <order_by_names>{$name}</order_by_names>
This XQuery generates the following output:
<order_by_names>Dan</order_by_names>
<order_by_names>khurram</order_by_names>
<order_by_names>Swarajit</order_by_names>
Ordering can be performed on multiple indexes by separating them with a comma, in which
case the first index takes precedence. For example, the following example order by clause
sorts the tuple stream by last_name, further sorting matching values of last_name by
first_name.
order by $last_name, $first_name
3.4.4 The return clause
The return clause is the only mandatory clause of a FLWOR expression and must come at
the end of the FLWOR expression. It is evaluated for each tuple in the tuple stream after
filtering by the where clause, if present, and concatenates each result into a sequence, which
is the result of the FLWOR expression itself.
3.5 Conditional expressions
XQuery provides an if, then else expression for providing conditional logic in the form as
follows:
if <test expression> then <then expression> else <else expression>
The effective boolean value of the <test expression> is determined, and if true the <then
expression> is evaluated. If not true, then the <else expression> is evaluated.
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
59
Example 3-6 uses an if, then else expression as part of a FLWOR expression.
Example 3-6 If, then else Expression
for $x in (1, 2, 3, 4)
return
if ($x > 3 or $x = 1)
then <if_result>{$x}</if_result>
else <else_result>{$x}</else_result>
Example 3-7 is the output from the expression in Example 3-6.
Example 3-7 Output from else expression
<if_result>1</if_result>
<else_result>2</else_result>
<else_result>3</else_result>
<if_result>4</if_result>
There are limitations on the type of expressions that can be used for the <then expression>
and <else expression>. Details can be found in the XQuery 1.0 Specification. Note that
either clause can use () if the desired behavior is a no-op.
3.6 XQuery modules and prologs
XQuery code is packaged as the following modules:
򐂰 Main modules, which start with an optional prolog followed by the query body
򐂰 Library modules and their associated module declarations and module imports. This
packaging type is not supported by the Feature Pack for XML
This section discusses the elements of Main modules.
3.6.1 Query body
The query body consists of the XPath expression to be evaluated.
3.6.2 Prolog
The prolog consists of various declaration and import statements. These statements must
come before the query body. The statements are all optional, and each is terminated by a
semicolon. If present, the version declaration must appear first in the prolog. The variable
declarations, function declarations, and option declarations must come after all other
declarations and imports in the prolog. We do not discuss all of these declarations and
imports in this section. We focus on the more important declarations.
Version declaration
A version declaration indicates the version of XQuery that the implementation processing the
expression must support. If the version declaration is absent, a default version of 1.0 is
assumed. If the version declaration is present, it must appear as the first statement in the
prolog. The following is an example of a version declaration:
xquery version "1.0";
60
Getting Started with the WebSphere Application Server Feature Pack for XML
Variable declaration
Variables can be declared in the prolog using a variable declaration. If the declaration does
not contain an explicit type for the variable, the processor infers the type of the variable
statically when the expression is prepared. The declared variable is added to the in scope
variables of the static context and are in scope for the entire XQuery body, as well as any
parts of the prolog following the declaration. The variable must either be initialized in the
declaration with an initializing expression or declared as external. If an initializing expression
is used, then the processor evaluates it before the variable is first referenced. The initializing
expression overrides any external values passed into the processor in the dynamic context
using the IBM XML API.
The following example declares a variable of type xs:integer and assigns an initial value of
50. The name of the variable is a QName. In this example, no prefix has been specified, and
so the variable is not in a namespace.
declare variable $poodle_population_size as xs:integer := 50;
To specify a variable name in a particular namespace, you can use the standard XML
notation for QName:
declare variable $local:poodle_population_size as xs:integer := 50;
The following example declares an external variable of type xs:string.
declare variable $prospective_dog_owner as xs:string external;
Alternatively, you can use the XStaticContext API to declare external variables, as shown in
the following example:
xStaticContext.declareVariable(new QName("prospective_dog_owner"),
XTypeConstants.STRING_QNAME);
This variable is not initialized. If used without a value being bound to the variable, an error
occurs at run time. To bind values to external variables, use the XDynamicContext API, as
shown in the following example:
xDynamicContext.bind(new QName("prospective_dog_owner"), "John Doe");
For more information, refer to 1.9, “Using external variables with XPath or XQuery” on
page 20 and 1.11, “Using external functions” on page 22.
Function declarations
The function declaration defines the name of the function, which is a QName, the names and
types of any parameters, and the return type. The specification of the types of both the
parameters and the return value is optional. If no type is specified for a parameter or return
value, then it is assigned a default static type of item()*, which declares a sequence of zero
or more items.
Functions can be either user-defined or external.
Function declarations for user-defined functions contain an enclosed expression containing
the implementation of the function in the declaration itself. All user-defined functions must
have a non-null namespace. If the function is declared without a namespace prefix, then the
function is assigned to the default function namespace. In the Feature Pack for XML this
defaults to the http://www.w3.org/2005/xpath-functions namespace URI.
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
61
Example 3-8 shows an XQuery that contains a user-defined function and the Query body that
uses the function.
Example 3-8 XQuery with a user defined function
declare function local:amendCaseAsName($name as xs:string) as xs:string*
{
for $token in fn:tokenize($name, ' ')
return
fn:concat(fn:upper-case(fn:substring($token, 1, 1)),
fn:lower-case(fn:substring($token, 2)))
};
for $name in ('SWARAJIT ROY', 'khurram faraaz', 'Dan matthews')
let $ammended_name := local:amendCaseAsName($name)
order by $ammended_name
return <order_by_names>{$ammended_name}</order_by_names>
The function in this example has a name of amendCaseAsName in the
http://www.w3.org/2005/xquery-local-functions namespace, which is predeclared with
the namespace prefix local. There is one parameter that is typed as an xs:string. The type
of the return value is a sequence of items of type xs:string. The function takes an xs:string
type as input, tokenizes the string using a space character to identify individual words,
capitalizes the first letter in each word, and converts the remainder of the word to lower case.
As shown in the example, user functions are invoked in the same way as the built-in functions.
Evaluating the XQuery gives the following output:
<order_by_names>Dan Matthews</order_by_names>
<order_by_names>Khurram Faraaz</order_by_names>
<order_by_names>Swarajit Roy</order_by_names>
Function declarations for external functions contain the external keyword instead of the
enclosed expression. The following example shows a function declaration for an external
version of the same function:
declare function local:amendCaseAsName($name as xs:string) as xs:string* external;
The Feature Pack for XML supports the use of external functions. It provides APIs for both
declaring external functions through the XStaticContext interface and binding the
implementation of the function using the XDynamicContext interface. External functions must
be declared either by an external function declaration in the prolog or by use of the
XStaticContext API. Both mechanisms can be used concurrently, but failure to declare the
external function with either results in an error when the XQuery is prepared.
To execute an XQuery that uses external functions, the implementation of the function must
be bound to the function name using the XDynamicContext API. Failure to bind an
implementation for an external function results in an error when the XQuery is executed.
XQuery supports overloading of functions but only to a limited degree. Overloaded functions
are functions that have the same name. In XQuery, multiple functions can have the same
QName only if their arity is different, meaning that they have a different number of
parameters. XQuery does not allow overloading of functions based on different types of
parameters. For more information, see “Using external variables with XPath or XQuery” on
page 20 and “Using external functions” on page 22.
62
Getting Started with the WebSphere Application Server Feature Pack for XML
Namespace declaration
When handling XML data, many entities are identified by QNames. In particular XML
elements and functions and variables in the XQuery language itself are identified by
QNames. To be able to use QNames that are part of a namespace in an XQuery expression
(QNames that consist of only a local part exist outside any namespace) the namespace must
be declared to the XQuery processor through the static context.
By default several namespaces are predeclared, and no further action is required to reference
these namespaces. The following example lists the predeclared namespaces and their
associated prefixes:
xml
xs
xsi
fn
local
http://www.w3.org/XML/1998/namespace
http://www.w3.org/2001/XMLSchema
http://www.w3.org/2001/XMLSchema-instance
http://www.w3.org/2005/xpath-functions
http://www.w3.org/2005/xquery-local-functions
To demonstrate the namespace declaration, we can modify Example 3-8 on page 62 to use a
newly declared namespace for both the function name and the XML elements it constructs.
Example 3-9 declares the xmlfep prefix for the "http://xmlfep.ibm.com" namespace. This
prefix is used when specifying the declaration of the function in the prolog, the QName of the
XML elements, and the reference to the function in the Query body.
Example 3-9 Namespace declaration
declare namespace xmlfep = "http://xmlfep.ibm.com";
declare function xmlfep:amendCaseAsName($name as xs:string) as xs:string*
{
for $token in fn:tokenize($name, ' ')
return
fn:concat(fn:upper-case(fn:substring($token, 1, 1)),
fn:lower-case(fn:substring($token, 2)))
};
for $name in ('SWARAJIT ROY', 'khurram faraaz', 'Dan matthews')
let $ammended_name := xmlfep:amendCaseAsName($name)
order by $ammended_name
return <xmlfep:order_by_names>{$ammended_name}</xmlfep:order_by_names>
The Feature Pack for XML also provides an API to declare namespaces using the
XStaticContext.declareNamespace(String prefix, String NamespaceURI) method. Either
technique can be used to declare namespaces. If the same prefix is used for different
namespace URIs using these different techniques, then the namespace declaration in the
prolog takes preference.
The following code snippet shows the equivalent namespace declaration as shown in
Example 3-9 but using the IBM XML API:
XStaticContext sCtx = factory.newStaticContext();
sCtx.declareNamespace("xmlfep", "http://xmlfep.ibm.com");
XQueryExecutable xqe = factory.prepareXQuery(source, sCtx);
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
63
3.7 Examples
This section contains a few examples to help you construct your own XQuery code.
Download material: You can find the code and files that we use in this example in the
downloadable materials that are associated with this paper. For more information, see
Appendix B, “Additional material” on page 121.
3.7.1 SimpleXQueryExecutor
This example consists of a simple Java program called SimpleXQueryExecutor that prepares
and executes XQuery expressions. You can see the code for the sample program in
“SimpleXQueryExecutor.java” on page 102.
Download material: The code and files used in this example are:
򐂰 Java program: SimpleXQueryExecutor.java
򐂰 XQueries: simplejoin.xq, simplejoin2.xq, and simplefunction.xq
򐂰 Data source: Defects.xml and Components.xml
The simplejoin.xq XQuery
By default, the XQuery that is evaluated by SimpleXQueryExecutor is simplejoin.xq, shown
in Example 3-10.
Example 3-10 The simplejoin.xq XQuery
let $defects := doc("../xmldata/Defects.xml")
let $components := doc("../xmldata/Components.xml")
for $component in $components//Component
order by $component/id
return
<Component id="{$component/id}" manager="{$component/manager}">
{
for $defect in $defects//Defect
where $defect/@component = $component/id
order by $defect/@number
return <DefectNumber>{$defect/@number}</DefectNumber>
}
</Component>
The simplejoin.xq XQuery uses the fn:doc function to access the document nodes of two
XML source files, Defects.xml and Components.xml. These source files contain defect and
component data from a hypothetical software defect tracking program. Defects are associated
with the component of the software in which the defect resides.
Example 3-11 shows the Defects.xml file.
Example 3-11 The Defects.xml file
<?xml version="1.0" encoding="UTF-8"?>
<Defects>
<Defect number="0001" component="widget.calculator">
64
Getting Started with the WebSphere Application Server Feature Pack for XML
<abstract>function calculates incorrect result</abstract>
<state>working</state>
<developer>dan_matthews</developer>
<tester>swarajit_roy</tester>
</Defect>
<Defect number="0002" component="widget.calculator">
<abstract>error thrown for valid input</abstract>
<state>open</state>
<developer>dan_matthews</developer>
<tester>swarajit_roy</tester>
</Defect>
<Defect number="0003" component="widget.gui">
<abstract>Incorrect graphic used for company logo</abstract>
<state>closed</state>
<developer>khurram_faraaz</developer>
<tester>swarajit_roy</tester>
</Defect>
</Defects>
Example 3-12 shows the Components.xml file.
Example 3-12 The Components.xml file
<?xml version="1.0" encoding="UTF-8"?>
<Components>
<Component>
<id>widget.calculator</id>
<manager>Dan's Manager</manager>
</Component>
<Component>
<id>widget.gui</id>
<manager>Khurram's Manager</manager>
</Component>
<Component>
<id>widget.documentation</id>
<manager>Swarajit's Manager</manager>
</Component>
</Components>
The simplejoin.xq XQuery uses FLWOR expressions to produce a sequence of component
elements that are ordered by the value of child ID nodes, each containing a sequence of
defect elements that are ordered by their number attribute. This type of join is called an outer
join because information from one of the sources is preserved in the result. For example, the
widget.documentation component appears in the output even though no defects are
associated with this component.
Example 3-13 shows the output for the simplejoin.xq XQuery.
Example 3-13 Output for the simplejoin.xq XQuery
<?xml version="1.0" encoding="UTF-8"?>
<Component id="widget.calculator" manager="Dan's Manager">
<DefectNumber number="0001"/><DefectNumber number="0002"/>
</Component>
<Component id="widget.documentation" manager="Swarajit's Manager"/>
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
65
<Component id="widget.gui" manager="Khurram's Manager">
<DefectNumber number="0003"/>
</Component>
The simplejoin2.xq XQuery
If you want to omit the component elements that are not associated with any defects, you can
use the simplejoin2.xq XQuery, shown in Example 3-14. (This method is only one method of
achieving this result.) This XQuery binds the $defectsincomponent variable to a sequence of
defect elements whose component attribute matches the child ID node of the current
$component value in the tuple stream. It filters out non-empty sequences in the where clause.
Example 3-14 The simplejoin2.xq XQuery
let $defects := doc("../xmldata/Defects.xml")
for $component in doc("../xmldata/Components.xml")//Component
let $defectsincomponent:= $defects//Defect[@component=$component/id]
where exists($defectsincomponent)
order by $component/id
return
<Component id="{$component/id}" manager="{$component/manager}">
{
for $defect in $defectsincomponent
return <DefectNumber>{$defect/@number}</DefectNumber>
}
</Component>
To execute the simplejoin2.xq XQuery, the SimpleXQueryExecutor can be invoked passing
in the simplejoin2.xq string as a parameter. Example 3-15 shows the output.
Example 3-15 Output for the simplejoin2.xq XQuery
<?xml version="1.0" encoding="UTF-8"?>
<Component id="widget.calculator" manager="Dan's Manager">
<DefectNumber number="0001"/>
<DefectNumber number="0002"/>
</Component>
<Component id="widget.gui" manager="Khurram's Manager">
<DefectNumber number="0003"/>
</Component>
The simplefunction XQuery
You can also use SimpleXQueryExecutor to execute the simplefunction.xq XQuery, as
shown in Example 3-16, by passing in the simplefunction.xq string as a parameter. This
XQuery demonstrates the use of a user-defined function in XQuery.
Example 3-16 The simplefunction.xq XQuery
declare namespace xmlfep = "http://xmlfep.ibm.com";
declare function xmlfep:amendCaseAsName($name as xs:string) as xs:string*
{
for $token in fn:tokenize($name, ' ')
return
66
Getting Started with the WebSphere Application Server Feature Pack for XML
fn:concat(fn:upper-case(fn:substring($token, 1, 1)),
fn:lower-case(fn:substring($token, 2)))
};
<Output>
{
for $name in ('SWARAJIT ROY', 'khurram faraaz', 'Dan matthews')
let $ammended_name := xmlfep:amendCaseAsName($name)
order by $ammended_name
return <xmlfep:order_by_names>{$ammended_name}</xmlfep:order_by_names>
}
</Output>
The prolog of the XQuery contains a namespace declaration that binds the xmlfep prefix to
the "http://xmlfep.ibm.com" namespace. The prefix is then used in the function declaration
that follows for the xmlfep:amendCaseAsName function. The implementation for the function
is the enclosed expression, the expressions contained in the curly brackets, which is part of
the function declaration.
This function takes an xs:string as input, tokenizes the input as space-separated words,
then sets the first letter of each word to upper case and the remaining letters to lower case.
The XQuery body uses a FLWOR expression to call the user-defined function to obtain an
amended string for each item in a hard-coded sequence, and ordering the results.
Example 3-17 shows the output.
Example 3-17 Output from the simplefunction.xq XQuery
<?xml version="1.0" encoding="UTF-8"?>
<Output>
<xmlfep:order_by_names>Dan Matthews</xmlfep:order_by_names>
<xmlfep:order_by_names>Khurram Faraaz</xmlfep:order_by_names>
<xmlfep:order_by_names>Swarajit Roy</xmlfep:order_by_names>
</Output>
3.7.2 XQueryNamespace
The XQueryNamespace example processes source similar to that described in
“SimpleXQueryExecutor” on page 64, but this time the XML source references schema
against which it is validated. The code for XQueryNamespace is shown in
“XQueryNamespace” on page 103.
Download material: This example uses the following code and files used:
򐂰 Java program: XQueryNamespace.java
򐂰 XQueries: namespace.xq
򐂰 Data source: DefectsNS.xml, DefectsNSnoncompliant.xml, and ComponentsNS.xml
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
67
The source data
The source data for this example is the DefectsNS.xml file, shown in Example 3-18.
Example 3-18 The DefectsNS.xml file
<?xml version="1.0" encoding="UTF-8"?>
<Defects xmlns="http://com.ibm.xml.samples"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://com.ibm.xml.samples
http://com.ibm.xml.samples.component/Defects.xsd">
<Defect number="0001" component="widget.calculator">
<abstract>function calculates incorrect result</abstract>
<state>working</state>
<developer>dan_matthews</developer>
<tester>swarajit_roy</tester>
</Defect>
<Defect number="0002" component="widget.calculator">
<abstract>error thrown for valid input</abstract>
<state>open</state>
<developer>dan_matthews</developer>
<tester>swarajit_roy</tester>
</Defect>
<Defect number="0003" component="widget.gui">
<abstract>Incorrect graphic used for company logo</abstract>
<state>closed</state>
<developer>khurram_faraaz</developer>
<tester>swarajit_roy</tester>
</Defect>
<extdefect:ExtendedDefect xmlns:extdefect="http://com.ibm.xml.samples.ext"
xsi:schemaLocation="http://com.ibm.xml.samples.ext
http://com.ibm.xml.samples.component/ExtendedDefects.xsd" number="0004"
component="widget.documentation">
<abstract>Incorrect product version used in documentation</abstract>
<state>open</state>
<developer>swarajit_roy</developer>
<tester>khurram_faraaz</tester>
<extdefect:outsource_company>Our Little Helper Co</extdefect:outsource_company>
</extdefect:ExtendedDefect>
<Defect xmlns:extdefect="http://com.ibm.xml.samples.ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="extdefect:ExtendedDefectType" number="0005"
component="widget.documentation">
<abstract>Documentation requires translation</abstract>
<state>open</state>
<developer>swarajit_roy</developer>
<tester>dan_matthews</tester>
<extdefect:outsource_company>Our Little Helper Co</extdefect:outsource_company>
</Defect>
</Defects>
68
Getting Started with the WebSphere Application Server Feature Pack for XML
The namespace.xq XQuery
The XQuery source for this example is found in the namespace.xq XQuery, shown in
Example 3-19. It produces a list of defects that have a state of open and provides contact
information for each defect.
Example 3-19 The namespace.xq XQuery
declare namespace xmlsamp = "http://com.ibm.xml.samples";
declare namespace xmlsampcomp = "http://com.ibm.xml.samples.component";
declare namespace xmlsampext = "http://com.ibm.xml.samples.ext";
declare function local:getContacts($x)
{
typeswitch ($x)
case $a as element(*, xmlsamp:DefectType)
return <defect_contacts>
{($a/xmlsamp:developer/child::node(),",",$a/xmlsamp:tester/child::node(),",",$a/xm
lsampext:outsource_company/child::node())}
</defect_contacts>
case $a as element(xmlsampcomp:Component)
return <component_contacts>
{$a/xmlsampcomp:manager/child::node()}
</component_contacts>
default return fn:error()
};
declare variable $defects := .//element(*,xmlsamp:DefectType);
declare variable $components :=
doc("../xmldata/ComponentsNS.xml")//xmlsampcomp:Component;
<OpenDefects>
{
for $defect in $defects
let $component := $components[xmlsampcomp:id = $defect/@component]
where $defect/xmlsamp:state = "open"
return <Defect number="{$defect/@number}">
{local:getContacts($defect)}
{local:getContacts($component)}
</Defect>
}
</OpenDefects>
The XQuery source begins with namespace declarations in the prolog that are declared in the
schema. These declarations associate a prefix with each namespace. Elsewhere, the xquery
source uses these prefixes to qualify the namespace for the QNames that identify the relevant
element names.
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
69
Next, the source defines an internal user-defined function, local:getContacts, that performs a
typeswitch on its $x input parameter and obtains different contact information depending on
the type of $x, as follows:
򐂰 The first case statement of the typeswitch uses element(*, xmlsamp:DefectType) to
perform type testing. This testing matches any type annotation that is, or is derived from,
xmlsamp:DefectType. This testing is required in the example because in the schema we
have defined the ExtendedDefectType to extend DefectType as a base type and declared
the Defect element in the substitution group of the ExtendedDefect element. This allows
us to use the ExtendedDefect element in the sequence of Defect elements in a Defects
element in the form used by defect number 4. Defect number 5 shows an alternative form
we would have to use without the use of substitution groups.
If we had used element(xmlsamp:DefectType) as the type test, then defect number 4
would have not been matched because its QName is xmlsampext:ExtendedDefect. The
typeswitch selects the default case, and the query fails.
򐂰 The second case statement uses element(xmlsampcomp:Component) as the type test. This
type matches elements with QName xmlsampcomp:Component, which is sufficient
because we are not using the ComponentType as an extended base class with
substitution groups.
When the XQueryNamespace program runs, the output indicates that the Component
schema is resolved at execution time, whereas the Defect and ExtendedDefect schema are
resolved at prepare time. This function occurs is because the XQuery itself needs access to
the Defect and ExtendedDefect schema at prepare time to prepare the type tests that make
use of annotated types. However, no such type testing exists in the query for the types
declared in the Component schema.
The body of the XQuery starts with two variable declarations, binding the variables to the
sequence of defects and components from the two XML source files. The $defects variable
makes use of the context item, signified by the “.” symbol which is the root node of the
Defects.xml file, because this file was specified as the Source parameter when the XQuery
was prepared. The XPath expression used for the defects variable uses a type test that tests
based on the annotated type (and subtypes) of xmlsamp:Defect.
Next is a FLWOR expression that processes all the defects in the sequence, assigns a
variable to the Component element referenced by the defect, filters on the state of the defect
to process only open defects, and calls the user-defined function to extract the contact
information for both the defect itself and the component associated with the defect.
Schema validation
The XQueryNamespace.java program is used to process the namespace.xq XQuery source.
Because the XQuery is schema aware, XQueryNamespace must specify that schema
validation is required. It does this with the call to setValidating on XFactory:
factory.setValidating(XFactory.FULL_VALIDATION);
70
Getting Started with the WebSphere Application Server Feature Pack for XML
Because the XQuery makes use of annotated types from the Defects.xsd and
ExtendedDefect.xsd schemas, it must also make the schema available to the Feature Pack
for XML run time at prepare time by resolving the schema source for ExtendedDefect.xsd and
by registering it with XFactory.
Example 3-20 Resolving and registering the schema source
URL schemaURL = XQueryNamespace.class.getResource("/schema/ExtendedDefect.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
...
factory.registerSchema(schemaSource);
For demonstration purposes, the program does not register Defects.xsd or Components.xsd
with XFactory directly. Instead, it makes the schema available using an XSchemaResolver:
XSchemaResolver resolver = new SimpleSchemaResolver();
factory.setSchemaResolver(resolver);
The Feature Pack for XML run time calls the SimpleSchemaResolver (described in
“SimpleSchemaResolver” on page 114) when it needs to resolve a schema.
The program output shows that the Feature Pack for XML run time calls the
SimpleSchemaResolver at prepare time to resolve the Defects.xsd schema and at execution
time to resolve the Components.xsd schema. Note that the Defects.xsd schema is resolved
when the schema resolution mechanism implicitly resolves the import of the defect
namespace contained within the ExtendedDefect.xsd schema.
The SimpleSchemaResolver implements the XSchemaResolver interface to resolve the
schema source themselves based on namespace, locations and baseURI information passed
to that interface by the run time, returning the schema as a List of Source objects. This simple
implementation just uses the namespace parameter passed by the run time to select a
schema loadable from predefined source files.
Example 3-21 shows the output.
Example 3-21 SimpleSchemaResolver output
FOUND DEFECT NAMESPACE
XQUERY PREPARED, ABOUT TO EXECUTE
FOUND COMPONENT NAMESPACE
<?xml version="1.0" encoding="UTF-8"?>
<OpenDefects>
<Defect
number="2"><defect_contacts>dan_matthews,swarajit_roy,</defect_contacts><component
_contacts>Dan's Manager</component_contacts></Defect>
<Defect number="4"><defect_contacts>swarajit_roy,khurram_faraaz,Our Little Helper
Co</defect_contacts><component_contacts>Swarajit's
Manager</component_contacts></Defect>
<Defect number="5"><defect_contacts>swarajit_roy,dan_matthews,Our Little Helper
Co</defect_contacts><component_contacts>Swarajit's
Manager</component_contacts></Defect>
</OpenDefects>
Non-compliant data
The XQueryNamespace program accepts a parameter string specifying the name of the
source XML file for the defect data. By passing in a value of the DefectsNSnoncompliant.xml
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
71
file (shown in Example 3-22), you can see how the run time handles XML data that does not
comply with its schema.
Example 3-22 The DefectsNSnoncompliant.xml file
<?xml version="1.0" encoding="UTF-8"?>
<Defects xmlns="http://com.ibm.xml.samples"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://com.ibm.xml.samples
http://com.ibm.xml.samples.component/Defects.xsd">
<Defect number="0001" component="widget.calculator">
<abstract>function calculates incorrect result</abstract>
<state>working</state>
<developer>dan_matthews</developer>
<tester>swarajit_roy</tester>
</Defect>
<Defect number="0002" component="widget.calculator">
<state>open</state>
<developer>dan_matthews</developer>
<tester>swarajit_roy</tester>
</Defect>
<Defect number="0003" component="widget.gui">
<abstract>Incorrect graphic used for company logo</abstract>
<state>closed</state>
<developer>khurram_faraaz</developer>
<tester>swarajit_roy</tester>
</Defect>
<extdefect:ExtendedDefect xmlns:extdefect="http://com.ibm.xml.samples.ext"
xsi:schemaLocation="http://com.ibm.xml.samples.ext
http://com.ibm.xml.samples.component/ExtendedDefects.xsd" number="0004"
component="widget.documentation">
<state>open</state>
<developer>swarajit_roy</developer>
<tester>khurram_faraaz</tester>
<extdefect:outsource_company>Our Little Helper Co</extdefect:outsource_company>
</extdefect:ExtendedDefect>
<Defect xmlns:extdefect="http://com.ibm.xml.samples.ext"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="extdefect:ExtendedDefectType" number="0005"
component="widget.documentation">
<abstract>Documentation requires translation</abstract>
<state>open</state>
<developer>swarajit_roy</developer>
<tester>dan_matthews</tester>
<extdefect:outsource_company>Our Little Helper Co</extdefect:outsource_company>
</Defect>
</Defects>
The output now includes the following error message, but the execution of the XQuery
continues:
ERROR: cvc-complex-type.2.4.a: Invalid content was found starting with element
'state'. One of '{"http://com.ibm.xml.samples":abstract}' is expected.;
72
Getting Started with the WebSphere Application Server Feature Pack for XML
In this case, the results are shown in Example 3-23.
Example 3-23 Output when XML data is non-compliant
<?xml version="1.0" encoding="UTF-8"?>
<OpenDefects><Defect number="5"><defect_contacts>swarajit_roy,dan_matthews,Our
Little Helper Co</defect_contacts><component_contacts>Swarajit's
Manager</component_contacts></Defect>
</OpenDefects>
The results do not contain data for defects 4 and 5 because these two Defect elements do not
contain <abstract> elements and, thus, are not compliant with the Defects.xsd schema. In
such a case, you might want to halt execution of the XQuery evaluation and return an error by
overriding the default message handling using the XMessageHandler interface.
In this case, we are concerned with an execution time error, so we can register the
XMessageHandler with the dynamic context or alternatively register it with XFactory itself.
If you are modifying the error handling at prepare time, you can register the
XMessageHandler with either XFactory or XStaticContext. The XQueryNamespace program
contains a commented line of code that you can uncomment. When the non-compliant
elements are now parsed, the SimpleXMessageHandler (shown in Example 3-24) object is
called.
Example 3-24 SimpleXMessageHandler.java
package messagehandler;
import
import
import
import
com.ibm.xml.xapi.XMessageHandler;
com.ibm.xml.xapi.XProcessException;
com.ibm.xml.xapi.XSequenceCursor;
com.ibm.xml.xapi.XSourceLocation;
public class SimpleXMessageHandler implements XMessageHandler {
@Override
public void report(MsgType arg0, String arg1, XSourceLocation arg2,
Throwable arg3, XSequenceCursor arg4) {
throw new XProcessException(arg1, arg3);
}
}
This message handler simply throws an XProcessException that causes the XQuery
evaluation to fail:
//dynamicContext.setMessageHandler(new SimpleXMessageHandler());
3.7.3 NavigatingXSequence
This example demonstrates how to process results using the XSequenceCursor and
XTreeCursor interfaces using the NavigatingXSequence.java program, which is shown in
“NavigatingXSequence” on page 104.
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
73
Download material: This example uses the following code and files:
򐂰 Java program: NavigatingXSequence
򐂰 XQueries: simpleqjoin.xq
򐂰 Source data: Components.xml and Defects.xml
Preparing and executing the XQuery is done in exactly the same way as with the
SimpleXQueryExecutor program. This example even uses the same simplejoin.xq XQuery
shown in Example 3-10 on page 64.
Each item in the sequence is a complex element that has a QName of Component.
After obtaining the XSequenceCursor from the execution of the XQuery, the program passes
it to the processSequenceWithCursors function. This function uses a do{..} while(...) loop
to iterate over the sequence, progressing the XSequenceCursor by a call to the
XSequenceCursor.toNext() function in the while statement. XSequenceCursor implements
XItemView and XNodeView and these interfaces can be used to process the item or node
that the XSequenceCursor is currently positioned to in the sequence.
We are not sure whether the current item is a node or an atomic value. So, we use the
XItemView.isAtomic() method, shown in Example 3-25, to check that the current item is in fact
a node. We can then use the XNodeView interface to further check that the current node is an
element with the expected QName. Failure to check that the current item is a node before
using the XNodeView interface will result in an XViewException if the current item is an
atomic item.
Example 3-25 Using the XItemView.isAtomic method
if(!componentItemView.isAtomic() &&
XNodeView.Kind.ELEMENT.equals(componentItemView.getKind()) &&
"Component".equals(componentItemView.getNodeQName().getLocalPart())) {
...
}
To process the internals of the Component element, you can use the XTreeCursor interface.
Obtain the XTreeCursor for the current item in the XSequence as follows:
XTreeCursor treeCursor = componentItemView.getTreeCursor();
To process the Component element’s attributes, move the XTreeCursor to the first attribute,
and then process each attribute in a while loop, moving the cursor using the toNextAttribute()
method, as shown in Example 3-26.
Example 3-26 Processing the Component elements’s attributes
boolean attributeExists = treeCursor.toFirstAttribute();
while(attributeExists) {
if("id".equals(treeCursor.getNodeQName().getLocalPart()))
component.id = treeCursor.getStringValue();
if("manager".equals(treeCursor.getNodeQName().getLocalPart()))
component.manager = treeCursor.getStringValue();
attributeExists = treeCursor.toNextAttribute();
}
74
Getting Started with the WebSphere Application Server Feature Pack for XML
After the processing is complete, you can process the children. However, you must first move
the treeCursor back to the parent (the Component node that contains the attributes) as shown
in Example 3-27.
Note that although attributes of an element are children of that element, they are children
along the attribute axis and, thus, are not present in the items accessed by
XTreeCursor.toFirstChild() and subsequent calls to XTreeCursor.toNextSibling().
Example 3-27 Process the children
boolean childToProcess = treeCursor.toFirstChild();
while(childToProcess) {
if(!treeCursor.isAtomic() &&
XNodeView.Kind.ELEMENT.equals(treeCursor.getKind()) &&
"DefectNumber".equals(treeCursor.getNodeQName().getLocalPart())) {
...
}
childToProcess = treeCursor.toNextSibling();
}
Processing of Defect child elements then proceeds in much the same way as for the
Component elements. XTreeCursor, like XSequenceCursor, implements the XItemView and
XnodeView interfaces that act on the current item or node at which the cursor is currently
positioned. Unlike XSequenceCursor it is more natural to use a while loop because we must
first move down to the first child, process it, then iterate to the next sibling.
After you process the XSequenceCursor using the processSequenceWithCursors method,
you need to re-process it with a slightly different algorithm. To do so, bring the
XSequenceCursor to its original state, with the cursor positioned at the first item in the
sequence, because you updated the cursor position while iterating over it with the toNext()
method:
while(sc.toPrevious()); // Rewind the cursor
You can now call processSequenceWithCursorsAlt. The only difference between this method
and the last one is how you obtain the items in the sequence. In this method, you use the
XSequenceCursor.exportAsList() method to obtain a List of XItemView objects, and you
simply iterate over the XItemView objects from the List, as shown in Example 3-28.
Example 3-28 Obtain a list of XItemView objects
for(XItemView componentItemView : xItemList) {
if(!componentItemView.isAtomic() &&
XNodeView.Kind.ELEMENT.equals(componentItemView.getKind()) &&
"Component".equals(componentItemView.getNodeQName().getLocalPart())) {...
XTreeCursor treeCursor = componentItemView.getTreeCursor();
...
}
}
Notice that we can call this method twice without repositioning the XSequenceCursor
because neither our application code nor the Feature Pack for XML run time update the
cursor position when accessing the items in the sequence in this way.
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
75
3.7.4 UsingDOMResult
This example uses the UsingDOMResult program to demonstrate how to process results
using DOM, as shown in “UsingDOMResult” on page 107.
Download material: This example uses the following code and files:
򐂰 Java program: UsingDOMResult
򐂰 XQueries: simpleqjoin.xq
򐂰 Source data: Components.xml and Defects.xml
The example uses the simplejoin.xq XQuery, shown in Example 3-10 on page 64.
The UsingDOMResult program creates an instance of DOMResult and passes it as a
parameter on the XQueryExecutable.execute() method. If you want to process StAX or SAX
results, simply use an instance of the StAXResult or SAXResult classes respectively:
DOMResult domResult = new DOMResult();
xqe.execute(domResult);
The program then processes the DOMResult object using the DOM API. It produces exactly
the same result (of course) as the NavigatingXSequence program.
3.7.5 CachingResults
This example demonstrates how the results from one XQuery can be cached and then used
as the input for a later XQuery (or XPath or XSLT) expression. The CachingResults.java
program, shown in “CachingResults” on page 109, is simply an extended version of
NavigatingXSequence.
Download material: This example uses the following code and files:
򐂰 Java program: CachingResults
򐂰 XQueries: simpleqjoin.xq and findDefectsForManager.xq
򐂰 Source data: Components.xml and Defects.xml
After generating the output XSequenceCursor from the simplejoin.xq XQuery (shown in
Example 3-10 on page 64), the program processes the results using the
NavigatingXSequence.processSequenceWithCursors method. It then rewinds the cursor and
caches the XSequenceCursor in an instance of an XCollectionResolver, keyed off a collection
URI string.
The program then prepares and executes a further findDefectsForManager.xq XQuery,
shown in Example 3-29, setting the collection resolver into the dynamic context that is used to
execute the request.
Example 3-29 The findDefectsForManager.xq XQuery
declare variable $manager_name as xs:string external;
let $components := fn:collection("http://defectsByComponent")
for $component in $components
let $defnums := $component//DefectNumber
where $component/@manager = $manager_name
return $defnums
76
Getting Started with the WebSphere Application Server Feature Pack for XML
The code snippet shown in Example 3-30 caches the results in a collection resolver. The
code for the CachedCollectionResolver is shown in “CachedCollectionResolver” on page 114.
Example 3-30 Cache the results in a collection resolver
CachedCollectionResolver collectionResolver = new CachedCollectionResolver();
collectionResolver.setCachedSequence("http://defectsByComponent", sc);
...
XDynamicContext dynamicContext = factory.newDynamicContext();
dynamicContext.setCollectionResolver(collectionResolver);
...
StreamResult toSystemOut = new StreamResult(System.out);
fdfmExecutable.execute(dynamicContext, toSystemOut);
The findDefectsForManager XQuery uses a FLWOR expression to process the cached
sequence. The cached sequence is accessed using the fn:collection function with the
parameter value being the string URI we used to cache the XSequenceCursor in the Java
program:
let $components := fn:collection("http://defectsByComponent")
The XQuery then uses a FLWOR expression to process each (Component element) item in
the sequence, filtered by its manager attribute and returning the associated DefectNumber
elements. The where clause uses the $manager_name variable that is declared as external.
declare variable $manager_name as xs:string external;
The CachingResults program provides the value to which the variable is bound at execution
time using the instance of the XDynamicContext API that is used to execute the query.
dynamicContext.bind(new QName("manager_name"), "Dan's Manager");
The program then goes on to process the original XSequenceCursor again, this time with
NavigatingXSequence.processSequenceWithCursorsAlt. It uses this version of processing
the XSequenceCursor for thread-safety reasons, because after the object is published
through the ConcurrentHashMap in the collection resolver, it is not thread-safe to reposition
the cursor because the object i no longer effectively immutable.
Note that the sequence itself and the items in the sequence are immutable, only the cursor
position of an XSequenceCursor is mutable. Furthermore, when the run time processes the
XSequenceCursor returned from the collection resolver it does not change its internal state.
Although such thread-safety issues are not relevant to this simple example which executes on
a single thread, they are relevant to the general principals of caching the XSequenceCursor.
The program finishes by processing the findDefectsForManager XQuery again, using a
different manager name. Example 3-31 shows the output from the program.
Example 3-31 Program output
[Component manager Dan's Manager, id widget.calculator has defects [Defect number
0001, Defect number 0002], Component manager Swarajit's Manager, id
widget.documentation has defects [], Component manager Khurram's Manager, id
widget.gui has defects [Defect number 0003]]
<?xml version="1.0" encoding="UTF-8"?><DefectNumber number="0001"/><DefectNumber
number="0002"/>
[Component manager Dan's Manager, id widget.calculator has defects [Defect number
0001, Defect number 0002], Component manager Swarajit's Manager, id
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
77
widget.documentation has defects [], Component manager Khurram's Manager, id
widget.gui has defects [Defect number 0003]]
<?xml version="1.0" encoding="UTF-8"?><DefectNumber number="0003"/>
3.7.6 ExternalFunctionXQuery
This example uses the ExternalFunctionXQuery Java program to demonstrate the use of an
external function in an XQuery using the IBM XML API. It is an extended version of the
XQueryNamespace program, processing a modified externalfunction.xq XQuery, which uses
an external function. The code for ExternalFunctionXQuery is shown in
“ExternalFunctionXQuery” on page 110.
Download material: This example uses the following code and files:
򐂰 Java program: ExternalFunctionXQuery
򐂰 XQueries: externalfunction.xq
򐂰 Source data: ComponentsNS.xml and DefectsNS.xml
The ExternalFunctionXQuery Java program declares the namespace in which the function
name exists, binding the prefix external to the "http://xmlfep.external.function"
namespace, using an instance of the XStaticContext API, which it later uses when preparing
the XQuery.
XStaticContext staticContext = factory.newStaticContext();
staticContext.declareNamespace("external", "http://xmlfep.external.function");
A namespace declaration is required because the XQuery needs to specify the QName of the
function to reference it correctly, although you can also use a namespace declaration in the
XQuery prolog itself, as shown in the commented out namespace declaration in the XQuery.
(: declare namespace external = "http://xmlfep.external.function"; :)
The XQuery also requires the external function to be declared. Declaration of a function
specifies the QName of the function and the types of the input parameters and the return
value. The program does this through the XStaticContext API.
QName getTelephoneNumberQName = new QName("http://xmlfep.external.function",
"getTelephoneNumberExt");
staticContext.declareFunction(getTelephoneNumberQName,
XTypeConstants.STRING_QNAME, new QName [] {XTypeConstants.STRING_QNAME});
This example shows that the external function is assigned the local name
getTelephoneNumberExt in the "http://xmlfep.external.function" namespace, takes a
single argument of type xs:string, and returns a value of type xs:string. Again, you can
make the function declaration in the XQuery prolog itself as per the commented out
declaration:
(: declare function external:getTelephoneNumberExt($x as xs:string) as xs:string
external; :)
78
Getting Started with the WebSphere Application Server Feature Pack for XML
Before executing the XQuery, the program must use the IBM XML API to provide the
implementation of the function to be bound to the function name. It does this with the instance
of the XDynamicContext that it uses when executing the XQuery (Example 3-32).
Example 3-32 Using XDynamicContext
XDynamicContext dynamicContext = factory.newDynamicContext();
Method getTelephoneNumberMethod =
ExternalDirectoryFunction.class.getMethod("getTelephoneNumber", String.class);
ExternalDirectoryFunction externalDirectoryInstance = new
ExternalDirectoryFunction();
dynamicContext.bindFunction(getTelephoneNumberQName, getTelephoneNumberMethod,
externalDirectoryInstance);
XSequenceCursor sc = xqe.execute(dynamicContext);
After obtaining the XDynamicContext from the XFactory the program obtains the
java.lang.reflect.Method through Java’s reflection API. The program must then use the
bindFunction method on the XDynamicContext API to bind the implementation to the function
name.
In this case the method is an instance method, associated with a specific instance of an
object, so an instance of the object must be created and the following method is used:
bindFunction(QName functionQName, Method
instance_method_implementing_the_function, Object instance)
For static methods, no object instance is required and the following method is used instead:
bindFunction(QName functionQName, Method static_method_implementing_the_function)
Inside the XQuery, the external function is used in exactly the same way as a user-defined
method. For example, in the XQuery, we invoke the external function as follows:
external:getTelephoneNumberExt($a/xmlsampcomp:manager/child::node())
The external function in this example simply uses a string representing a contact name to
look up a corresponding telephone number for that contact, its source is
ExternalDirectoryFunction.java.
Example 3-33 shows the output for the program.
Example 3-33 Program output
FOUND DEFECT NAMESPACE
XQUERY PREPARED, ABOUT TO EXECUTE
FOUND COMPONENT NAMESPACE
<?xml version="1.0" encoding="UTF-8"?>
<OpenDefects>
<Defect number="2">
<defect_contacts>
<contact>dan_matthews, +44 1111 111111</contact>
<contact>swarajit_roy, +91 3333 333333</contact>
</defect_contacts>
<component_contacts>
<contact>Dan's Manager, +44 5555 555555</contact>
</component_contacts>
</Defect>
<Defect number="4">
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
79
<defect_contacts>
<contact>swarajit_roy, +91 3333 333333</contact>
<contact>khurram_faraaz, +91 2222 222222</contact>
<contact>Our Little Helper Co, +1 4444 444444</contact>
</defect_contacts>
<component_contacts>
(<contact>Swarajit's Manager, +91 7777 777777</contact>)
</component_contacts>
</Defect>
<Defect number="5">
<defect_contacts>
<contact>swarajit_roy, +91 3333 333333</contact>
<contact>dan_matthews, +44 1111 111111</contact>
<contact>Our Little Helper Co, +1 4444 444444</contact>
</defect_contacts>
<component_contacts>
(<contact>Swarajit's Manager, +91 7777 777777</contact>)
</component_contacts>
</Defect>
</OpenDefects>
3.7.7 DerbyXQuery and DB2XQuery
This example illustrates how an XQuery expression can be evaluated over input data sourced
from a database using the XCollectionResolver interface.
Download material: This example uses the following code and files:
򐂰 Java program: DatabaseXQuery
򐂰 XQueries: database.xq
򐂰 Source data: Derby, DB2 databases, and Components.xml
Derby examples
This example uses the DatabaseXQuery Java program to illustrate accessing input XML data
from a Derby database using either non-XML SQL data types or XML data types without full
SQL or XML support. The code for this program is shown in “DatabaseXQuery” on page 112.
The program uses a Derby database called XMLFEPDB.
Download material: See the following sections for information about creating the
databases for the samples and configuring the client and server environments:
򐂰 “Creating the databases for the examples” on page 33
򐂰 “Preparing for the database examples” on page 30
򐂰 “Preparing for the DB2 database example” on page 32
In this example, the DerbyXQuery processes the database.xq XQuery, shown in
Example 3-34.
Example 3-34 The database.xq XQuery
(: declare variable $database_url as xs:string external; :)
let $defects := fn:collection($database_url)
let $components := doc("../xmldata/Components.xml")
for $component in $components//Component
80
Getting Started with the WebSphere Application Server Feature Pack for XML
order by $component/id
return
<Component id="{$component/id}" manager="{$component/manager}">
{
for $defect in $defects//Defect
where $defect/@component = $component/id
order by $defect/@number
return <DefectNumber>{$defect/@number}</DefectNumber>
}
</Component>
This XQuery is almost identical to the simplejoin.xq and produces the same output, given
the same input source. The difference is that it obtains the $defects input sequence using the
fn:collection function. The collection URI string is an external variable passed in by the Java
program using the IBM XML API.
let $defects := fn:collection($database_url)
The DerbyXQuery program declares the database_url variable on the instance of the
XStaticContext used to prepare the XQuery with the following code:
XStaticContext staticCtx = factory.newStaticContext();
staticCtx.declareVariable(new QName("database_url"), XTypeConstants.STRING_QNAME);
XQueryExecutable xqe = factory.prepareXQuery(source, staticCtx);
Later, the program binds a value to the variable on the instance of the XDynamicContext used
to execute the XQuery. It also sets the XCollectionResolver for the execution of the XQuery to
an instance of the DatabaseCollectionResolver class (see “DatabaseCollectionResolver” on
page 116). The program is responsible for opening the JDBC connection to the database and
setting it in the DatabaseCollectionResolver for later use when accessing the data from the
database. Example 3-35 shows the code that performs these actions.
Example 3-35 Using the DatabaseCollectionResolver
XDynamicContext dynamicCtx = factory.newDynamicContext();
DatabaseCollectionResolver dbCollectionResolver = new
DatabaseCollectionResolver();
dbCollectionResolver.setConnection(dbConnection);
dynamicCtx.setCollectionResolver(dbCollectionResolver);
dynamicCtx.bind(new QName("database_url"), database_url);
XSequenceCursor sc = xqe.execute(dynamicCtx);
The DatabaseCollectionResolver class is responsible for resolving the collection URI string
specified on the fn:collection function in the XQuery, which is passed as a parameter to the
XCollectionResolver's getCollection method. Depending on the value of this string the
DatabaseCollectionResolver accesses data in the different databases and tables.
The processing performed by the DatabaseCollectionResolver for any URI follows the same
basic pattern:
1. Create an ArrayList of XItemView objects using the XItemFactory:
XFactory xFactory = XFactory.newInstance();
XItemFactory itemFactory = xFactory.getItemFactory();
ArrayList<XItemView> items = new ArrayList<XItemView>();
2. Access the data from the database.
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
81
3. For each record in the table, create an XItemView object for that data and add the
XItemView to the ArrayList:
XItemView item = itemFactory.item(new StreamSource(new
ByteArrayInputStream(fragmentStr.getBytes())));
items.add(item);
4. Create an XSequenceCursor for the XItemView ArrayList and return it:
XSequenceCursor sequence = itemFactory.sequence(items.toArray(new
XItemView[0]));
...
return sequence;
By default, the value of the collection URI is "http://derbydefects". In this case, the
collection resolver performs a standard select statement to obtain the data from the non-XML
table DEFECTS, and processes each record in the ResultSet in the standard manner as per
the table’s schema, to extract the data for each column type.
In this case, we want to present the data to the XQuery as standard XML by composing a
String to represent the Defect element. We use this string as an array of bytes from which we
can create a javax.xml.transform.Source object. From this object, we create an XItemView
using the XItemFactory, as shown in Example 3-36.
Example 3-36 Creating an XItemView
String sqlselect = "SELECT * FROM DEFECTS";
...
while (resultSet.next()) {
int number = resultSet.getInt("NUMBER");
String component = resultSet.getString("COMPONENT");
...
String fragmentStr =
"<Defect " + "number=\"" +number+ "\" " + "component=\"" +component+ "\" " +
">" +
"<abstract>"+abstractStr+"</abstract>" +
"<state>"+state+"</state>" +
"<developer>"+developer+"</developer>" +
"<tester>"+tester+"</tester>" +
"</Defect>";
fragmentStr.getBytes();
XItemView item = itemFactory.item(new StreamSource(new
ByteArrayInputStream(fragmentStr.getBytes())));
...
}
The program produces the output shown in Example 3-37 when processing the
http://derbydefects collection:
Example 3-37 Output from the DatabaseXQuery program
found DEFECTS
<?xml version="1.0" encoding="UTF-8"?>
<Component id="widget.calculator" manager="Dan's Manager"><DefectNumber
number="1"/><DefectNumber number="2"/></Component>
<Component id="widget.documentation" manager="Swarajit's Manager"/>
<Component id="widget.gui" manager="Khurram's Manager"><DefectNumber
number="3"/></Component>
82
Getting Started with the WebSphere Application Server Feature Pack for XML
The DerbyXQuery program accepts the value to use for the collection URI string as a single
parameter. By invoking the program with a parameter value of
http://derbydefectsXMLasCLOB, the DatabaseCollectionResolver accesses the data that is
stored as XML in the DEFECTXML table. Derby does not support the java.sql.SQLXML type,
so XML data must be bound to a different suitable type. In this case, we used the CLOB type
as shown in the SELECT statement that is used to retrieve the data:
String sqlselect = "SELECT XMLSERIALIZE(DEFECT AS CLOB) FROM DEFECTXML";
When processing each row in the ResultSet, we extract the XML data as a CLOB, create a
javax.xml.transform.Source object from the CLOB ASCII stream and create the XItemView
from that as shown in Example 3-38.
Example 3-38 Code to process rows using CLOB
while (resultSet.next()) {
Clob clob = resultSet.getClob(1);
StreamSource ss = new StreamSource(clob.getAsciiStream());
XItemView item = itemFactory.item(ss);
clob.free();
items.add(item);
}
The program produces the output shown in Example 3-39 when processing the
http://derbydefectsXMLasCLOB collection.
Example 3-39 Output when extracting data as a CLOB
found DB2 Native XQuery
<?xml version="1.0" encoding="UTF-8"?>
<Component id="widget.calculator" manager="Dan's Manager"><DefectNumber
number="0002"/></Component>
<Component id="widget.documentation" manager="Swarajit's Manager"/>
<Component id="widget.gui" manager="Khurram's Manager"/>
DB2 examples
You can also use the DatabaseXQuery application to run the DB2 examples. To configure the
DB2 database for the sample, run the CreateDB2Tables helper program to create the
DEFECTSDB2 table. You can run the LoadDataIntoDB2 program to populate the tables with
data. See 1.12.4, “Creating the databases for the examples” on page 33. To execute these
utility programs and to execute the DatabaseXQuery application to process data from DB2,
you must include the db2jcc4.jar file, is in the DB2 installation directory in the java
subdirectory, in the Java class path.
Invoking DatabaseXQuery with a parameter of http://db2defectsXML causes the program to
use that value as the collection URI. When processing this collection URI string, the
DatabaseCollectionResolver reads the XML data stored in the DEFECTSDB2 table as XML
and process it using the java.sql.SQLXML type, which DB2 version 9 fully supports (see
Example 3-40). The SQLXML API supports generation of javax.xml.transform.Source objects
using the getSource method, taking the class of the desired Source type as an input
parameter.
Example 3-40 XML data is read from DB2
String sqlselect = "SELECT DEFECT FROM DEFECTSDB2";
...
while (resultSet.next()) {
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
83
SQLXML sqlx = resultSet.getSQLXML("DEFECT");
StreamSource ss = sqlx.getSource(StreamSource.class);
XItemView item = itemFactory.item(ss);
sqlx.free();
items.add(item);
}
The program produces the output shown in Example 3-41 when processing the
http://db2defectsXML collection.
Example 3-41 Program output
found DB2DEFECTS
<?xml version="1.0" encoding="UTF-8"?>
<Component id="widget.calculator" manager="Dan's Manager"><DefectNumber
number="0001"/><DefectNumber number="0002"/></Component>
<Component id="widget.documentation" manager="Swarajit's Manager"/>
<Component id="widget.gui" manager="Khurram's Manager"><DefectNumber
number="0003"/></Component>
Invoking DatabaseXQuery with a parameter of http://db2XQuery:open causes the program
to use that value as the collection URI. When processing this collection URI string, the
DatabaseCollectionResolver performs a native XQuery to DB2 on the XML data in the
DEFECTXML table.
Example 3-42 Performing a native XQuery on DB2
String pureXQueryStr =
"xquery for $y in db2-fn:xmlcolumn" +
"('DEFECTSDB2.DEFECT') " +
"where $y/Defect/state=\"open\" " +
"return $y";
In this case, the XQuery running inside DB2 uses a FLWOR expression to return a sequence
of Defect elements that have state child element with a value of open. Example 3-43 shows
the code that processes the resultSet of the native XQuery.
Example 3-43 Code to process the resultSet of the native XQuery
while (resultSet.next()) {
SQLXML sqlx = resultSet.getSQLXML(1);
StreamSource ss = sqlx.getSource(StreamSource.class);
XItemView item = itemFactory.item(ss);
sqlx.free();
items.add(item);
}
This native XQuery results in a single result in the ResultSet for each Defect element that
matches the 'where' criteria, although in the sample data there is only one such defect. The
program produces the output shown in Example 3-44 when processing the
http://db2XQuery:open collection.
Example 3-44 Output from the DB2 native XQuery
found DB2 Native XQuery
<?xml version="1.0" encoding="UTF-8"?>
84
Getting Started with the WebSphere Application Server Feature Pack for XML
<Component id="widget.calculator" manager="Dan's Manager"><DefectNumber
number="0002"/></Component>
<Component id="widget.documentation" manager="Swarajit's Manager"/>
<Component id="widget.gui" manager="Khurram's Manager"/>
For more information about using XQuery with databases, see the developerWorks®
document “Programming XML across the multiple tiers: Use XML in the middle tier for
performance, fidelity, and development ease,” which is available at:
http://www.ibm.com/developerworks/xml/library/x-xmlfeat1/index.html
3.8 Summary
XQuery contains many more built-in functions, operators and expressions than we discuss
here. Reading the specifications (or a good book) is recommended to gain a more complete
understanding of the fullness of the function that XQuery provides. The information that we
provide here is a sufficient grounding to explore the Feature Pack for XML.
You can find a fuller description of the requirements that XQuery 1.0 was designed to satisfy
in the XML Query Requirements document published by the W3C at:
http://www.w3.org/TR/xquery-requirements/
Chapter 3. Using the XQuery features of the WebSphere Application Server Feature Pack for XML
85
86
Getting Started with the WebSphere Application Server Feature Pack for XML
4
Chapter 4.
Using the XSLT features of the
WebSphere Application Server
Feature Pack for XML
XML Stylesheet Language Transformation (XSLT) is a declarative XML-based language that
is used to transform an input XML document into other formats such as XML, HTML, XHTML,
or plain text. During transformation, program logic can be infused to generate a very different
(according to the business need) output.
This chapter provides examples of using XSLT features included with the WebSphere
Application Server Feature Pack for XML, Version 1.0. (referred to as the Feature Pack for
XML in this document).
© Copyright IBM Corp. 2010. All rights reserved.
87
4.1 XSLT overview
XSLT is a robust programming platform. The program specification is maintained by the World
Wide Web Consortium (W3C). At present, XSLT 2.0 is the latest standard.
You can use XSLT to transform XML to HTML or XHTML in websites. The transformation can
be performed at the server side and content can be sent back to the web user agent.
Transformation can also be performed at the client side using an XSLT-aware browser:
however, note that although most browsers support XSLT 1.0, support for XSLT 2.0 is limited
at this time. XSLT is also used for XML to XML transformation in integration architecture
spaces, messaging scenarios, and other cases.
The Feature Pack for XML brings the features of XSLT 2.0 to applications deployed on
WebSphere Application Server. IBM Rational Application Developer 7.5.5 provides excellent
support for XSLT 2.0 compliant style sheet authoring.
Most XSLT implementation engines provide a mechanism to compile style sheets. You should
take advantage of this feature to enhance transformation performance.
XSLT 2.0 includes the following features:
򐂰
򐂰
򐂰
򐂰
򐂰
򐂰
򐂰
򐂰
Multiple output documents
Built-in support for grouping
Date and time data formatting
Regular expression support
User-defined functions
XHTML output
Other serialization enhancements
(Optional) Schema awareness
We explain these capabilities in detail in the example section.
4.2 XSLT 2.0 examples
Download materials: The samples in this chapter are compressed into a project
interchange file for use with Rational Application Developer 7.5.5. You can extract them
into a file system for reference. For information about obtaining these materials, see
Appendix B, “Additional material” on page 121.
Download the XSLT/XMLFPSamplePrograms.zip file into a directory. In this paper, we refer to
this directory as download_directory.
In this section, we show examples of some of the features that are exclusive to XSLT 2.0. The
examples take advantage of the Feature Pack for XML 1.0 thin client version and do not
require a WebSphere Application Server instance to run them. We use Rational Application
Developer 7.5 (upgraded to 7.5.5 with Feature Pack for XML 1.0 installed) and create a Java
Project to setup the development project.
88
Getting Started with the WebSphere Application Server Feature Pack for XML
4.2.1 Setting up the Java project in Rational Application Developer 7.5.5
with the thin client
This paper uses a set of examples to illustrate some of the highlights of the Feature Pack for
XML. In this section, we create a Java project in Rational Application Developer for the
samples that we develop to showcase some of the XSLT 2.0 features.
Download materials: To use the samples included with this document, you will need
Rational Application Developer 7.5.5 or later. The download material contains a project
interchange file that can be imported into the Rational workspace.
To import the samples into your workspace, select File  Import  Other  Project
Interchange. Browse to the download_directory/XSLT directory and select
XMLFPSamplePrograms.
To keep things lightweight, we will use the Feature Pack for XML thin client JAR file. The thin
client is in the following directory:
WAS_install_root\feature_packs\xml\runtimes\com.ibm.xml.thinclient1.0.0.jar
In a Rational Application Developer installation with the WebSphere Application Server V7
unit test environment, this will be:
RAD_install\runtimes\base_v7\feature_packs\xml\runtimes\com.ibm.xml.thinclient1.0.
0.jar
When the project interchange file is imported into a Rational Application Developer
workspace, you will have a project named XMLFPSamplePrograms. You need to replace the
thin client JAR file location in the build path for the project to match your RAD_install location.
1. Right-click the project name and select Build Path  Configure Build Path.
2. Select com.ibm.xml.thinclient_1.0.0.jar, and click Remove. (The JAR file included here
reflects the installation path of the author’s systems, not necessarily yours).
3. Click Add External Jars.
4. Browse to the location of the thin client JAR file:
RAD_install\runtimes\base_v7\feature_packs\xml\runtimes
Select com.ibm.xml.thinclient_1.0.0.jar, and click OK.
The resulting project structure looks similar to Figure 4-1.
Figure 4-1 Adding the thin client to the project
4.2.2 Transforming a simple XML using XSLT
In this section, we illustrate a very basic XML to XML transformation using an XSLT 2.0 style
sheet and the Feature Pack for XML 1.0 API.
Chapter 4. Using the XSLT features of the WebSphere Application Server Feature Pack for XML
89
Download materials: This example requires the following sample files:
򐂰 PROBLEM.xml
򐂰 SimpleTransformation.xsl
򐂰 SimpleXMLTransformation.java
The PROBLEM.xml file represents a typical problem ticket information for a system. It contains
information about the problem ticket ID, open date, close date, severity, and cause code kind
of information as elements.
Our goal is to transform the PROBLEM.xml file to a different XML format, where each
sub-element of element <ticket> becomes an attribute name and the sub-element text
becomes the attribute value.
Example 4-1 shows the Java program and the API.
Example 4-1 The SimpleXMLTransformation.java file
try {
XFactory factory = XFactory.newInstance();
XSLTExecutable xslt = factory.prepareXSLT(new StreamSource(new
File(xslFilePath)));
StreamSource input = new StreamSource(new File(filePath));
StreamResult output = new StreamResult(System.out);
xslt.execute(input, output);
}catch (Exception e) {
e.printStackTrace();
}
In this example:
򐂰 The com.ibm.xml.xapi.XFactory class is the main factory class for creating executables for
XPath, XQuery, and XSLT.
򐂰 Using the new instance of XFactory, we create the com.ibm.xml.xapi.XSLTExecutable. It
represents a prepared XSLT style sheet based on the XSL file path given to it.
򐂰 The input XML and the target output location is provided to the XSLTExecutable through
standard JAXP StreamSource and StreamResult classes and the execute method is
called, which is responsible for the transformation.
Note that the xsl:stylesheet element of the XSL file SimpleTransformation.xsl (Example 4-2)
shows that we are working with XSLT 2.0 (version 2.0). In this example, we do not use
anything specific to XSL 2.0.
Example 4-2 SimpleTransformation.xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" name="ticketExtract"/>
<xsl:template match="/">
<xsl:element name="tickets">
<xsl:for-each select="tickets/ticket">
90
Getting Started with the WebSphere Application Server Feature Pack for XML
<xsl:element name="ticket">
<xsl:attribute name="PROBLEM_ID">
<xsl:value-of select="PROBLEM_ID" />
</xsl:attribute>
<xsl:attribute name="PROBLEM_CODE">
<xsl:value-of select="PROBLEM_CODE" />
</xsl:attribute>
<xsl:attribute name="CLOSE_DATE">
<xsl:value-of select="CLOSE_DATE" />
</xsl:attribute>
<xsl:attribute name="OPEN_DATE">
<xsl:value-of select="OPEN_DATE" />
</xsl:attribute>
<xsl:attribute name="SEVERITY">
<xsl:value-of select="SEVERITY" />
</xsl:attribute>
<xsl:attribute name="CAUSE_CODE">
<xsl:value-of select="CAUSE_CODE" />
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
Example 4-3 shows the input XML.
Example 4-3 Input XML
<?xml version="1.0" encoding="UTF-8"?>
<tickets>
<ticket>
<PROBLEM_CODE>CLOSED</PROBLEM_CODE>
<CLOSE_DATE>2009-10-21</CLOSE_DATE>
<OPEN_DATE>2009-10-21</OPEN_DATE>
<SEVERITY>2</SEVERITY>
<PROBLEM_ID>22504302</PROBLEM_ID>
<CAUSE_CODE>DATABASE</CAUSE_CODE>
</ticket>
</tickets>
Example 4-4 shows the output XML.
Example 4-4 Output XML
<?xml version="1.0" encoding="UTF-8"?>
<tickets>
Chapter 4. Using the XSLT features of the WebSphere Application Server Feature Pack for XML
91
<ticket PROBLEM_ID="22504302" PROBLEM_CODE="CLOSED" CLOSE_DATE="2009-10-21"
OPEN_DATE="2009-10-21" SEVERITY="2" CAUSE_CODE="DATABASE"/>
</tickets>
4.2.3 Multiple output documents
In XSLT 1.0, an XSLT processor run can produce only one output document. Proprietary
extensions are needed to support the multiple output documents from one processor run (for
example, saxon:output). However in XSLT 2.0, the xsl:result-document element allows
multiple documents to be created from a single processor run. We demonstrate this capability
in this section.
Download materials: This example requires the following sample files:
򐂰 XSLT2MultipleOutputDocumentsDemo.xml
򐂰 XSLT2MultipleOutputDocumentsDemo.xsl
򐂰 XSLT2MultipleOutputDocumentDemo.java
Let us assume that we want to create an output XML that transforms all sub-elements of
<ticket> into attributes. The same transformation creates another text document that has the
problem ID and description of the ticket.
This example can be easily achieved by establishing two output formats at the beginning of
the style sheet and then transforming the logic under the <xsl:result-document> section.
Each <xsl:result-document> element has an href attribute that points to the URI of the file to
be generated and a format attribute to match the appropriate output (for example,
text/xml/html).
Example 4-5 shows the Java code for this example.
Example 4-5 The XSLT2MultipleOutputDocumentDemo.java file
import
import
import
import
import
public
java.io.File;
javax.xml.transform.stream.StreamResult;
javax.xml.transform.stream.StreamSource;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XSLTExecutable;
class XSLT2MultipleOutputDocumentDemo {
public static void main(String[] args) {
String filePath = "XSLT2MultipleOutputDocumentsDemo.xml" ;
String xslFilePath = "XSLT2MultipleOutputDocumentsDemo.xsl" ;
try {
XFactory factory = XFactory.newInstance();
XSLTExecutable xslt = factory.prepareXSLT(new StreamSource(new
File(xslFilePath)));
StreamSource input = new StreamSource(new File(filePath));
StreamResult output = new StreamResult(System.out);
xslt.execute(input, output);
}catch (Exception e) {
92
Getting Started with the WebSphere Application Server Feature Pack for XML
e.printStackTrace();
}
}
}
Example 4-6 shows the XSLT used for this transformation.
Example 4-6 XSLT2MultipleOutputDocumentsDemo.xsl
<xsl:output method="text" name="textFormat"/>
<xsl:output method="xml" name="xmlFormat"/>
<xsl:result-document href="output.txt" format="textFormat">
<xsl:result-document href="output.xml" format="xmlFormat">
The output files are available under the project interchange with the names output.txt and
output.xml.
4.2.4 Built-in support for grouping
XSLT 2.0 adds several features that greatly enhance the ability of style sheets to work with
data. In this section, we explore the new XSLT 2.0 feature called xsl:for-each-group.
Download materials: This example requires the following sample files:
򐂰 XSLT2GroupingNodesDemo.java
򐂰 XSLT2GroupingNodesDemo.xml
򐂰 XSLT2GroupingNodesDemo.xsl
Let us analyze the input XML for this example, XSLT2GroupingNodesDemo.xml (shown in
Example 4-7). The XML files contain a series of problem tickets. Each ticket has an element
called CAUSE_CODE, which represents the technology areas from which the ticket has been
created. In this example, an XML file is generated that groups these tickets based on the
distinct CAUSE_CODE values and then provides the necessary ticket information under each.
Example 4-7 Input XML snippet from XSLT2GroupingNodesDemo.xml
<tickets>
<ticket>
<PROBLEM_CODE>CLOSED</PROBLEM_CODE>
<CLOSE_DATE>2009-10-21</CLOSE_DATE>
<OPEN_DATE>2009-10-21</OPEN_DATE>
<SEVERITY>2</SEVERITY>
<PROBLEM_ID>22504302</PROBLEM_ID>
<CAUSE_CODE>DATABASE</CAUSE_CODE>
</ticket>
<ticket>
<PROBLEM_CODE>CLOSED</PROBLEM_CODE>
<CLOSE_DATE>2009-10-21</CLOSE_DATE>
<OPEN_DATE>2009-10-21</OPEN_DATE>
<SEVERITY>1</SEVERITY>
<PROBLEM_ID>22504345</PROBLEM_ID>
<CAUSE_CODE>APPLICATION_SERVER</CAUSE_CODE>
</ticket>
Chapter 4. Using the XSLT features of the WebSphere Application Server Feature Pack for XML
93
.....</tickets>
Example 4-8 shows the expected output after the grouping occurs.
Example 4-8 Expected output
<TICKET_CAUSE_CODE CAUSE_CODE_NAME="DATABASE">
<TICKET_DETAILS PROBLEM_ID="22504302" SEVERITY="2"
<TICKET_DETAILS PROBLEM_ID="22504356" SEVERITY="2"
<TICKET_DETAILS PROBLEM_ID="22504366" SEVERITY="3"
<TICKET_DETAILS PROBLEM_ID="22504312" SEVERITY="2"
</TICKET_CAUSE_CODE>
<TICKET_CAUSE_CODE CAUSE_CODE_NAME="APPLICATION_SERVER">
<TICKET_DETAILS PROBLEM_ID="22504345" SEVERITY="1"
CAUSE_CODE="APPLICATION_SERVER"/>
<TICKET_DETAILS PROBLEM_ID="22504322" SEVERITY="2"
CAUSE_CODE="APPLICATION_SERVER"/>
<TICKET_DETAILS PROBLEM_ID="22504300" SEVERITY="4"
CAUSE_CODE="APPLICATION_SERVER"/>
</TICKET_CAUSE_CODE>
<TICKET_CAUSE_CODE CAUSE_CODE_NAME="WEB_SERVER">
<TICKET_DETAILS PROBLEM_ID="22504302" SEVERITY="2"
<TICKET_DETAILS PROBLEM_ID="22509302" SEVERITY="2"
</TICKET_CAUSE_CODE>
CAUSE_CODE="DATABASE"/>
CAUSE_CODE="DATABASE"/>
CAUSE_CODE="DATABASE"/>
CAUSE_CODE="DATABASE"/>
CAUSE_CODE="WEB_SERVER"/>
CAUSE_CODE="WEB_SERVER"/>
In XSLT 1.0, this function is possible only through extensive XSL programming. However,
XSLT 2.0 supports this function through the xsl:for-each-group element. The select attribute
of the element can select a node and the group-by attribute allows you to determine the node
for which the grouping would happen. In this case, we apply the select attribute on the
<ticket> element and the group-by on <CAUSECODE>.
Example 4-9 shows the XSL used to perform the transformation.
Example 4-9 XSLT2GroupingNodesDemo.xsl
<xsl:for-each-group select="ticket" group-by="CAUSE_CODE">
<xsl:element name="TICKET_CAUSE_CODE">
<xsl:attribute name="CAUSE_CODE_NAME">
<xsl:value-of select="current-grouping-key()" />
</xsl:attribute>
<xsl:for-each select="current-group()">
<xsl:element name="TICKET_DETAILS">
<xsl:attribute name="PROBLEM_ID">
<xsl:value-of select="PROBLEM_ID" />
</xsl:attribute>
<xsl:attribute name="SEVERITY">
<xsl:value-of select="SEVERITY" />
</xsl:attribute>
<xsl:attribute name="CAUSE_CODE">
<xsl:value-of select="CAUSE_CODE" />
</xsl:attribute>
</xsl:element>
</xsl:for-each>
</xsl:element>
94
Getting Started with the WebSphere Application Server Feature Pack for XML
</xsl:for-each-group>
4.2.5 Date and time formatting
XSLT 2.0 provides the following functions for date and time data formatting:
򐂰 format-dateTime
򐂰 format-date
򐂰 format-time
The same functionality in XSLT 1.0 requires custom coding or the use of XSLT extension
functions from the vendors. In this section, we illustrate the use of the format-dateTime
function.
Download materials: This example requires the following sample files:
򐂰 XSLT2DateTimeFormattingDemo.xml
򐂰 XSLT2DateTimeFormattingDemo.xsl
򐂰 XSLT2DateTimeFormattingDemo.java
In this example, we need a transformation that adds an XML element at the top of the file to
show when the transformation happened. We also need to add the time stamp formatted into
a string that shows the day in day, month, year, and time zone as a time offset from UTC in
German, using ISO as the calendar and United States as the country.
We can achieve this transformation easily using format-dateTime, as shown in Example 4-10.
Example 4-10 XSLT2DateTimeFormattingDemo.xsl
<xsl:variable name="current-timestamp" select="current-dateTime()"/>
<xsl:element name="transform-info">
<xsl:attribute name="timestamp">
<xsl:value-of select="$current-timestamp" />
</xsl:attribute>
<xsl:attribute name="formatted-timestamp">
<xsl:value-of select="format-dateTime($current-timestamp, '[D1o] [MNn],
[Y], [Z]', 'de', 'ISO', 'US')"/>
</xsl:attribute>
</xsl:element>
The arguments of the format-dateTime function are as follows:
format-dateTime( $value as xs:dateTime?, $picture as xs:string, $language as
xs:string?, $calendar as xs:string?,$country as xs:string?)
The $picture as xs:string argument contains consists of a sequence of variable markers
and literal substrings used to format the time stamp. For information about using $picture,
see section 16.5.1 of the XSLT 2.0 specification at:
http://www.w3.org/TR/xslt20/#format-date
4.2.6 Character maps
We have already seen some of the serialization enhancements in XSLT 2.0 like multiple result
documents support (xsl:result-document), XHTML support (xsl:output new format
Chapter 4. Using the XSLT features of the WebSphere Application Server Feature Pack for XML
95
support). Apart from these enhancements, character maps, unicode normalization, and byte
order mark (BOM) support are further enhancements for serialization.
In this section, we demonstrate the capability of character maps. Character maps allow fine
grained control for outputting characters during serialization. This feature is useful when the
consuming application needs very specific serialization formats.
Download materials: This example requires the following sample files required:
򐂰 XSLT2OtherSerializationDemo.xml
򐂰 XSLT2OtherSerializationDemo.xsl
򐂰 XSLT2OtherSerializationDemo.java
A character map defines how particular characters are serialized as a particular string
through a character to string mapping. As an example, consider the snippet of input XML
shown in Example 4-11. During serialization, we want the characters &#062, which represent
a greater than sign (>) in the XML, to be output as an “>” character. We also want to substitute
the string “and” for the plus (“+”) sign.
Example 4-11 Input XML
<PROBLEM_CODE>CLOSED></PROBLEM_CODE>
<CAUSE_CODE>DATABASE+APPSERVER</CAUSE_CODE>
This transformation is done using the character map shown in Example 4-12.
Example 4-12 XSL character mapping for XSLT2OtherSerializationDemo.xsl
<xsl:character-map name="format">
<xsl:output-character character="+" string=" and " />
<xsl:output-character character=">" string=">" />
</xsl:character-map>
To apply this character mapping during serialization, the <xsl:output> tag uses an optional
attribute called use-character-maps, shown in Example 4-13.
Example 4-13 The use-character-maps attribute
<xsl:output method="xml" indent="yes" encoding="UTF-8" use-character-maps="format"
/>
An example of the output using this character map looks like Example 4-14.
Example 4-14 Output
<?xml version="1.0" encoding="UTF-8"?>
<tickets>
<ticket PROBLEM_ID="22504302"
PROBLEM_CODE="CLOSED>"
CLOSE_DATE="2009-10-21"
OPEN_DATE="2009-10-21"
SEVERITY="2"
CAUSE_CODE="DATABASE and APPSERVER"/>
</tickets>
96
Getting Started with the WebSphere Application Server Feature Pack for XML
4.2.7 Regular expression support
In XSLT2.0, the support of Regular Expressions is available through elements such as
xsl:analyze-string, xsl:matching-substring, xsl:non-matching-substring, and a function
called regex-group.
Download materials: This example requires the following sample files:
򐂰 XSLT2RegexDemo.java
򐂰 XSLT2RegexDemo.xml
򐂰 XSLT2RegexDemo.xsl
The input XML has a series of problem ticket information, The goal is to analyze the input
<CLOSE_DATE> element, for example:
<CLOSE_DATE>2009-10-21</CLOSE_DATE>
Using a regular expression, we want to extract the year (2009), month (10), and date (21) and
report these values as three different attributes:
<CLOSE_DATE
year="2009" month="10" date="21" />
Example 4-15 Style sheet code: XSLT2RegexDemo.xsl
<xsl:variable name="elValue" select="CLOSE_DATE"/>
<xsl:element name="CLOSE_DATE">
<xsl:analyze-string select="$elValue"
regex="(\d+)(\d+)(\d+)">
<xsl:matching-substring>
<xsl:attribute name="year">
<xsl:value-of select="regex-group(1)" />
</xsl:attribute>
<xsl:attribute name="month">
<xsl:value-of select="regex-group(2)" />
</xsl:attribute>
<xsl:attribute name="date">
<xsl:value-of select="regex-group(3)" />
</xsl:attribute>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:element>
4.2.8 Schema-aware XSLT
XSLT 2.0 allows programmers to design style sheets to be schema aware. It is an optional
feature of XSLT 2.0 processors and the Feature Pack for XML supports it. You can do input
tree validation as well as output tree validation.
Chapter 4. Using the XSLT features of the WebSphere Application Server Feature Pack for XML
97
Download materials: This example requires the following sample files:
򐂰 The XML schema: XSLT2SchemaAwareDemo.xsd
򐂰 The input XML which conforms to the schema: XSLT2SchemaAwareDemo.xml
򐂰 An input XML which does not conform to the schema:
XSLT2SchemaAwareDemoInputFailure.xml
򐂰 The style sheet that transforms element nodes of <ticket> to attributes:
XSLT2SchemaAwareDemo.xsl
򐂰 Java program that demonstrates the API: XSLT2SchemaAwareDemo.java
Looking at the Java program that uses the XSL, Example 4-16 shows the relevant lines of
code.
Example 4-16 XSLT2SchemaAwareDemo.java excerpt
String xsdFilePath = "XSLT2SchemaAwareDemo.xsd" ;
factory.registerSchema(new StreamSource(new File(xsdFilePath)));
factory.setValidating(XFactory.FULL_VALIDATION);
If an XML file is used as input to this program that does not conform to the schema, an error
will be generated.
To illustrate the error in this example, we use XSLT2SchemaAwareDemoInputFailure.xml as the
input XML. This input XML has a missing the required element named <PROBLEMCODE> for a
particular <ticket> element. If you run the program with this XML as input, the following
expected exception is issued during transformation.
ERROR: cvc-complex-type.2.4.a: Invalid content was found starting with element
'CLOSEDATE'. One of ' {PROBLEMCODE}' is expected.;
You can use additional mechanisms to validate output trees. For more information, see the
XSLT documentation at:
http://www.w3.org/TR/xslt20/
You can find information about the following XSL elements:
򐂰 <xsl:import-schema>
򐂰 xsl:validation="strict"
4.2.9 User-defined functions
An important aspect of XSLT 2.0 is the user-defined function feature. You can now define a
user-defined function in the style sheet using the <xsl:function> element. You can define
strongly typed input, process it, and return strongly typed output in the function.
For example, assume we have a transformation requirement where the SEVERITY field of the
XML that contains problem ticket information needs a change. You need to map the numeric
values such as 1, 2, 3, 4, and so forth to values such as MAJOR, MEDIUM, MINOR, and so
forth. We can write a separate function where these mapping rules reside, that takes the
severity value as input and returns the updated severity text.
98
Getting Started with the WebSphere Application Server Feature Pack for XML
Download materials: This example requires the following sample files:
򐂰 XSLT2UserDefinedFunctionDemo.xml
򐂰 XSLT2UserDefinedFunctionDemo.xsl
򐂰 XSLT2UserDefinedFunctionDemo.java
The key aspects of the style sheet are the function code and the function invocation.
Example 4-17 shows the function code format.
Example 4-17 XSL function code format
<xsl:function name="xmlfep:translateSeverity">
....
....
</xsl:function>
Example 4-18 shows the function code invocation.
Example 4-18 Function code invocation
<xsl:variable name="sevValue">
<xsl:value-of select="xmlfep:translateSeverity(SEVERITY/text())"/>
</xsl:variable>
4.2.10 XHTML output
XSLT 1.0 does not support the XHTML output type. However, XHTML gained significant
momentum across various user agents, as discussed in the following FAQ:
http://www.w3.org/MarkUp/2004/xhtml-faq
The XSLT 2.0 Feature Pack for XML provides support for XHTML as output type.
Download materials: This example requires the following sample files:
򐂰
򐂰
򐂰
򐂰
XSLT2XHTMLDemo.xml
XSLT2XHTMLDemo.xsl
XSLT2XHTMLDemo.java
XSLT2XHTMLDemo.xhtml
The key line in the style sheet program is:
<xsl:output method="xhtml" />
Chapter 4. Using the XSLT features of the WebSphere Application Server Feature Pack for XML
99
100
Getting Started with the WebSphere Application Server Feature Pack for XML
A
Appendix A.
Example code
In this appendix, we include select code and other artifacts that we use in the examples in this
paper. You can download and extract the Java code, XML data, XSL style sheets, and other
required artifacts for further examination. For more information about downloading the
examples, see Appendix B, “Additional material” on page 121.
© Copyright IBM Corp. 2010. All rights reserved.
101
XQuery examples
In Chapter 3, “Using the XQuery features of the WebSphere Application Server Feature Pack
for XML” on page 53, we use several examples to illustrate the concepts that we discuss in
that chapter. The code, XQuery files, and data files are all contained in the downloadable
material for this book (see Appendix B, “Additional material” on page 121). In addition, we list
several example files here for reference.
Java programs
This section contains the code for the application programs used in Chapter 3, “Using the
XQuery features of the WebSphere Application Server Feature Pack for XML” on page 53.
SimpleXQueryExecutor.java
Example A-1 SimpleXQueryExecutor.java
package xquerysamples;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import com.ibm.xml.xapi.XFactory;
import com.ibm.xml.xapi.XQueryExecutable;
public class SimpleXQueryExecutor {
public static void main(String[] args) {
System.out.println(execute(args));
}
public static String execute(String[] args) {
StringWriter writer = new StringWriter();
try {
String simpleXQuery = "simplejoin.xq";
if(args.length > 0)
simpleXQuery = args[0];
XFactory factory = XFactory.newInstance();
URL url =
SimpleXQueryExecutor.class.getResource("/xqueries/"+simpleXQuery);
StreamSource source = new StreamSource(url.toString());
XQueryExecutable xqe = factory.prepareXQuery(source);
xqe.execute(new StreamResult(writer));
} catch (Exception e) {
e.printStackTrace(new PrintWriter(writer));
}
return writer.toString();
102
Getting Started with the WebSphere Application Server Feature Pack for XML
}
}
XQueryNamespace
Example A-2 XQueryNamespace.java
package xquerysamples;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import messagehandler.SimpleXMessageHandler;
import resolvers.SimpleSchemaResolver;
import
import
import
import
com.ibm.xml.xapi.XDynamicContext;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XQueryExecutable;
com.ibm.xml.xapi.XSchemaResolver;
public class XQueryNamespace {
public static void main(String[] args) {
System.out.println(execute(args));
}
public static String execute(String[] args) {
StringWriter writer = new StringWriter();
try {
String defectSourceFile = "DefectsNS.xml";
if(args.length > 0) {
defectSourceFile = args[0];
}
XFactory factory = XFactory.newInstance();
factory.setValidating(XFactory.FULL_VALIDATION);
URL schemaURL =
XQueryNamespace.class.getResource("/schema/ExtendedDefect.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
XSchemaResolver resolver = new SimpleSchemaResolver(writer);
factory.setSchemaResolver(resolver);
factory.registerSchema(schemaSource);
URL url = XQueryNamespace.class.getResource("/xqueries/namespace.xq");
StreamSource xquerysource = new StreamSource(url.toString());
XQueryExecutable xqe = factory.prepareXQuery(xquerysource);
writer.write("XQUERY PREPARED, ABOUT TO EXECUTE\n");
Appendix A. Example code
103
StreamSource defectsource = new
StreamSource(XQueryNamespace.class.getResource("/xmldata/"+defectSourceFile).toStr
ing());
XDynamicContext dynamicContext = factory.newDynamicContext();
//dynamicContext.setMessageHandler(new SimpleXMessageHandler());
xqe.execute(defectsource, dynamicContext, new StreamResult(writer));
} catch (Exception e) {
e.printStackTrace(new PrintWriter(writer));
}
return writer.toString();
}
}
NavigatingXSequence
Example A-3 NavigatingXSequence.java
package xquerysamples;
import
import
import
import
import
java.io.PrintWriter;
java.io.StringWriter;
java.net.URL;
java.util.ArrayList;
java.util.List;
import javax.xml.transform.stream.StreamSource;
import
import
import
import
import
import
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XItemView;
com.ibm.xml.xapi.XNodeView;
com.ibm.xml.xapi.XQueryExecutable;
com.ibm.xml.xapi.XSequenceCursor;
com.ibm.xml.xapi.XTreeCursor;
public class NavigatingXSequence {
public static void main(String[] args) {
System.out.println(execute());
}
public static String execute() {
StringWriter writer = new StringWriter();
try {
XFactory factory = XFactory.newInstance();
URL url =
NavigatingXSequence.class.getResource("/xqueries/simplejoin.xq");
StreamSource source = new StreamSource(url.toString());
XQueryExecutable xqe = factory.prepareXQuery(source);
XSequenceCursor sc = xqe.execute();
writer.write(processSequenceWithCursors(sc).toString());
104
Getting Started with the WebSphere Application Server Feature Pack for XML
writer.write("\n");
while(sc.toPrevious()); // Rewind the cursor
writer.write(processSequenceWithCursorsAlt(sc).toString());
to rewind to re-use sc
writer.write("\n");
// No need
writer.write(processSequenceWithCursors(sc).toString());
writer.write("\n");
} catch (Exception e) {
e.printStackTrace(new PrintWriter(writer));
}
return writer.toString();
}
static List<ComponentHolder> processSequenceWithCursors(XSequenceCursor sc) {
List<ComponentHolder> components = new ArrayList<ComponentHolder>();
do {
if(!sc.isAtomic() && XNodeView.Kind.ELEMENT.equals(sc.getKind()) &&
"Component".equals(sc.getNodeQName().getLocalPart())) {
ComponentHolder component = new ComponentHolder();
components.add(component);
XTreeCursor treeCursor = sc.getTreeCursor();
// Process the attributes
boolean attributeExists = treeCursor.toFirstAttribute();
while(attributeExists) {
if("id".equals(treeCursor.getNodeQName().getLocalPart()))
component.id = treeCursor.getStringValue();
if("manager".equals(treeCursor.getNodeQName().getLocalPart()))
component.manager = treeCursor.getStringValue();
attributeExists = treeCursor.toNextAttribute();
}
treeCursor.toParent();
// Set the cursor back to the 'Component'
element
// Process children
boolean childToProcess = treeCursor.toFirstChild();
while(childToProcess) {
if(!treeCursor.isAtomic() &&
XNodeView.Kind.ELEMENT.equals(treeCursor.getKind()) &&
"DefectNumber".equals(treeCursor.getNodeQName().getLocalPart())) {
DefectHolder defect = new DefectHolder();
component.defects.add(defect);
// Process Defect attributes
boolean defectAttributeExists = treeCursor.toFirstAttribute();
while(defectAttributeExists) {
if("number".equals(treeCursor.getNodeQName().getLocalPart()))
defect.number = treeCursor.getStringValue();
Appendix A. Example code
105
defectAttributeExists = treeCursor.toNextAttribute();
}
treeCursor.toParent();
}
childToProcess = treeCursor.toNextSibling();
}
}
} while (sc.toNext());
return components;
}
static List<ComponentHolder> processSequenceWithCursorsAlt(XSequenceCursor sc)
{
List<ComponentHolder> components = new ArrayList<ComponentHolder>();
List<XItemView> xItemList = sc.exportAsList();
for(XItemView componentItemView : xItemList) {
if(!componentItemView.isAtomic() &&
XNodeView.Kind.ELEMENT.equals(componentItemView.getKind()) &&
"Component".equals(componentItemView.getNodeQName().getLocalPart())) {
ComponentHolder component = new ComponentHolder();
components.add(component);
XTreeCursor treeCursor = componentItemView.getTreeCursor();
// Process the attributes
boolean attributeExists = treeCursor.toFirstAttribute();
while(attributeExists) {
if("id".equals(treeCursor.getNodeQName().getLocalPart()))
component.id = treeCursor.getStringValue();
if("manager".equals(treeCursor.getNodeQName().getLocalPart()))
component.manager = treeCursor.getStringValue();
attributeExists = treeCursor.toNextAttribute();
}
treeCursor.toParent();
// Set the cursor back to the 'Component'
element
// Process children
boolean childToProcess = treeCursor.toFirstChild();
while(childToProcess) {
if(!treeCursor.isAtomic() &&
XNodeView.Kind.ELEMENT.equals(treeCursor.getKind()) &&
"DefectNumber".equals(treeCursor.getNodeQName().getLocalPart())) {
DefectHolder defect = new DefectHolder();
component.defects.add(defect);
// Process Defect attributes
boolean defectAttributeExists = treeCursor.toFirstAttribute();
while(defectAttributeExists) {
if("number".equals(treeCursor.getNodeQName().getLocalPart()))
defect.number = treeCursor.getStringValue();
defectAttributeExists = treeCursor.toNextAttribute();
}
treeCursor.toParent();
106
Getting Started with the WebSphere Application Server Feature Pack for XML
}
childToProcess = treeCursor.toNextSibling();
}
}
}
return components;
}
}
class DefectHolder {
String number;
public String toString() {
return "Defect number "+number;
}
}
class ComponentHolder {
String manager;
String id;
List<DefectHolder> defects = new ArrayList<DefectHolder>();
public String toString() {
return "Component manager "+manager+", id "+id+" has defects
"+defects.toString();
}
}
UsingDOMResult
Example A-4 UsingDOMResult.java
package xquerysamples;
import
import
import
import
import
java.io.PrintWriter;
java.io.StringWriter;
java.net.URL;
java.util.ArrayList;
java.util.List;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.ibm.xml.xapi.XFactory;
import com.ibm.xml.xapi.XQueryExecutable;
public class UsingDOMResult {
Appendix A. Example code
107
public static void main(String[] args) {
System.out.println(execute());
}
public static String execute() {
StringWriter writer = new StringWriter();
try {
XFactory factory = XFactory.newInstance();
URL url = UsingDOMResult.class.getResource("/xqueries/simplejoin.xq");
StreamSource source = new StreamSource(url.toString());
XQueryExecutable xqe = factory.prepareXQuery(source);
DOMResult domResult = new DOMResult();
xqe.execute(domResult);
writer.write(processResultsWithDOM(domResult).toString());
} catch (Exception e) {
e.printStackTrace(new PrintWriter(writer));
}
return writer.toString();
}
static List<ComponentHolder> processResultsWithDOM(DOMResult domResult) {
List<ComponentHolder> components = new ArrayList<ComponentHolder>();
Node docFragmentNode = domResult.getNode();
NodeList docFragmentChildren = docFragmentNode.getChildNodes();
for(int docFragmentChildIndex=0; docFragmentChildIndex <
docFragmentChildren.getLength(); docFragmentChildIndex++) {
Node docFragmentChild = docFragmentChildren.item(docFragmentChildIndex);
if("Component".equals(docFragmentChild.getLocalName())) {
ComponentHolder component = new ComponentHolder();
components.add(component);
// Process attributes
NamedNodeMap componentAttributes = docFragmentChild.getAttributes();
for(int i=0; i < componentAttributes.getLength(); i++) {
Node componentAttribute = componentAttributes.item(i);
if("id".equals(componentAttribute.getNodeName()))
component.id = componentAttribute.getNodeValue();
if("manager".equals(componentAttribute.getNodeName()))
component.manager = componentAttribute.getNodeValue();
}
// Process children
NodeList childNodes = docFragmentChild.getChildNodes();
for(int i=0; i < childNodes.getLength(); i++) {
Node childNode = childNodes.item(i);
if("DefectNumber".equals(childNode.getLocalName())) {
DefectHolder defect = new DefectHolder();
component.defects.add(defect);
// Process Defect attributes
108
Getting Started with the WebSphere Application Server Feature Pack for XML
NamedNodeMap defectAttributes = childNode.getAttributes();
for(int j=0; j < defectAttributes.getLength(); j++) {
Node defectAttribute = defectAttributes.item(j);
if("number".equals(defectAttribute.getNodeName()))
defect.number = defectAttribute.getNodeValue();
}
}
}
}
}
return(components);
}
}
CachingResults
Example A-5 CachingResults.java
package xquerysamples;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import resolvers.CachedCollectionResolver;
import
import
import
import
com.ibm.xml.xapi.XDynamicContext;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XQueryExecutable;
com.ibm.xml.xapi.XSequenceCursor;
public class CachingResults {
public static void main(String[] args) {
System.out.println(execute());
}
public static String execute() {
StringWriter writer = new StringWriter();
try {
XFactory factory = XFactory.newInstance();
URL url = CachingResults.class.getResource("/xqueries/simplejoin.xq");
StreamSource source = new StreamSource(url.toString());
XQueryExecutable xqe = factory.prepareXQuery(source);
XSequenceCursor sc = xqe.execute();
writer.write(NavigatingXSequence.processSequenceWithCursors(sc).toString());
while(sc.toPrevious()); // Rewind the cursor
Appendix A. Example code
109
writer.write("\n");
// Cache the results in a collection resolver
CachedCollectionResolver collectionResolver = new
CachedCollectionResolver();
collectionResolver.setCachedSequence("http://defectsByComponent", sc);
URL fdfmURL =
CachingResults.class.getResource("/xqueries/findDefectsForManager.xq");
StreamSource fdfmSource = new StreamSource(fdfmURL.toString());
XQueryExecutable fdfmExecutable = factory.prepareXQuery(fdfmSource);
XDynamicContext dynamicContext = factory.newDynamicContext();
dynamicContext.setCollectionResolver(collectionResolver);
dynamicContext.bind(new QName("manager_name"), "Dan's Manager");
StreamResult outputStream = new StreamResult(writer);
fdfmExecutable.execute(dynamicContext, outputStream);
writer.write("\n");
writer.write(NavigatingXSequence.processSequenceWithCursorsAlt(sc).toString());
writer.write("\n");
dynamicContext.bind(new QName("manager_name"), "Khurram's Manager");
fdfmExecutable.execute(dynamicContext, outputStream);
} catch (Exception e) {
e.printStackTrace(new PrintWriter(writer));
}
return writer.toString();
}
}
ExternalFunctionXQuery
Example A-6 ExternalFunctionXQuery
package xquerysamples;
import
import
import
import
java.io.PrintWriter;
java.io.StringWriter;
java.lang.reflect.Method;
java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import resolvers.SimpleSchemaResolver;
import com.ibm.xml.xapi.XDynamicContext;
110
Getting Started with the WebSphere Application Server Feature Pack for XML
import
import
import
import
import
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XQueryExecutable;
com.ibm.xml.xapi.XSchemaResolver;
com.ibm.xml.xapi.XStaticContext;
com.ibm.xml.xapi.XTypeConstants;
import externalfunction.ExternalDirectoryFunction;
public class ExternalFunctionXQuery {
public static void main(String[] args) {
System.out.println(execute());
}
public static String execute() {
StringWriter writer = new StringWriter();
try {
XFactory factory = XFactory.newInstance();
factory.setValidating(XFactory.FULL_VALIDATION);
URL schemaURL =
ExternalFunctionXQuery.class.getResource("/schema/ExtendedDefect.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
XSchemaResolver resolver = new SimpleSchemaResolver(writer);
factory.setSchemaResolver(resolver);
factory.registerSchema(schemaSource);
URL url =
ExternalFunctionXQuery.class.getResource("/xqueries/externalfunction.xq");
StreamSource source = new StreamSource(url.toString());
XStaticContext staticContext = factory.newStaticContext();
staticContext.declareNamespace("external",
"http://xmlfep.external.function");
QName getTelephoneNumberQName = new
QName("http://xmlfep.external.function", "getTelephoneNumberExt");
staticContext.declareFunction(getTelephoneNumberQName,
XTypeConstants.STRING_QNAME, new QName [] {XTypeConstants.STRING_QNAME});
XQueryExecutable xqe = factory.prepareXQuery(source, staticContext);
writer.write("XQUERY PREPARED, ABOUT TO EXECUTE\n");
XDynamicContext dynamicContext = factory.newDynamicContext();
Method getTelephoneNumberMethod =
ExternalDirectoryFunction.class.getMethod("getTelephoneNumber", String.class);
ExternalDirectoryFunction externalDirectoryInstance = new
ExternalDirectoryFunction();
dynamicContext.bindFunction(getTelephoneNumberQName,
getTelephoneNumberMethod, externalDirectoryInstance);
xqe.execute(dynamicContext, new StreamResult(writer));
} catch (Exception e) {
e.printStackTrace(new PrintWriter(writer));
Appendix A. Example code
111
}
return writer.toString();
}
}
DatabaseXQuery
Example A-7 DatabaseXQuery.java
package database;
import
import
import
import
java.io.PrintWriter;
java.io.StringWriter;
java.net.URL;
java.sql.Connection;
import
import
import
import
javax.sql.DataSource;
javax.xml.namespace.QName;
javax.xml.transform.stream.StreamResult;
javax.xml.transform.stream.StreamSource;
import
import
import
import
import
import
com.ibm.xml.xapi.XDynamicContext;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XQueryExecutable;
com.ibm.xml.xapi.XSequenceCursor;
com.ibm.xml.xapi.XStaticContext;
com.ibm.xml.xapi.XTypeConstants;
public class DatabaseXQuery {
public static void main(String[] args) {
String dataSourceClassName = "org.apache.derby.jdbc.ClientDataSource";
String database_url = "http://derbydefects";
if(args.length > 0)
database_url = args[0];
if("http://db2defectsXML".equals(database_url) ||
"http://db2XQuery:open".equals(database_url))
dataSourceClassName = "com.ibm.db2.jcc.DB2SimpleDataSource";
else if ("http://derbydefects".equals(database_url) ||
"http://derbydefectsXMLasCLOB".equals(database_url))
dataSourceClassName = "org.apache.derby.jdbc.ClientDataSource";
else {
System.out.println("Sorry, I didn't recognize the parameters specified");
return;
}
System.out.println(execute(database_url, dataSourceClassName, false));
}
public static String executeOnServer(String database_url) {
String dataSourceJNDIName = "XMLFEPDERBYDS";
112
Getting Started with the WebSphere Application Server Feature Pack for XML
if(database_url == null)
database_url = "http://derbydefects";
if("http://db2defectsXML".equals(database_url) ||
"http://db2XQuery:open".equals(database_url))
dataSourceJNDIName = "XMLFEPDB2DS";
else if ("http://derbydefects".equals(database_url) ||
"http://derbydefectsXMLasCLOB".equals(database_url))
dataSourceJNDIName = "XMLFEPDERBYDS";
else {
return("Sorry, I didn't recognize the parameters specified");
}
return execute(database_url, dataSourceJNDIName, true);
}
public static String execute(String database_url, String dataSourceID, boolean
useJNDI) {
StringWriter writer = new StringWriter();
try {
DataSource dataSource = null;
if(useJNDI)
dataSource = DataSourceHelper.getDataSourceFromJNDI(dataSourceID);
else
dataSource =
DataSourceHelper.getDataSourceFromClassName(dataSourceID);
Connection dbConnection = dataSource.getConnection();
try {
XFactory factory = XFactory.newInstance();
URL url = DatabaseXQuery.class.getResource("/xqueries/database.xq");
StreamSource source = new StreamSource(url.toString());
XStaticContext staticCtx = factory.newStaticContext();
staticCtx.declareVariable(new QName("database_url"),
XTypeConstants.STRING_QNAME);
XQueryExecutable xqe = factory.prepareXQuery(source, staticCtx);
XDynamicContext dynamicCtx = factory.newDynamicContext();
DatabaseCollectionResolver dbCollectionResolver = new
DatabaseCollectionResolver(writer);
dbCollectionResolver.setConnection(dbConnection);
dynamicCtx.setCollectionResolver(dbCollectionResolver);
dynamicCtx.bind(new QName("database_url"), database_url);
XSequenceCursor sc = xqe.execute(dynamicCtx);
sc.exportSequence(new StreamResult(writer));
} catch(Exception e) {
Appendix A. Example code
113
e.printStackTrace(new PrintWriter(writer));
}
dbConnection.close();
} catch (Exception e) {
e.printStackTrace(new PrintWriter(writer));
}
return writer.toString();
}
}
Resolvers
This section provides the code for the resolvers used in the examples.
CachedCollectionResolver
Example A-8 CachedCollectionResolver
package resolvers;
import java.util.concurrent.ConcurrentHashMap;
import com.ibm.xml.xapi.XCollectionResolver;
import com.ibm.xml.xapi.XSequenceCursor;
public class CachedCollectionResolver implements XCollectionResolver {
ConcurrentHashMap<String, XSequenceCursor> cachedSequences = new
ConcurrentHashMap<String, XSequenceCursor>();
@Override
public XSequenceCursor getCollection(String uri, String base) {
return cachedSequences.get(uri);
}
public void setCachedSequence(String uri, XSequenceCursor sc) {
cachedSequences.put(uri, sc);
}
}
SimpleSchemaResolver
Example A-9 SimpleSchemaResolver
package resolvers;
import java.io.IOException;
import java.io.Writer;
import java.net.URL;
114
Getting Started with the WebSphere Application Server Feature Pack for XML
import java.util.Arrays;
import java.util.List;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import com.ibm.xml.xapi.XSchemaResolver;
public class SimpleSchemaResolver implements XSchemaResolver {
private Writer _writer = null;
public SimpleSchemaResolver(Writer writer) {
_writer = writer;
}
@Override
public List<? extends Source> getSchema(String namespace, List<String>
locations,
String baseURI) {
if(namespace.equals("http://com.ibm.xml.samples.component")) {
try {
_writer.write("FOUND COMPONENT NAMESPACE\n");
} catch (IOException e) {
e.printStackTrace();
}
URL schemaURL =
SimpleSchemaResolver.class.getResource("/schema/Components.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
return Arrays.asList(schemaSource);
}
if(namespace.equals("http://com.ibm.xml.samples")) {
try {
_writer.write("FOUND DEFECT NAMESPACE\n");
} catch (IOException e) {
e.printStackTrace();
}
URL schemaURL =
SimpleSchemaResolver.class.getResource("/schema/Defects.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
return Arrays.asList(schemaSource);
}
if(namespace.equals("http://com.ibm.xml.samples.ext")) {
try {
_writer.write("FOUND EXTENDED DEFECT\n");
} catch (IOException e) {
e.printStackTrace();
}
URL schemaURL =
SimpleSchemaResolver.class.getResource("/schema/ExtendedDefect.xsd");
StreamSource schemaSource = new StreamSource(schemaURL.toString());
return Arrays.asList(schemaSource);
}
return null;
Appendix A. Example code
115
}
}
DatabaseCollectionResolver
Example A-10 DatabaseCollectionResolver.java
package database;
import
import
import
import
import
import
import
import
import
java.io.ByteArrayInputStream;
java.io.PrintWriter;
java.io.Writer;
java.sql.Clob;
java.sql.Connection;
java.sql.PreparedStatement;
java.sql.ResultSet;
java.sql.SQLXML;
java.util.ArrayList;
import javax.xml.transform.stream.StreamSource;
import
import
import
import
import
com.ibm.xml.xapi.XCollectionResolver;
com.ibm.xml.xapi.XFactory;
com.ibm.xml.xapi.XItemFactory;
com.ibm.xml.xapi.XItemView;
com.ibm.xml.xapi.XSequenceCursor;
public class DatabaseCollectionResolver implements XCollectionResolver {
private Connection dbConnection = null;
private Writer _writer = null;
public void setConnection(Connection connection) {
dbConnection = connection;
}
public DatabaseCollectionResolver(Writer writer) {
_writer = writer;
}
@Override
public XSequenceCursor getCollection(String uri, String base) {
if("http://derbydefects".equals(uri)) {
try {
_writer.write("found DEFECTS\n");
String sqlselect = "SELECT * FROM DEFECTS";
PreparedStatement pstmt = dbConnection.prepareStatement(sqlselect);
ResultSet resultSet = pstmt.executeQuery();
XFactory xFactory = XFactory.newInstance();
XItemFactory itemFactory = xFactory.getItemFactory();
ArrayList<XItemView> items = new ArrayList<XItemView>();
116
Getting Started with the WebSphere Application Server Feature Pack for XML
while (resultSet.next()) {
int number = resultSet.getInt("NUMBER");
String component = resultSet.getString("COMPONENT");
String abstractStr = resultSet.getString("ABSTRACT");
String state = resultSet.getString("STATE");
String developer = resultSet.getString("DEVELOPER");
String tester = resultSet.getString("TESTER");
String fragmentStr =
"<Defect " +
"number=\"" +number+ "\" " +
"component=\"" +component+ "\" " +
">" +
"<abstract>"+abstractStr+"</abstract>" +
"<state>"+state+"</state>" +
"<developer>"+developer+"</developer>" +
"<tester>"+tester+"</tester>" +
"</Defect>";
fragmentStr.getBytes();
XItemView item = itemFactory.item(new StreamSource(new
ByteArrayInputStream(fragmentStr.getBytes())));
items.add(item);
}
XSequenceCursor sequence = itemFactory.sequence(items.toArray(new
XItemView[0]));
pstmt.close();
return sequence;
} catch(Exception e) {
e.printStackTrace(new PrintWriter(_writer));
}
}
if("http://derbydefectsXMLasCLOB".equals(uri)) {
try {
_writer.write("found DEFECTSXMLASCLOB\n");
String sqlselect = "SELECT XMLSERIALIZE(DEFECT AS CLOB) FROM
DEFECTXML";
PreparedStatement pstmt = dbConnection.prepareStatement(sqlselect);
ResultSet resultSet = pstmt.executeQuery();
XFactory xFactory = XFactory.newInstance();
XItemFactory itemFactory = xFactory.getItemFactory();
ArrayList<XItemView> items = new ArrayList<XItemView>();
while (resultSet.next()) {
Clob clob = resultSet.getClob(1);
StreamSource ss = new StreamSource(clob.getAsciiStream());
XItemView item = itemFactory.item(ss);
clob.free();
items.add(item);
}
Appendix A. Example code
117
XSequenceCursor sequence = itemFactory.sequence(items.toArray(new
XItemView[0]));
pstmt.close();
return sequence;
} catch(Exception e) {
e.printStackTrace(new PrintWriter(_writer));
}
}
if("http://db2defectsXML".equals(uri)) {
try {
_writer.write("found DB2DEFECTS\n");
String sqlselect = "SELECT DEFECT FROM DEFECTSDB2";
PreparedStatement pstmt = dbConnection.prepareStatement(sqlselect);
ResultSet resultSet = pstmt.executeQuery();
XFactory xFactory = XFactory.newInstance();
XItemFactory itemFactory = xFactory.getItemFactory();
ArrayList<XItemView> items = new ArrayList<XItemView>();
while (resultSet.next()) {
SQLXML sqlx = resultSet.getSQLXML("DEFECT");
StreamSource ss = sqlx.getSource(StreamSource.class);
XItemView item = itemFactory.item(ss);
sqlx.free();
items.add(item);
}
XSequenceCursor sequence = itemFactory.sequence(items.toArray(new
XItemView[0]));
pstmt.close();
return sequence;
} catch(Exception e) {
e.printStackTrace(new PrintWriter(_writer));
}
}
if("http://db2XQuery:open".equals(uri)) {
try {
_writer.write("found DB2 Native XQuery\n");
String pureXQueryStr = "xquery for $y in db2-fn:xmlcolumn" +
"('DEFECTSDB2.DEFECT') " +
"where $y/Defect/state=\"open\" " +
"return $y";
PreparedStatement pstmt =
dbConnection.prepareStatement(pureXQueryStr);
ResultSet resultSet = pstmt.executeQuery();
XFactory xFactory = XFactory.newInstance();
XItemFactory itemFactory = xFactory.getItemFactory();
118
Getting Started with the WebSphere Application Server Feature Pack for XML
ArrayList<XItemView> items = new ArrayList<XItemView>();
while (resultSet.next()) {
SQLXML sqlx = resultSet.getSQLXML(1);
StreamSource ss = sqlx.getSource(StreamSource.class);
XItemView item = itemFactory.item(ss);
sqlx.free();
items.add(item);
}
XSequenceCursor sequence = itemFactory.sequence(items.toArray(new
XItemView[0]));
pstmt.close();
return sequence;
} catch(Exception e) {
e.printStackTrace(new PrintWriter(_writer));
}
}
return null;
}
}
Appendix A. Example code
119
120
Getting Started with the WebSphere Application Server Feature Pack for XML
B
Appendix B.
Additional material
This paper refers to additional material that you can download from the Internet as described
in this appendix.
Locating the web material
The web material that is associated with this paper is available in softcopy on the Internet
from the IBM Redbooks web server. Point your web browser at:
ftp://www.redbooks.ibm.com/redbooks/REDP4654
Alternatively, you can go to the IBM Redbooks website at:
ibm.com/redbooks
Select the Additional materials and open the directory that corresponds with the IBM
Redpaper form number, REDP4654.
Using the web material
The additional web material that accompanies this paper includes the following files:
File name
XQuery\examplesrc.zip
XPath\XPathSamples.zip
XSLT\XMLFPSamplePrograms.zip
Description
Basic and XQuery code samples
XPath samples
XLST samples
How to use the web material
Create a subdirectory (folder) on your workstation, and extract the contents of the web
material compressed file into this folder.
© Copyright IBM Corp. 2010. All rights reserved.
121
122
Getting Started with the WebSphere Application Server Feature Pack for XML
Related publications
We consider the publications that we list in this section particularly suitable for a more
detailed discussion of the topics that we cover in this paper.
IBM Redbooks publications
For information about ordering these publications, see “How to get Redbooks” on page 125.
Note that some of the documents referenced here might be available in softcopy only.
򐂰 Experience JEE! Using Rational Application Developer V7.5, SG24-7827
򐂰 Getting Started with the WebSphere Application Server Feature Pack for Communications
Enabled Applications V1.0, REDP-4613
򐂰 Getting Started with WebSphere Application Server Feature Pack for Service Component
Architecture, REDP-4633
Online resources
The following website is also relevant as a further information source:
򐂰 Feature Pack for XML, Version 1.0 Information Center
http://publib.boulder.ibm.com/infocenter/wasinfo/v7r0/topic/com.ibm.websphere.x
mlfep.multiplatform.doc/info/ae/ae/welcome_fepxml.html
XPath 2.0 resources
Consult the following XPath 2.0 resources:
򐂰 XML Path Language (XPath) 2.0
http://www.w3.org/TR/xpath20/
򐂰 XPath 2.0 Error Conditions
http://www.w3.org/TR/xpath20/#id-errors
򐂰 What's New in XPath 2.0
http://www.xml.com/pub/a/2002/03/20/xpath2.html
򐂰 Getting Started with XPath
http://www.ibm.com/developerworks/edu/x-dw-xxpath-i.html
򐂰 Working XML: Get started with XPath 2.0
http://www.ibm.com/developerworks/xml/library/x-wxxm35.html
򐂰 Chapter 9, “XPath” of XML in a Nutshell
http://oreilly.com/catalog/xmlnut/chapter/ch09.html
򐂰 WebSphere Application Server Feature Pack for XML Demo 2 - End to End XPath 2.0 - 1/2
http://www.youtube.com/watch?v=y7Q3sBGuMSE
© Copyright IBM Corp. 2010. All rights reserved.
123
򐂰 WebSphere Application Server Feature Pack for XML Demo 2 - End to End XPath 2.0 - 2/2
http://www.youtube.com/watch?v=PdQ9kusb460
򐂰 XQuery 1.0 and XPath 2.0 Functions and Operators
http://www.w3.org/TR/xpath-functions/
򐂰 Update XML in DB2 9.5
http://www.ibm.com/developerworks/data/library/techarticle/dm-0710nicola/
򐂰 Work with GPX XML in DB2 9.5 using JDBC
http://www.ibm.com/developerworks/data/library/techarticle/dm-0901faraaz/
򐂰 XQuery 1.0 and XPath 2.0 Data Model (XDM)
http://www.w3.org/TR/xpath-datamodel/
XSLT 2.0 resources
Consult the following XSLT 2.0 resources:
򐂰 XSLT 1.0
http://www.w3.org/TR/xslt
򐂰 XSLT Requirements
http://www.w3.org/TR/xslt20req
򐂰 XSLT 2.0
http://www.w3.org/TR/xslt20/
򐂰 Extensible Stylesheet Language Transformations (XSLT) 2.0
http://www.w3.org/TR/2007/REC-xslt20-20070123/
򐂰 WebSphere Application Server Feature Pack for XML Demo End to End XSLT 2.0 - Part I
http://www.youtube.com/watch?v=3Hhx2-KuNzg&feature=related
򐂰 WebSphere Application Server Feature Pack for XML Demo End to End XSLT 2.0 - Part II
http://www.youtube.com/watch?v=DSQTZQt6Xpo&feature=related
򐂰 WebSphere Application Server Feature Pack for XML Demo 4 - XSLT 2.0 Features - Part I
http://www.youtube.com/watch?v=LQBQAP8vbNA&feature=related
򐂰 WebSphere Application Server Feature Pack for XML Demo 4 - XSLT 2.0 Features - Part II
http://www.youtube.com/watch?v=7kJ6L2-cLi0&feature=related
򐂰 XML for Data: XSLT 2.0: An early look
http://www.ibm.com/developerworks/xml/library/x-xdxslt20.html
򐂰 Save time and code with XPath 2.0 and XSLT 2.0
http://www.ibm.com/developerworks/library/x-xslt20xpath20/
򐂰 Planning to upgrade XSLT 1.0 to 2.0 Series
– Part 1: Improvements in XSLT
http://www.ibm.com/developerworks/library/x-xslt20pt1.html
– Part 2: Five strategies for changing from XSLT 1.0 to 2.0
http://www.ibm.com/developerworks/library/x-xslt20pt2.html
124
Getting Started with the WebSphere Application Server Feature Pack for XML
– Part 3: Why the transition requires planning
http://www.ibm.com/developerworks/library/x-xslt20pt3.html
– Part 4: The toolkit for XSLT portability
http://www.ibm.com/developerworks/library/x-xslt20pt4.html
– Part 5: Make your stylesheets work with any processor version
http://www.ibm.com/developerworks/library/x-xslt20pt5.html
򐂰 Schema-aware processing with XSLT 2.0
http://www.ibm.com/developerworks/xml/library/x-schemaxslt.html
򐂰 Create multiple files in XSLT 2.0
http://www.ibm.com/developerworks/xml/library/x-tipmultxsl.html
XQuery resources
Consult the following XQuery resources:
򐂰 XML Query Language (XQuery) 1.0
http://www.w3.org/TR/2007/REC-xquery-20070123/
򐂰 XQuery 1.0 and XPath 2.0 Data Model (XDM)
http://www.w3.org/TR/xpath-datamodel/
򐂰 XML Query (XQuery) Requirements
http://www.w3.org/TR/xquery-requirements/
򐂰 Programming XML across the multiple tiers: Use XML in the middle tier for performance,
fidelity, and development ease
http://www.ibm.com/developerworks/xml/library/x-xmlfeat1/index.html
򐂰 XML Schema Part 1: Structures Second Edition Specification
http://www.w3.org/TR/xmlschema-1/
򐂰 XML Schema Part 2: Datatypes Second Edition specification
http://www.w3.org/TR/xmlschema-2/
How to get Redbooks
You can search for, view, or download Redbooks, Redpapers, Technotes, draft publications
and Additional materials, as well as order hardcopy Redbooks publications, at this website:
ibm.com/redbooks
Help from IBM
IBM Support and downloads
ibm.com/support
IBM Global Services
ibm.com/services
Related publications
125
126
Getting Started with the WebSphere Application Server Feature Pack for XML
Back cover
Getting Started with the
WebSphere Application
Server Feature Pack for XML
Use XPath 2.0, XSLT
2.0, and XQuery 1.0 in
WebSphere
applications
Help improve
application
performance and
reliability
Help improve
developer
productivity
The WebSphere Application Server V7 Feature Pack for XML delivers
support for the Worldwide Web Consortium (W3C) XML standards XSLT
2.0, XPath 2.0, and XQuery 1.0. The implementation of these standards
in the Feature Pack for XML provide developers with advanced
capabilities for building XML applications. These capabilities simplify
development and can help you enhance your use of XML data in
applications. The Feature Pack for XML supports Java applications that
connect to WebSphere Application Server through an XML thin client.
This IBM Redpaper publication provides an introduction to the
technology implemented with the Feature Pack for XML and provides
an extensive list of websites and documentation that can be used to
increase your knowledge of the subject.
®
Redpaper
™
INTERNATIONAL
TECHNICAL
SUPPORT
ORGANIZATION
BUILDING TECHNICAL
INFORMATION BASED ON
PRACTICAL EXPERIENCE
IBM Redbooks are developed
by the IBM International
Technical Support
Organization. Experts from
IBM, Customers and Partners
from around the world create
timely technical information
based on realistic scenarios.
Specific recommendations
are provided to help you
implement IT solutions more
effectively in your
environment.
For more information:
ibm.com/redbooks
REDP-4654-00
Download