<?xml version="1.0" encoding="UTF-8"?>
<!-- Reviewed: no -->
<sect1 id="zend.dom.query">
    <title>Zend_Dom_Query</title>

    <para>
        <classname>Zend_Dom_Query</classname> provides mechanisms for querying XML and
        (X)HTML documents utilizing either XPath or CSS selectors. It was
        developed to aid with functional testing of MVC applications, but could
        also be used for rapid development of screen scrapers.
    </para>

    <para>
        CSS selector notation is provided as a simpler and more familiar
        notation for web developers to utilize when querying documents with XML
        structures. The notation should be familiar to anybody who has developed
        Cascading Style Sheets or who utilizes Javascript toolkits that provide
        functionality for selecting nodes utilizing CSS selectors
        (<ulink url="http://prototypejs.org/api/utility/dollar-dollar">Prototype's
            $$()</ulink> and
        <ulink url="http://api.dojotoolkit.org/jsdoc/dojo/HEAD/dojo.query">Dojo's
            dojo.query</ulink> were both inspirations for the component).
    </para>

    <sect2 id="zend.dom.query.operation">
        <title>Theory of Operation</title>

        <para>
            To use <classname>Zend_Dom_Query</classname>, you instantiate a
            <classname>Zend_Dom_Query</classname> object, optionally passing a document to
            query (a string). Once you have a document, you can use either the
            <methodname>query()</methodname> or <methodname>queryXpath()</methodname> methods; each
            method will return a <classname>Zend_Dom_Query_Result</classname> object with
            any matching nodes.
        </para>

        <para>
            The primary difference between <classname>Zend_Dom_Query</classname> and using
            DOMDocument + DOMXPath is the ability to select against CSS
            selectors. You can utilize any of the following, in any combination:
        </para>

        <itemizedlist>
            <listitem><para>
                <emphasis>element types</emphasis>: provide an element type to
                match: 'div', 'a', 'span', 'h2', etc.
            </para></listitem>

            <listitem><para>
                <emphasis>style attributes</emphasis>: CSS style attributes to
                match: '.error', 'div.error', 'label.required', etc. If an
                element defines more than one style, this will match as long as
                the named style is present anywhere in the style declaration.
            </para></listitem>

            <listitem><para>
                <emphasis>id attributes</emphasis>: element ID attributes to
                match: '#content', 'div#nav', etc.
            </para></listitem>

            <listitem>
                <para>
                    <emphasis>arbitrary attributes</emphasis>: arbitrary element
                    attributes to match. Three different types of matching are
                    provided:
                </para>

                <itemizedlist>
                    <listitem><para>
                        <emphasis>exact match</emphasis>: the attribute exactly
                        matches the string: 'div[bar="baz"]' would match a div
                        element with a "bar" attribute that exactly matches the
                        value "baz".
                    </para></listitem>

                    <listitem><para>
                        <emphasis>word match</emphasis>: the attribute contains
                        a word matching the string: 'div[bar~="baz"]' would match a div
                        element with a "bar" attribute that contains the
                        word "baz". '&lt;div bar="foo baz"&gt;' would match, but '&lt;div
                                bar="foo bazbat"&gt;' would not.
                    </para></listitem>

                    <listitem><para>
                        <emphasis>substring match</emphasis>: the attribute contains
                        the string: 'div[bar*="baz"]' would match a div
                        element with a "bar" attribute that contains the
                        string "baz" anywhere within it.
                    </para></listitem>
                </itemizedlist>
            </listitem>

            <listitem><para>
                <emphasis>direct descendents</emphasis>: utilize '&gt;' between
                selectors to denote direct descendents. 'div > span' would
                select only 'span' elements that are direct descendents of a
                'div'. Can also be used with any of the selectors above.
            </para></listitem>

            <listitem>
                <para>
                    <emphasis>descendents</emphasis>: string together
                    multiple selectors to indicate a hierarchy along which
                    to search. 'div .foo span #one' would select an element
                    of id 'one' that is a descendent of arbitrary depth
                    beneath a 'span' element, which is in turn a descendent
                    of arbitrary depth beneath an element with a class of
                    'foo', that is an descendent of arbitrary depth beneath
                    a 'div' element. For example, it would match the link to
                    the word 'One' in the listing below:
                </para>

                <programlisting language="html"><![CDATA[
<div>
<table>
    <tr>
        <td class="foo">
            <div>
                Lorem ipsum <span class="bar">
                    <a href="/foo/bar" id="one">One</a>
                    <a href="/foo/baz" id="two">Two</a>
                    <a href="/foo/bat" id="three">Three</a>
                    <a href="/foo/bla" id="four">Four</a>
                </span>
            </div>
        </td>
    </tr>
</table>
</div>
]]></programlisting>
            </listitem>
        </itemizedlist>

        <para>
            Once you've performed your query, you can then work with the result
            object to determine information about the nodes, as well as to pull
            them and/or their content directly for examination and manipulation.
            <classname>Zend_Dom_Query_Result</classname> implements <code>Countable</code>
            and <code>Iterator</code>, and store the results internally as
            DOMNodes/DOMElements. As an example, consider the following call,
            that selects against the HTML above:
        </para>

        <programlisting language="php"><![CDATA[
$dom = new Zend_Dom_Query($html);
$results = $dom->query('.foo .bar a');

$count = count($results); // get number of matches: 4
foreach ($results as $result) {
    // $result is a DOMElement
}
]]></programlisting>

        <para>
            <classname>Zend_Dom_Query</classname> also allows straight XPath queries
            utilizing the <methodname>queryXpath()</methodname> method; you can pass any
            valid XPath query to this method, and it will return a
            <classname>Zend_Dom_Query_Result</classname> object.
        </para>
    </sect2>

    <sect2 id="zend.dom.query.methods">
        <title>Methods Available</title>

        <para>
            The <classname>Zend_Dom_Query</classname> family of classes have the following
            methods available.
        </para>

        <sect3 id="zend.dom.query.methods.zenddomquery">
            <title>Zend_Dom_Query</title>

            <para>
                The following methods are available to
                <classname>Zend_Dom_Query</classname>:
            </para>

            <itemizedlist>
                <listitem><para>
                    <methodname>setDocumentXml($document)</methodname>: specify an XML
                    string to query against.
                </para></listitem>

                <listitem><para>
                    <methodname>setDocumentXhtml($document)</methodname>: specify an XHTML
                    string to query against.
                </para></listitem>

                <listitem><para>
                    <methodname>setDocumentHtml($document)</methodname>: specify an HTML
                    string to query against.
                </para></listitem>

                <listitem><para>
                    <methodname>setDocument($document)</methodname>: specify a
                    string to query against; <classname>Zend_Dom_Query</classname> will
                    then attempt to autodetect the document type.
                </para></listitem>

                <listitem><para>
                    <methodname>getDocument()</methodname>: retrieve the original document
                    string provided to the object.
                </para></listitem>

                <listitem><para>
                    <methodname>getDocumentType()</methodname>: retrieve the document
                    type of the document provided to the object; will be one of
                    the <code>DOC_XML</code>, <code>DOC_XHTML</code>, or
                    <code>DOC_HTML</code> class constants.
                </para></listitem>

                <listitem><para>
                    <methodname>query($query)</methodname>: query the document using CSS
                    selector notation.
                </para></listitem>

                <listitem><para>
                    <methodname>queryXpath($xPathQuery)</methodname>: query the document
                    using XPath notation.
                </para></listitem>
            </itemizedlist>
        </sect3>

        <sect3 id="zend.dom.query.methods.zenddomqueryresult">
            <title>Zend_Dom_Query_Result</title>

            <para>
                As mentioned previously, <classname>Zend_Dom_Query_Result</classname>
                implements both <code>Iterator</code> and
                <code>Countable</code>, and as such can be used in a
                <code>foreach</code> loop as well as with the
                <methodname>count()</methodname> function. Additionally, it exposes the
                following methods:
            </para>

            <itemizedlist>
                <listitem><para>
                    <methodname>getCssQuery()</methodname>: return the CSS selector query
                    used to produce the result (if any).
                </para></listitem>

                <listitem><para>
                    <methodname>getXpathQuery()</methodname>: return the XPath query
                    used to produce the result. Internally,
                    <classname>Zend_Dom_Query</classname> converts CSS selector queries to
                    XPath, so this value will always be populated.
                </para></listitem>

                <listitem><para>
                    <methodname>getDocument()</methodname>: retrieve the DOMDocument the
                    selection was made against.
                </para></listitem>
            </itemizedlist>
        </sect3>
    </sect2>
</sect1>
<!--
vim:se ts=4 sw=4 et:
-->
