< Day Day Up > |
Processing an XML document by iterating over every element works in some cases. In large XML documents, when you're interested in only specific records, not the whole set, this parsing is unwieldy. To narrow the focus and extract only the records you need, the XML Beans API allows using XPath and XQuery expressions. Overview of XPathXPath uses expressions with a syntax that's similar to file system navigation to identify content in an XML document. For example, when working with the sample Casino document (refer to Listing 10.4), the following line would select all the games at all the tables in the casino: /casino/table/game Locating Elements in a DocumentThe leading slash in the preceding expression means that you're defining the absolute path to the elements of interest. In this case, the statement returns only the instances of game that are subelements of table . If the path expression starts with a double slash ( // ), all elements that meet the search criteria are returned, regardless of their location in the XML document hierarchy. For example, the following line also returns all instances of game in the casino: //game The path expressions can also replace specific "directories" in the path expression with wildcards ( * ). For example, the following line also returns all instances of game in the casino ”you can think of it as returning all instance of game that are grandchildren of the casino element: //casino/*/game Filtering on the ElementsTo help filter the data, XPath provides a library of standard operators to work on the contents of elements to which path expressions are pointing. Expressions using these operators are specified by including them in square brackets ( [] ) at the end of an XPath expression. The typical equality ( = , != ), relational ( < , <= , > , >= ), and Boolean ( or , and ) operators are available and can be used to check against element and attribute values. Attributes are specified by the @ prefix. For example, the following line returns all tables where Blackjack is being played : /casino/table[game="blackjack"] This second example returns the data for tables 1 through 5 in the casino: /casino/table[@number<=5] Processing the Element DataXPath also supplies a large library of standard functions to process the data after it's retrieved from path and relational expressions. Discussion on the complete set of these functions is beyond the scope of this book, but a couple of brief examples follow. This first example provides a count of all slot machines: count(/casino/table/[game="slots"]) This second example returns the record for the first slot machine in the casino: /casino/table/[game="slots"][position()=1] Where to Get More DataTo learn more about XPath and its features, visit the XPath page on the World Wide Web Consortium (W3C) Web site at http://www.w3.org/TR/xpath. Using XPath Expressions with XML BeansTo use XPath expressions, the XML Beans API provides the selectPath method, which returns results related to the current XML document. There are two different ways to call this method: through an XmlObject (or any subclass) or through an XmlCursor . In both cases, the method expects a single string argument containing the following:
There is an XmlObject for every element of an XML Beans representation of a document, so the selectPath method can be called from the root element or any of its descendants. When called on an instance of XmlObject , the method returns an array of objects that match the criteria. Listing 10.7 shows the code necessary to call one of the previous examples ”returning all tables where Blackjack is being played.
Listing 10.7. Calling an XPath Expression with the XML Beans APIpublic XmlObject[] getBlackjackTables(String casinoString) { try { CasinoDocument casinoDoc = CasinoDocument.Factory. parse(casinoString); String xPathString = "$this/casino/table[game="blackjack"]"; XmlObject[] resultArray = casinoDoc.selectPath(xPathString); return resultArray; } catch (com.bea.xml.XmlException xmle) { return null; } } When called on an instance of XmlCursor , the selectPath method stores in the XmlCursor object a list of locations, or selections, in the XML document that match the criteria. Navigation through the selections is accomplished by calling the iterator-type methods summarized in Table 10.3. Table 10.3. Iterator-Type Methods of the XmlCursor Class
Overview of XQueryAlthough XPath is a powerful data navigation language, it lacks the capability to represent complex loop operations and user -defined functions. XQuery builds on XPath and adds these missing features. This section is short because, except for the most obscure forms of XPath statements, XQuery is a superset of XPath. Iterating over DataXQuery provides a means for creating FLWR ( for , let , where , and result ) constructs that provide query language features similar to SQL for relational databases:
The following code, although not overly exciting, shows the FLWR representation of the code needed to return all tables where Blackjack is being played: for $tb in $this/casino/table where $tb.game="blackjack" return $tb The power of the FLWR format is illustrated by two important features. First, XQuery permits for loops to be nested, providing the XML equivalent of joining data from two tables. Second, the return clause can include embedded FLWR constructs, allowing result data to be wrapped by formatting text. This latter feature is often used to produce HTML documents from XQuery expressions. To demonstrate these two features, service data ”the table ID and corresponding status ( ok , out of money ) ”is added as a separate element tree within the Casino document, as shown in Listing 10.8. Listing 10.8. Representing Service Data in the Casino XML Document<casino xmlns="http://openuri.org/bea/samples/workshop/chap10/casinoLayout"> <table number="1"> ... </table> <serviceRequest id="1"> <tableNum>4,</tableNum> <status>out of money</status> </serviceRequest> <serviceRequest id="2"> <tableNum>5,</tableNum> <status>out of money</status> </serviceRequest> </casino> The code in Listing 10.9 can then be used to create a work order for the coin-filling attendant. This work order lists the slot machines that need to be filled and the affiliated coin denomination. Listing 10.9. Nested Loops and Embedded FLWR Constructs in XQuery<html> <h1>Work Order</h1> { for $tb in $this/casino/table for $sr in $this/casino/serviceRequest where $tb@number=$sr.tableNum and $tb.game="slots" and $sr.status="out of money" return <h2>Table{$sr.tableNum} needs ${$tb.minimumBet} coins</h2> } </html> Defining FunctionsXQuery, as a full-featured programming language, also enables you to create user-defined functions. These functions have varied uses, but two possible applications are
The code in Listing 10.10 shows how to streamline XQuery code listings by encapsulating the code to print the number of tables where each game is being played in a function. Listing 10.10. User-Defined Functions in XQuerydefine function formatTotalLine($game) { let $countGame=count($this/cl:table[game=$game]) return $game + " is being played at " + $countGame + " tables." } for $game in ("slots","blackjack","poker","roulette") return formatTotalLine($game) Where to Get More DataTo learn more about XQuery and its features, visit the XQuery page on the W3C Web site at http://www.w3.org/TR/xquery. Using XQuery Expressions with XML BeansTo use XQuery expressions, the XML Beans API provides the executeQuery method. As with the selectPath method, there are two different ways to call this method: through an XmlObject (or any subclass) or through an XmlCursor . In both cases, the method expects a single string argument containing
Note that unlike the selectPath method, the executeQuery method returns results as a new XML document. Calling the method on an XmlObject returns the new document as an array of the type XmlObject ; calling the method on an XmlCursor returns a new instance of XmlCursor . Listing 10.11 shows the code for calling one of the previous examples ”returning the work order for the coin-filling attendant as an HTML document. Listing 10.11. Invoking an XQuery Expression with the XML Beans APIpublic XmlObject generateWorkOrder(XmlObject casinoDoc) { XmlCursor cursor = casinoDoc.newCursor(); cursor.toNextSibling(); XmlObject resultXML = null; String xQueryString = "<html><h1>Work Order</h1>" + "{ " + "for $tb in $this/casino/table " + "for $sr in $this/casino/serviceRequest " + "where $tb@number=$sr.tableNum and $tb.game=\"slots\" " + "and $sr.status=\"out of money\" " + "return <h2>Table{$sr.tableNum} needs ${$tb.minimumBet}" " coins</h2>" + "} " + "</html>"; try { XmlCursor resultCursor = cursor.execQuery(xQueryString); resultXML = resultCursor.getObject(); return resultXML; } catch(Exception e) { return null; } } |
< Day Day Up > |