<?xml version="1.0" encoding="UTF-8"?>
<!--
  Licensed to the Apache Software Foundation (ASF) under one or more
  contributor license agreements.  See the NOTICE file distributed with
  this work for additional information regarding copyright ownership.
  The ASF licenses this file to You under the Apache License, Version 2.0
  (the "License"); you may not use this file except in compliance with
  the License.  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-->
<!DOCTYPE document PUBLIC "-//APACHE//DTD Documentation V2.0//EN" "http://forrest.apache.org/dtd/document-v20.dtd">
<document>
    <header>
        <title>Selecting XML with XQuery and XPath</title>
    </header>
    <body>
        <section>
            <title>Selecting XML with XQuery and XPath</title>

            <p>You can use XPath and XQuery to retrieve specific pieces of XML as you might
                retrieve data from a database. XQuery and XPath provide a syntax for specifying
                which elements and attributes you're interested in. The XMLBeans API provides
                two methods for executing XQuery and XPath expressions, and two ways to use them. The methods are
                <strong>selectPath</strong>
                for XPath and <strong>execQuery</strong> for XQuery.
            </p>
            <p>You can call them from and
                <a href="ext:api/stable/XmlObject">
                    <strong>XmlObject</strong>
                </a>
                instance (or a generated type inheriting from it) or an
                <a href="ext:api/stable/XmlCursor">
                    <strong>XmlCursor</strong>
                </a>
                instance.
                As noted below, each of the four methods works slightly differently; be sure to keep these differences
                in mind when choosing your approach.
            </p>
            <note>
                <strong>Note:</strong>
                Both XQuery and complex XPath expressions require additional classes on the class path, as noted in the
                sections that follow. Also, be sure to see the XMLBeans <a
                    href="site:install">installation instructions</a>.
            </note>
        </section>

        <section id="xpath_selectpath">
            <title>Using XPath with the selectPath Method</title>
            <p>You can execute XPath expressions use the <strong>selectPath</strong> method. When you use XPath with the
                <strong>selectPath</strong>
                method, the value returned is view of values from the <em>current document</em> &#8212; not a copy of
                those values. In other words, changes your code makes to XML returned by the selectPath method change
                the XML in the document queried against. In contrast, with XQuery executed using the <strong>execQuery
                </strong> method, the value returned is a <em>copy of values in the XML queried against</em>.
            </p>
            <p>Note that XPath itself does not provide syntax for declaring prefix to URI bindings. For user
                convenience, we allow XQuery syntax to be used for such purposes. You can consult the latest XQuery
                draft when using syntax for declaring namespaces.
            </p>
        </section>

        <section>
            <title>Calling XmlObject.selectPath</title>

            <p>When called from <strong>XmlObject</strong> (or a type that
                inherits from it), the <code>selectPath</code> method returns an array of objects. If the expression
                is executed against types generated from schema, then the type for the returned
                array is one of the Java types corresponding to the schema, and you can cast it accordingly.
            </p>

            <p>For example, imagine you have the following XML containing employee information.
                You've compiled the schema describing this XML and the types generated from
                schema are available to your code.
            </p>

            <source><![CDATA[
                <xq:employees xmlns:xq="http://xmlbeans.apache.org/samples/xquery/employees">
                    <xq:employee>
                        <xq:name>Fred Jones</xq:name>
                        <xq:address location="home">
                            <xq:street>900 Aurora Ave.</xq:street>
                            <xq:city>Seattle</xq:city>
                            <xq:state>WA</xq:state>
                            <xq:zip>98115</xq:zip>
                        </xq:address>
                        <xq:address location="work">
                            <xq:street>2011 152nd Avenue NE</xq:street>
                            <xq:city>Redmond</xq:city>
                            <xq:state>WA</xq:state>
                            <xq:zip>98052</xq:zip>
                        </xq:address>
                        <xq:phone location="work">(425)555-5665</xq:phone>
                        <xq:phone location="home">(206)555-5555</xq:phone>
                        <xq:phone location="mobile">(206)555-4321</xq:phone>
                    </xq:employee>
                </xq:employees>
            ]]></source>

            <p>If you wanted to find the phone numbers whose area code was 206, you could capture
                the XPath expression in this way:
            </p>

            <source><![CDATA[
                String queryExpression =
                "declare namespace xq='http://xmlbeans.apache.org/samples/xquery/employees';" +
                "$this/xq:employees/xq:employee/xq:phone[contains(., '(206)')]";
            ]]></source>

            <p>Notice in the query expression that the variable
                <strong>$this</strong>
                represents the current context node (the
                <strong>XmlObject</strong>
                that you are querying from). In this example you are querying from the document
                level <strong>XmlObject</strong>.
            </p>

            <p>You could then print the results with code such as the following:</p>

            <source><![CDATA[
                // Retrieve the matching phone elements and assign the results to the corresponding
                // generated type.
                PhoneType[] phones = (PhoneType[])empDoc.selectPath(queryExpression);

                // Loop through the results, printing the value of the phone element.
                for (int i = 0; i < phones.length; i++) {
                    System.out.println(phones[i].stringValue());
                }
            ]]></source>
        </section>

        <section>
            <title>Calling XmlCursor.selectPath</title>
            <p>When called from an <strong>XmlCursor</strong> instance, the
                <strong>selectPath</strong>
                method retrieves a list of <em>selections</em>,
                or locations in the XML. The selections are remembered by the cursor instance.
                You can use methods such as
                <strong>toNextSelection</strong>
                to navigate among them.
            </p>
            <p>The <strong>selectPath</strong> method takes an XPath expression.
                If the expression returns any results, each of those results is added as
                a selection to the cursor's list of selections. You can move through these
                selections in the way you might use
                <strong>java.util.Iterator</strong>
                methods to move through a collection.
            </p>
            <p>For example, for a path such as <strong>$this/employees/employee</strong>,
                the cursor instance from which you called <code>selectPath</code> would include a selection for each
                employee element found by
                the expression. Note that the variable
                <strong>$this</strong>
                is always bound to the current context node, which in this example is the
                document. After calling the <strong>selectPath</strong> method,
                you would use various "selection"-related methods to work with
                the results. These methods include:
            </p>

            <ul>
                <li>
                    <strong>getSelectionCount()</strong>
                    to retrieve the
                    number of selections resulting from the query.
                </li>
                <li>
                    <strong>toNextSelection()</strong>
                    to move the cursor to the next selection in the list (such as to the one pointing at the next
                    employee element found).
                </li>
                <li>
                    <strong>toSelection(int)</strong>
                    to move the cursor to the selection at the specified index (such as to the third employee element in
                    the selection).
                </li>
                <li>
                    <strong>hasNextSelection()</strong>
                    to find out if there are more selections after the cursor's current position.
                </li>
                <li>
                    <strong>clearSelections()</strong>
                    clears the selections from the current cursor. This doesn't modify the document (in other words, it
                    doesn't delete the selected XML); it merely clears the selection list so that the cursor is no
                    longer keeping track of those positions.
                </li>
            </ul>

            <p>The following example shows how you might use <strong>selectPath</strong>,
                in combination with the <strong>push</strong> and
                <strong>pop</strong>
                methods, to maneuver through XML, retrieving specific values.
            </p>

            <source><![CDATA[
                public void printZipsAndWorkPhones(XmlObject xml) {
                    // Declare the namespace that will be used.
                    String xqNamespace =
                    "declare namespace xq='http://xmlbeans.apache.org/samples/xquery/employees';";

                    // Insert a cursor and move it to the first element.
                    XmlCursor cursor = xml.newCursor();
                    cursor.toFirstChild();

                    // Save the cursor's current location by pushing it
                    // onto a stack of saved locations.
                    cursor.push();
                    // Query for zip elements.
                    cursor.selectPath(xqNamespace + "$this//xq:zip");

                    // Loop through the list of selections, getting the value of
                    // each element.
                    while (cursor.toNextSelection()) {
                        System.out.println(cursor.getTextValue());
                    }
                    // Pop the saved location off the stack.
                    cursor.pop();
                    // Query again from the top, this time for work phone numbers.
                    cursor.selectPath(xqNamespace + "$this//xq:phone[@location='work']");

                    // Move the cursor to the first selection, then print that element's
                    // value.
                    cursor.toNextSelection();
                    System.out.println(cursor.getTextValue());
                    // Dispose of the cursor.
                    cursor.dispose();
                }
            ]]></source>

            <p>Using selections is somewhat like tracking the locations of multiple cursors
                with a single cursor. This becomes especially clear when you remove the
                XML associated with a selection. When you do so the selection itself remains
                at the location where the removed XML was, but now the selection's location
                is immediately before the XML that was after the XML you removed. In other
                words, removing XML created a kind of vacuum that was filled by the XML
                after it, which shifted up into the space &#8212; up into position immediately
                after the selection location. This is exactly the same as if the selection
                had been another cursor.
            </p>
            <p>Finally, when using selections keep in mind that the list of selections
                is in a sense "live". The cursor you're working with is keeping
                track of the selections in the list. In other words, be sure to call the
                <strong>clearSelections</strong>
                method when you're finished
                with the selections, just as you should call the
                <strong>XmlCursor.dispose()</strong>
                method when you're finished using the cursor.
            </p>
        </section>

        <section id="xquery_execquery">
            <title>Using XQuery with the execQuery Method</title>
            <p>You use the <strong>execQuery</strong> method to execute XQuery
                expressions. With XQuery expressions, XML returned is a copy of XML in the document queried against. In
                other words, changes your code makes to the values returned by <code>execQuery</code> are not reflected
                in the document queried against.
            </p>
            <note id="saxon_jars">
                <strong>Note:</strong>
                To execute XQuery expressions, you must have Saxon-HE 12.5 on the classpath
                which can be downloaded from the <a
                    href="https://search.maven.org/artifact/net.sf.saxon/Saxon-HE/12.5/jar">Maven Repo</a>.
            </note>
        </section>

        <section>
            <title>Calling XmlObject.execQuery</title>
            <p>As with <strong>selectPath</strong>, calling
                <strong>execQuery</strong>
                from an <strong>XmlObject</strong> instance will return an
                <strong>XmlObject</strong>
                array.
            </p>
            <p>The following example retrieves work <code>&lt;zip&gt;</code> elements from the incoming XML, adding the
                elements as children to a new <code>&lt;zip-list&gt;</code> element.
            </p>
            <source><![CDATA[
                public boolean collectZips(XmlObject empDoc) {
                    String namespaceDeclaration =
                    "declare namespace xq='http://xmlbeans.apache.org/samples/xquery/employees';";
                    // The query is designed to return results, so return
                    // true if it does.
                    boolean hasResults = false;

                    // The expression: Get the <zip> elements and return them as children
                    // of a new <zip-list> element.
                    String queryExpression =
                        "let $e := $this/xq:employees " +
                        "return " +
                        "<zip-list> " +
                        "{for $z in $e/xq:employee/xq:address/xq:zip " +
                        "return $z} " +
                        "</zip-list>";

                    // Execute the query. Results will be copies of the XML queried against,
                    // stored as members of an XmlObject array.
                    XmlObject[] results =
                        empDoc.execQuery(namespaceDeclaration + queryExpression);

                    // Print the results.
                    if (results.length > 0) {
                        hasResults = true;
                        System.out.println("The query results: \n");
                        System.out.println(results[0].toString() + "\n");
                    }
                    return hasResults;
                }
            ]]></source>
        </section>

        <section>
            <title>Calling XmlCursor.execQuery</title>

            <p>Unlike the <code>selectPath</code> method called from a cursor, the <strong>execQuery</strong> method
                doesn't return <code>void</code>. Instead it returns an <strong>XmlCursor</strong> instance positioned
                at the beginning of a new XML document representing
                the query results. Rather than accessing results as selections, you use the cursor to move through the
                results in typical cursor fashion (for more information, see <a href="CursorNavigation.html">
                    Navigating XML with Cursors</a>). The models are very different.
            </p>
            <p>As always, you can cast the results to a type generated from schema if you know that the results conform
                to that type.
            </p>
            <p>The following example retrieves work <code>&lt;phone&gt;</code> elements from the incoming XML, then
                changes the number in the results.
            </p>
            <source><![CDATA[
                public boolean updateWorkPhone(XmlObject empDoc) {
                    boolean hasResults = false;

                    // A cursor instance to query with.
                    XmlCursor empCursor = empDoc.newCursor();
                    empCursor.toNextToken();

                    // The expression: Get the <employee> elements with <state> elements whose
                    // value is "WA".
                    String queryExpression =
                        "for $e in $this/xq:employees/xq:employee " +
                        "let $s := $e/xq:address/xq:state " +
                        "where $s = 'WA' " +
                        "return $e//xq:phone[@location='work']";

                    // Execute the query. Results, if any, will be available at
                    // the position of the resultCursor in a new XML document.
                    XmlCursor resultCursor =
                    empCursor.execQuery(namespaceDeclaration + queryExpression);

                    System.out.println("The query results, element copies made " +
                    "from the received document: \n");
                    System.out.println(resultCursor.getObject().toString() + "\n");

                    // If there are results, the results will be children of the fragment root
                    // where the new cursor is positioned. This statement tests for children
                    // and moves the cursor if to the first if it exists.
                    if (resultCursor.toFirstChild()) {
                        hasResults = true;
                        // Use the cursor to loop through the results, printing each sibling
                        // <employee>element returned by the query.
                        int i = 0;
                        do {
                            // Change the phone numbers.
                            XmlCursor editCursor = resultCursor.newCursor();
                            editCursor.toLastAttribute();
                            editCursor.toNextToken();
                            editCursor.removeXml();
                            editCursor.insertChars("(206)555-1234");
                        } while (resultCursor.toNextSibling());

                        resultCursor.toStartDoc();
                        System.out.println("The query results after changes: \n");
                        System.out.println(resultCursor.getObject().toString() + "\n");

                        System.out.println("The received document -- note that it is unchanged. " +
                        "Changes were made to the copy created by the execQuery method. \n");
                        System.out.println(empDoc + "\n");
                    }
                    return hasResults;
                }
            ]]></source>
        </section>

        <section>
            <title>Related Topics</title>
            <p>
                <a href="site:gettingstarted">Getting Started with XMLBeans</a>
            </p>
        </section>
    </body>
</document>
