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&#062;</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