1 /* Copyright 2004 The Apache Software Foundation 2 * 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 package org.apache.xmlbeans.samples.xquery; 17 18 import org.apache.xmlbeans.XmlCursor; 19 import org.apache.xmlbeans.XmlObject; 20 import org.apache.xmlbeans.XmlException; 21 import org.apache.xmlbeans.samples.xquery.employees.PhoneType; 22 23 /** 24 * This class demonstrates how to use the selectPath method to execute XPath 25 * expressions. Compare the code here with the code in the ExecQuery class. 26 * That class uses the execQuery method to execute XQuery expressions. 27 * <p/> 28 * You can call the selectPath method from either an XmlObject or XmlCursor 29 * instance. Calling from XmlObject returns an XmlObject array. Calling 30 * from XmlCursor returns void, and you use methods of the cursor to 31 * navigate among returned "selections". 32 */ 33 public class SelectPath 34 { 35 // Declare a namespace corresponding to the namespace declared in the XML 36 // instance. The string here will be used as part of the XPath expression to 37 // ensure that the query finds namespace-qualified elements in the XML. 38 final static String m_namespaceDeclaration = 39 "declare namespace xq='http://xmlbeans.apache.org/samples/xquery/employees';"; 40 41 /** 42 * Prints the XML bound to <em>empDoc</em>, uses XPath to 43 * retrieve elements containing work phone numbers, changes the numbers 44 * to another number, then prints the XML again to display the changes. 45 * 46 * This method demonstrates the following characteristics of the selectPath method: 47 * 48 * - it supports expressions that include predicates 49 * - the XML it returns is the XML queried against -- not a copy, as with results 50 * returned via execQuery methods and XQuery. Changes to this XML update 51 * the XML queried against. 52 * - selectPath called from an XMLBean type (instead of a cursor) returns an 53 * array of results (if any). These results can be cast to a matching type 54 * generated from schema. 55 * 56 * @param empDoc The incoming XML. 57 * @return <code>true</code> if the XPath expression returned results; 58 * otherwise, <code>false</code>. 59 */ 60 public boolean updateWorkPhone(XmlObject empDoc) 61 { 62 boolean hasResults = false; 63 64 // Print the XML received. 65 System.out.println("XML as received by updateWorkPhone method: \n\n" 66 + empDoc.toString()); 67 68 // Create a variable with the query expression. 69 String pathExpression = 70 "$this/xq:employees/xq:employee/xq:phone[@location='work']"; 71 72 // Execute the query. 73 XmlObject[] results = empDoc.selectPath(m_namespaceDeclaration 74 + pathExpression); 75 if (results.length > 0) 76 { 77 hasResults = true; 78 79 // <phone> elements returned from the expression will conform to the 80 // schema, so bind them to the appropriate XMLBeans type generated 81 // from the schema. 82 PhoneType[] phones = (PhoneType[]) results; 83 84 // Change all the work phone numbers to the same number. 85 for (int i = 0; i < phones.length; i++) 86 { 87 phones[i].setStringValue("(206)555-1234"); 88 } 89 // Print the XML with updates. 90 System.out.println("\nXML as updated by updateWorkPhone method (each work \n" + 91 "phone number has been changed to the same number): \n\n" 92 + empDoc.toString() + "\n"); 93 } 94 return hasResults; 95 } 96 97 /** 98 * Uses the XPath text() function to get values from <name> 99 * elements in received XML, then collects those values as the value of a 100 * <names> element created here. 101 * <p/> 102 * Demonstrates the following characteristics of the selectPath method: 103 * <p/> 104 * - It supports expressions that include XPath function calls. 105 * - selectPath called from an XmlCursor instance (instead of an XMLBeans 106 * type) places results (if any) into the cursor's selection set. 107 * 108 * @param empDoc The incoming XML. 109 * @return <code>true</code> if the XPath expression returned results; 110 * otherwise, <code>false</code>. 111 */ 112 public boolean collectNames(XmlObject empDoc) 113 { 114 boolean hasResults = false; 115 116 // Create a cursor with which to execute query expressions. The cursor 117 // is inserted at the very beginning of the incoming XML, then moved to 118 // the first element's START token. 119 XmlCursor pathCursor = empDoc.newCursor(); 120 pathCursor.toFirstChild(); 121 122 // Execute the path expression, qualifying it with the namespace 123 // declaration. 124 pathCursor.selectPath(m_namespaceDeclaration 125 + "$this//xq:employee/xq:name/text()"); 126 127 // If there are results, then go ahead and do stuff. 128 if (pathCursor.getSelectionCount() > 0) 129 { 130 hasResults = true; 131 132 // Create a new <names> element into which names from the XML 133 // will be copied. Note that this element is in the default 134 // namespace; it's not part of the schema. 135 XmlObject namesElement = null; 136 try 137 { 138 namesElement = XmlObject.Factory.parse("<names/>"); 139 } catch (XmlException e) 140 { 141 e.printStackTrace(); 142 } 143 144 // Add a cursor the new element and put it between its START and END 145 // tokens, where new values can be inserted. 146 XmlCursor namesCursor = namesElement.newCursor(); 147 namesCursor.toFirstContentToken(); 148 namesCursor.toEndToken(); 149 150 // Loop through the selections, appending the incoming <name> element's 151 // value to the new <name> element's value. (Of course, this could have 152 // been done with a StringBuffer, but that wouldn't show the cursor in 153 // use.) 154 while (pathCursor.toNextSelection()) 155 { 156 namesCursor.insertChars(pathCursor.getTextValue()); 157 if (pathCursor.hasNextSelection()) 158 { 159 namesCursor.insertChars(", "); 160 } 161 } 162 // Dispose of the cursors now that they're not needed. 163 pathCursor.dispose(); 164 namesCursor.dispose(); 165 166 // Print the new element. 167 System.out.println("\nNames collected by collectNames method: \n\n" 168 + namesElement + "\n"); 169 } 170 return hasResults; 171 } 172 }