eXcavator
An XML Query Facility for XML_PullParser
version 1.0.6
Myron Turner
Namespace Support

Contents         

Namespace support for eXcavator builds directly upon the namespace support in XML_PullParser.1 It entails the addition of two package level functions:
  1. mixed eXcavator_setNamespace(string $ns)
    This function takes a single parameter, a string consisting of one or more namespace URI's. They must be exactly as defined in the XML document. If there is a trailing forward slash in the URI, then this must be included. If more than one namespace is passed in, they must separated by the vertical bar:
    $parser->XML_PullParser_setCurrentNS("http://room535.org/movies/title/|"
    . "http://room535.org/movies/mov/|http://room535.org/movies/star/");
    The return value is the previously set namespace definition, or TRUE if there was no previous namespace defined.
  2. mixed eXcavator_unsetNamespace()
    This function unsets the current namespace definition.
    It is aimed at scripts which create more than one instance of eXcavator, where the the aim is to turn off namespace support and unset the namespace definition, so that the next query is processed without namespace support in effect. Unless this function is called between queries, the namespace definition of the previous query remains in effect and therefore namespace support will also remain in effect.
    Its return value is the previously set namespace definition or NULL if no definition has been set.

Let's make the following changes to the sample XML document and then look at some examples of queries that use namespace support.


<vehicles
  xmlns = "http://example.com/default/"
  xmlns:nm = "http://example.com/local/name/"
  xmlns:addr = "http://example.com/local/addr/"
  xmlns:attr = "http://example.com/local/attributes/"
>
     .    .    . 
  <owner>
        <name>
            <nm:last_name>Jones</nm:last_name>
            <nm:first_name nm:middle_init="J">Douglas</nm:first_name>
            <addr:address>
                <addr:street>200 Winnipegosis Ave</addr:street>
                <addr:city>St Adolphe</addr:city>
                <addr:city>Winnipeg</addr:city>
                <addr:zip>R3L 1Z5</addr:zip>
            </addr:address>
        </name>
   </owner>

These changes create four namespaces, one for names, one for the address, one for attributes, and a default namespace which applies to all elements (but not attributes) that do not have a namespace prefix assigned to them. 2 Following are a few sample queries and their results.


Example 1
This example sets the namespace definition to http://example.com/local/name/, which is assigned to the prefix nm . The query returns the owner element which has "Douglas" for first_name and "J" for middle_init . Had the query been
owner[[first_name => CDATA = Michael _AND_ first_name @middle_init=M]]
it would return no result because these are not in the defined namespace.

   eXcavator_setNamespace("http://example.com/local/name/");
   $condition = "owner[[first_name => CDATA  <<  Douglas _AND_ first_name @middle_init=J]]"    
   $this->eXc->eXcavator_Query($condition);

   $str =  $this->eXc->eXcavator_getResultAsString  (false, true);
   echo "$str\n";

/*
Result

 < !--   -- 1 --   -->
 < OWNER>
 < NAME>
 < LAST_NAME>Jones < /LAST_NAME>
 < FIRST_NAME MIDDLE_INIT = "J">Douglas < /FIRST_NAME>
 < ADDRESS>
 < STREET>200 Winnipegosis Ave < /STREET>
 < CITY>St Adolphe < /CITY>
 < CITY>Winnipeg < /CITY>
 < ZIP>R3L 1Z5 < /ZIP>
 < /ADDRESS>
 < /NAME>
 < /OWNER>

*/


Example 2
This query returns all of the street elements which are in the default namespace, but excludes
     <addr:street>200 Winnipegosis Ave</addr:street>
which is in the addr namespace.

     eXcavator_setNamespace("http://example.com/default/");
     $this->eXc->eXcavator_Query("street[[CDATA]]");
     echo $this->eXc->eXcavator_getResultAsString(false,true) . "\n";
/*
Result

 < !--   -- 1 --   -->
 < STREET>Waverly St. < /STREET>

 < !--   -- 2 --   -->
 < STREET>323 Oak Bay < /STREET>

 < !--   -- 3 --   -->
 < STREET>750 Main St < /STREET>

*/


Example 3
Examples three and four execute the same query. In example three, the namespace definition is set to
http://example.com/local/attributes/
The query returns the one carfax element which conforms to that namespace definition. Example four, however, calls the XML_PullParser package level function
XML_PullParser_Disable_NS_Prefixes
with a value of True . This causes XML_PullParser to ignore namespace prefixes and so the query returns both carfax elements.


     eXcavator_setNamespace("http://example.com/local/attributes/");
     $this->eXc->eXcavator_Query("carfax[[@buyback]]");
     echo $this->eXc->eXcavator_getResultAsString(false,true) . "\n";
/*
Result

 < !--   -- 1 --   -->
 < CARFAX BUYBACK = "yes"> < /CARFAX>


*/


Example 4



     XML_PullParser_Disable_NS_Prefixes(true);

     $this->eXc->eXcavator_Query("carfax[[@buyback]]");
     echo $this->eXc->eXcavator_getResultAsString(false,true) . "\n";

/*
Result

 < !--   -- 1 --   -->
 < CARFAX BUYBACK = "no"> < /CARFAX>

 < !--   -- 2 --   -->
 < CARFAX BUYBACK = "yes"> < /CARFAX>


*/


CDATA Queries
A final note about using the unqualified CDATA condition. Let's assume the query is
owner[[CDATA]]    
and that the namespace definition is set to the default namespace. The query would return the complete first owner element, i.e. Michael M. Taylor and his address. If, however, in the treatment of the second owner's address we had this:
<zip>R3L 1Z5</zip>    
the query would return both owner elements. The reason for this is that the addr prefix has been omitted from zip . The query asks for any character data that is found in the owner element. Therefore, XML_PullParser checks every element in owner for it conformance with the namespace definition that has been set for the query. When it arrives at zip , it finds an element that is in the default namespace and returns the zip code. This causes eXcavator to evaluate the condition as True , because all that the query has asked for is the presence of any character data in owner and the zip code meets that test.


Notes
1 Namespace support was introduced with release 1.3.0. As of this writing, the current version 1.3.1, which introduces some additional namespace functionality.
2. Default namespaces do not apply to attributes, only to elements.