001 package xmlBeans.xquery;
002
003 import com.bea.xml.XmlCursor;
004 import com.bea.xml.XmlObject;
005
006 /**
007 * A web service demonstrating how to use the selectPath
008 * method to execute an XQuery expressions. Compare the code in this
009 * web service with the code in the SimpleExpressions service. That
010 * service uses the XmlCursor.execQuery method to execute expressions.
011 * <br/><br/>
012 *
013 * You can call the selectPath method from either an XmlObject or XmlCursor
014 * instance. Calling from XmlObject returns an XmlObject array. Calling
015 * from XmlCursor returns void, and you use methods of the cursor to navigate
016 * among returned "selections".
017 *
018 * @common:target-namespace namespace="http://workshop.bea.com/SelectPath"
019 */
020 public class SelectPath implements com.bea.jws.WebService
021 {
022 /**
023 * Declare a namespace corresponding to the namespace declared
024 * in the XML instance. The string here will be used as part of the
025 * XPath expression to ensure that the query finds namespace-qualified
026 * elements in the XML.
027 */
028 final static String m_namespaceDeclaration =
029 "declare namespace xq='http://openuri.org/bea/samples/workshop/xmlBeans/xquery'";
030
031 /**
032 * Test this method by copying the entire contents of the Employees.xml file and
033 * pasting them in place of the <AnyElement/> element. Click the
034 * selectByState button to execute the following expression, which selects
035 * any employee elements whose state child element has a value of "WA":
036 * <br/><br/>
037 *
038 * $this/xq:employees/employee[address/state='WA']
039 *
040 * <br/><br/>
041 *
042 * The portion of this expression in square brackets -- [address/state='WA'] --
043 * is known as a "predicate." The predicate filters items returned by the
044 * expression to its immediate left. In other words, the first part of this
045 * expression returns all of the employee elements, then the predicate
046 * further filters those values to include only those whose address child element
047 * has a state child element with a value of "WA".
048 *
049 * This method illustrates how you can query from an XmlObject instance
050 * with the selectPath method. Results of the query (if any) are
051 * returned in an XmlObject array.
052 *
053 * @common:operation
054 */
055 public XmlObject[] selectByState(XmlObject empDoc)
056 {
057 /*
058 * Create an XmlObject array to contain the results of the query.
059 */
060 XmlObject[] resultArray = null;
061
062 /* A variable for the XQuery path expression. */
063 String queryExpression = "$this/xq:employees/xq:employee[xq:address/xq:state='WA']";
064
065 try
066 {
067 /*
068 * Perform the query, combining the namespace declaration and the rest of query
069 * expression.
070 */
071 resultArray = empDoc.selectPath(m_namespaceDeclaration + queryExpression);
072 }catch(Exception e)
073 {
074 System.out.println(e.getLocalizedMessage());
075 }
076 /*
077 * Return the array of results. Note that the returned results are contained
078 * in an XmlObject element -- not an employee element.
079 */
080 return resultArray;
081 }
082
083 /**
084 * Test this method by copying the entire contents of the Employees.xml file and
085 * pasting them in place of the <AnyElement/> element. Click the
086 * selectWorkPhonesAttr button to execute the following expression, which selects any
087 * phone elements whose location attribute value is "work":
088 * <br/><br/>
089 *
090 * $this/xq:employees/employee/phone[@location='work']
091 *
092 * <br/><br/>
093 *
094 * As with the selectByState method, this method
095 * uses a path expression and predicate to specify the requested XML.
096 *
097 * This method illustrates how you can query from an XmlCursor instance
098 * with the selectPath method. Unlike the selectByState example, the results of
099 * this query (if any) are managed by the cursor from which selectPath
100 * is called. Query results are available as "selections" in the cursor.
101 * You navigate among them with methods such as XmlCursor.toNextSelection.
102 *
103 * @common:operation
104 */
105 public XmlObject selectWorkPhonesAttr(XmlObject empDoc)
106 {
107 // Add a cursor to the incoming XML.
108 XmlCursor empCursor = empDoc.newCursor();
109
110 // Create a new XmlObject instance in which to return the results of the query.
111 XmlObject resultXml = XmlObject.Factory.newInstance();
112
113 /*
114 * Add a cursor to the new object; each of the returned results will be
115 * copied to the location of this cursor. In other words, the XML
116 * will be copied from cursor located in one XmlObject to a cursor located
117 * in another.
118 */
119 XmlCursor resultCursor = resultXml.newCursor();
120
121 /*
122 * Move the result cursor to a location that's valid for receiving XML
123 * copied from the set of results. When first inserted, the cursor is just
124 * outside (or "left of") the STARTDOC token -- or outside the XML. This
125 * call to toFirstToken moves it to a location between the STARTDOC and
126 * ENDDOC, where XML can be inserted.
127 */
128 resultCursor.toFirstContentToken();
129
130 // Create a variable with the query expression.
131 String queryExpression = "$this/xq:employees/xq:employee/xq:phone[@location='work']";
132
133 try
134 {
135 // Execute the query.
136 empCursor.selectPath(m_namespaceDeclaration + queryExpression);
137 /*
138 * Loop through the list of selections. For each selection,
139 * copy its value to the location of a cursor in another
140 * XmlObject.
141 */
142 while (empCursor.toNextSelection())
143 {
144 empCursor.copyXml(resultCursor);
145 }
146 }catch(Exception e)
147 {
148 System.out.println(e.getLocalizedMessage());
149 }
150 // Dispose of the query cursor.
151 empCursor.dispose();
152 // Return the XmlObject instance that now contains the results of the query.
153 return resultXml;
154 }
155
156 /**
157 * Test this method by copying the entire contents of the Employees.xml file and
158 * pasting them in place of the <AnyElement/> element. Click the
159 * selectEmpsByStateFLWR button to execute the following expression, which selects any
160 * employee elements whose location state element value is "WA":
161 * <br/><br/>
162 *
163 * for $e in $this/xq:employees/employee<br/>
164 * let $s := $e/address/state<br/>
165 * where $s = 'WA'<br/>
166 * return $e<br/>
167 * <br/><br/>
168 *
169 * This method's expression illustrates a FLWR (pronounced "flower") expression.
170 * The letters in the acronym stand for "for... let... where... return". As you
171 * can probably imagine, a FLWR expression is a way to loop through XML,
172 * binding variables and evaluating based on the variables. This is very similar
173 * to loops in Java.
174 *
175 * Compare the results of this method with the results of the
176 * selectEmpsByStateFLWR method in the SimpleExpressions web service. That
177 * method uses the execQuery method to execute the expression, while this one
178 * uses selectPath.
179 *
180 * @common:operation
181 */
182 public XmlObject[] selectEmpsByStateFLWR(XmlObject empDoc)
183 {
184 XmlObject[] resultArray = null;
185 /*
186 * This expression loops through the employee elements, querying for the
187 * state elements whose value is "WA", then returning the results.
188 */
189 String queryExpression =
190 "for $e in $this/xq:employees/xq:employee " +
191 "let $s := $e/xq:address/xq:state " +
192 "where $s = 'WA' " +
193 "return $e";
194 try
195 {
196 // Execute the expression.
197 resultArray = empDoc.selectPath(m_namespaceDeclaration + queryExpression);
198 }catch(Exception e)
199 {
200 System.out.println(e.getLocalizedMessage());
201 }
202 return resultArray;
203 }
204
205 /**
206 * Uses the selectPath method to execute the following
207 * expression against the incoming XML:
208 * <br/><br/>
209 *
210 * $this//xq:employee
211 *
212 * <br/><br/>
213 * If results are returned, you can move the cursor to the first of
214 * those results with the toNextSelection method. The method then
215 * uses the following path expression to get the name element for
216 * each employee element:
217 * <br/><br/>
218 *
219 * $this//xq:name
220 *
221 * <br/><br/>
222 * The name element values
223 * are placed into a String array returned by the method.
224 * <br/><br/>
225 * To test this method, paste the contents of the Employees.xml
226 * file between the getEmployees elements in the box on the
227 * Test XML tab of Test View.
228 *
229 * @common:operation
230 */
231 public String[] getEmployees(XmlObject employees)
232 {
233 /**
234 * Create a cursor with which to execute query expressions.
235 * The cursor is inserted at the very beginning of the
236 * incoming XML, then moved to the first element's start.
237 */
238 XmlCursor cursor = employees.newCursor();
239 cursor.toNextToken();
240 /**
241 * Execute the path expression, qualifying it with the
242 * namespace declaration.
243 */
244 cursor.selectPath(m_namespaceDeclaration + "$this//xq:employee");
245 // Advance to the first selection in the list.
246 cursor.toNextSelection();
247 /**
248 * Create an array to hold the name element values.
249 */
250 String[] names = new String[cursor.getSelectionCount()];
251 /**
252 * Loop through the selections, querying for the name
253 * element, then placing the name element's value
254 * in the String array.
255 */
256 for (int i = 0; i < cursor.getSelectionCount(); i++)
257 {
258 // An new cursor for the new query.
259 XmlCursor nameCursor = cursor.newCursor();
260 // Get the name element.
261 nameCursor.selectPath(m_namespaceDeclaration +
262 "$this/xq:name");
263 // Advance to the first selection.
264 nameCursor.toNextSelection();
265 /**
266 * Extract the name element's value and assign it
267 * to the array.
268 */
269 names[i] = nameCursor.getTextValue();
270 /**
271 * Advance to the next selection in the original set
272 * of results.
273 */
274 cursor.toNextSelection();
275 }
276 return names;
277 }
278 }
|