Delicious Bookmark this on Delicious Share on Facebook SlashdotSlashdot It! Digg! Digg



PHP : Function Reference : DOM XML Functions : xpath_eval

xpath_eval

Evaluates the XPath Location Path in the given string (PHP 4 >= 4.0.4)
XPathObject xpath_eval ( XPathContext xpath_context, string xpath_expression [, domnode contextnode] )

XPathContext {
  XPathObject xpath_eval(string xpath_expression,
                         domnode contextnode);

}

The optional contextnode can be specified for doing relative XPath queries.

See also xpath_new_context().

Code Examples / Notes » xpath_eval

tk dot lists

You can indeed use the result object of xpath_eval(). You just have to be careful to pass the result by reference! (note the ampersand's position).
$objXP = xpath_new_context($objDom)
$objTest = &xpath_eval($objXP,"//lalala");
$objTest->nodeset[0]->set_attribute("test","test data");
echo htlentities($objDom->dump_mem());
just be careful that is you pass around values from $objTest then they also need to be passed by reference.


newsforsam

xpath_eval() returns only a copy of your document. So you cant for example change the $foo->nodeset[id]->content's of the resulting matches. If you want to, you have to do it yourself by going recursive through your doc, which makes xpath_eval at least useless except for checking if you have to ;).

pking

This is a very (very) minor point, but there is a comma missing in the function definition for xpath_eval.  This being my first experience with xpath, I thought "object xpath context" was refering to a single parameter produced by a previous call to xpath_new_context().  Then I couldn't see where you would add the query (which is actually the context parameter)
So the proper definition should be
array xpath_eval (object xpath, context)
Additionally an example would be nice.  I found one from a post to phpbuilder.com:
-------------------------------
http://www.phpbuilder.com/annotate/message.php3?id=1002772
-------------------------------
Message # 1002772:
Date: 01/02/01 06:40
By: Luis Argerich
Subject: new DOM features im 4.0.4
Just wanted to add that PHP 4.0.4 has improved DOM support including Xpath and
Xpointer support:
Try this:
$xml='SOME XML ....';
$doc=xmldoc($xml);
$ctx=xpath_new_context($doc);
$foo=xpath_eval($ctx,"//title");
print_r($foo);
It returns an object that contains a property called Nodeset with an array of DomNodes with the result of the Xpath expression. print_r($foo) to see the full structure.
4.0.4 has also added Xpointer support, so with Xpath and Xpointer support we can really do a lot of things from PHP to XML files.
Luis.


sbarnum@pointsystems com

This function has come in handy for recursively viewing the results of xpath searches.  It iterates through a node and converts it to a big associative array:
/**
* Recursive function to convert xml root node to big assoc array
*/
function xmlnode2array($node) {
   if ($node->type==XML_ELEMENT_NODE) {
       if ($attrArray = $node->attributes()) {
           // parse attributes //
           foreach($attrArray AS $attr) {
               $out['ATTRIBUTE'][$attr->name] = $attr->value;
           }
       }
       if ($childArray = $node->children()) {
           // add child nodes //
           foreach($childArray AS $child) {
               if ($child->type==XML_ELEMENT_NODE) {
                   $out[$child->tagname][] = xmlnode2array($child);
               } else {
                   if ($content = xmlnode2array($child))
                       $out['CONTENT'] = $content;
               }
           }
       }
   } else {
       // this is a CONTENT NODE //
       $out = trim($node->content);
       if (!$out) return false;
   }
   return $out;
}


fabiostt x_at_x libero x_dot_x .it

Querying documents closed inside a namespace can be tricky
http://bugs.php.net/bug.php?id=11903


tuxo

PHP Version: 4.3.1
I tried out how to get a part of a xml document with the xpath functions in domxml.
Try the following solution:
<?php
// get dom object
$xmldoc = domxml_open_mem($xml);
// init xpath
$xpath = xpath_new_context($xmldoc);
$xpresult = xpath_eval($xpath, "/root/info");
// dump all nodes directly in plain text
foreach ($xpresult->nodeset as $node)
{
   $newxml .= $node->dump_node($node);
}
?>
If you wanna get a new dom object of the result just add
$newxmldoc = domxml_open_mem($newxml);


patrikg

Just an example of how to grab XML attributes with xpath - which took me a while to figure out. I'm filtering the returned object function node_content() which is a somewhat quick'n dirty solution, but I don't always need XML's child-parent relationships.
<?php
$xml='<MY_SERVICE>
<MERCHANDISE>
<SERVICE TYPE="books">
<NAME>Ulysses</NAME>
</SERVICE>
<SERVICE TYPE="books">
<NAME>The Poisonwood Bible</NAME>
</SERVICE>
<SERVICE TYPE="cars">
<NAME>Van</NAME>
</SERVICE>
<SERVICE TYPE="vehicle sans wheels">
<NAME>UFO</NAME>
</SERVICE>
</MERCHANDISE>
</MY_SERVICE>';
echo "<h4>XML</h4><xmp>";print_r(parse_XML($xml));echo"</xmp>";
function node_content($node,$attribute="content"){
foreach($node->nodeset as $content){
$return[] = $content->{$attribute};
}
return $return;
}
function parse_XML($xml){
//needs PHP's xPath extension installed
$dom =domxml_open_mem($xml);
$calcX = &$dom->xpath_new_context();
$xml_parsed["merchandise"]=node_content(
$calcX->xpath_eval("//MERCHANDISE/SERVICE/NAME/text()")
);
$xml_parsed["service"]=node_content(
$calcX->xpath_eval("//MERCHANDISE/SERVICE/attribute::TYPE",$calcX)
,"value");
return $xml_parsed;
}
?>
The code above returns:
XML
Array
(
   [merchandise] => Array
       (
           [0] => Ulysses
           [1] => The Poisonwood Bible
           [2] => Van
           [3] => UFO
       )
   [service] => Array
       (
           [0] => books
           [1] => books
           [2] => cars
           [3] => vehicle sans wheels
       )
)


ziw

it seems that namespaces are not yet (PHP 4.06) implemented - xpath_eval($cnx,"/ns:tag") does work on w2k and does NOT on linux

brandon dot whitehead

In order to use the default namespace you must understand
how namespace prefixes work.  Prefixes are simply convenient mappies to the namespace URI.
For example, if you set the namespace:
xmlns:xm="http://www.someurl.org"
and you have the following document fragment:
<rootnode><xm:childnode>Text</xm:childnode></rootnode>  
this is essentially equivalent to:
<rootnode>
  <http://www.someurl.org:childnode>
     Text
  </http://www.someurl.org:childnode>
</rootnode>  
because the namespace URI is what matters, not the namespace prefix.
Unfortuantly, if you have a default namespace:
xmlns="http://www.anotherurl.org"
then all elements without a prefix belong to that namespace, and yet, it appears that PHP, and the underlying LIBXML2 don't let you register a default namespace with
"xpath_register_ns(context, prefix, uri)"
i.e. by leaving the prefix = "".  Therefore, to get around the problem, simply give the default prefix a simple name, such as "pre".  
For example, if you have a default namespace declaration such as the following document:
<?xml version="1.0" encoding="UTF-8"?>
<rootname xmlns="http://www.some.org" xml:lang="en-US">
  <childnode>Some text</childnode>
</rootname>
And you want to evaluate the xpath expression:
"/rootname/childnode"
then you need to register the default namespace in PHP like this:
xpath_register_ns(context, "pre", "http://www.some.org");
and then use the following xpath expression:
"/pre:rootname/pre:childnode"
As you can see this is a lot prettier and more intuititive than using the local-name() function.  In addition, it makes your code more portable, because you are guaranteed to always be working on nodes that belong to your explicitly stated namespace, uniquely identified by your URI.


arthur

If you want to get the XPath for a particular node:
function getXPath($node) {
/* node id is held in a property named '1', this is
illegal in php so we use a workaround */
   $one = '1';
   $xpath = '';
   while ($parent = $node->parent_node()) {
       $siblings = $parent->child_nodes();
       $index = 1;
       foreach ($siblings as $sibling) {
           if ($sibling->type != XML_ELEMENT_NODE || $sibling->tagname != $node->tagname) continue;
           if ($sibling->$one == $node->$one) {
               $xpath = '/' . $node->tagname . '[' . $index . ']' . $xpath;
               break;
             }
           $index++;
           }
       $node = $parent;
       }
   return $xpath;
   }


chregu

If you want to apply an XPath-Expression to a particular node:
$ctx->xpath_eval("xpath",$node);


marius kreis email to mariuskreis . de

If the namespace is subject to change you can write even more portable code if you extend brandon dot whitehead at orst dot edu's solution like this:
$doc = domxml_open_mem($xml);
$xpath = $doc->xpath_new_context();
$namespace = $xpath->xpath_eval('namespace-uri(//*)')->value; // returns the namespace uri
xpath_register_ns($xpath, "pre", $namespace); // sets the prefix "pre" for the namespace
$obj = $xpath->xpath_eval('//pre:Offer'); // finds all Offer tags
$nodeset = $obj->nodeset;
print_r($nodeset);
This code will determine the namespace of the root element and set a prefix for XPath queries. Thus it doesn't matter if the namespace is changing in your XML (like some webservices do...)


sofnology

I hope this little example helps someone out. If the XML data doesn't come thru in the post feel free to contact me via email.
<?
$p = xslt_create();
$o += 0;
$s =  '';
$s .= "<query type='create'>";
$s .= "<resourceClass id='12345678901234567890' displayName='DAISY'>";
$s .= "<group family='global' id='kind'>";
$s .= "<node id='NODE_A' displayName='Red Ferrari' description='Red always goes faster'/>";
$s .= "</group>";
$s .= "</resourceClass>";
$s .= "<resourceClass id='12345678901234567890' displayName='BETTY'>";
$s .= "<group family='global' id='kind'>";
$s .= "<node id='NODE_B' displayName='Blue Porsche' description='But Porsches are a drivers car'/>";
$s .= "</group>";
$s .= "</resourceClass>";
$s .= "</query>";
$dom=xmldoc($s);
$ctx=xpath_new_context($dom);
$query_xo = xpath_eval($ctx,"count(/query/resourceClass)");
$num_rc = $query_xo->value;
echo("
There are $num_rc classes in this list");
for($x=1; $x <= $num_rc; $x++){
$query_xo = xpath_eval($ctx,"/query/resourceClass[position()=$x]");
$query_ns = $query_xo->nodeset;
$resourceClass_dn = $query_ns[0];
// echo("<PRE>");
// print_r( $query_xo );
// echo("<PRE><HR>");
// print_r( $query_ns );
// echo("<PRE><HR>");
// print_r( $rc_dn );
echo("
[id::".$resourceClass_dn->get_attribute('id')."][displayName::".$resourceClass_dn->get_attribute('displayName')."]");
}
?>


28-mar-2001 03:12

actually the description at the top should read:
object xpath_eval(object context, string xpath);


bate

<?
$xml = xmldocfile('file.xml');
$xpath = $xml->xpath_new_context();
/**
* object access
*/
$ret = $xpath->xpath_eval('//tag');
/**
* function access
*/
$ret2 = xpath_eval($xpath, '//tag');
print_r($ret);
print_r($ret2);
?>


mfkahn2_nospam

$ctx = xpath_new_context($doc);
$xpath_nodes = xpath_eval($ctx, "//some_element");
$xpath_nodes->nodeset[i]->set_content($string) allows you to set the node content.  Try it and then do a $doc->dumpmem, you'll see the nodes in the original document are indeed updated properly.
I've used this feature lots.  It does work.


Change Language


Follow Navioo On Twitter
DomAttribute->name
DomAttribute->set_value
DomAttribute->specified
DomAttribute->value
DomDocument->add_root
DomDocument->create_attribute
DomDocument->create_cdata_section
DomDocument->create_comment
DomDocument->create_element_ns
DomDocument->create_element
DomDocument->create_entity_reference
DomDocument->create_processing_instruction
DomDocument->create_text_node
DomDocument->doctype
DomDocument->document_element
DomDocument->dump_file
DomDocument->dump_mem
DomDocument->get_element_by_id
DomDocument->get_elements_by_tagname
DomDocument->html_dump_mem
DomDocument->xinclude
DomDocumentType->entities()
DomDocumentType->internal_subset()
DomDocumentType->name()
DomDocumentType->notations()
DomDocumentType->public_id()
DomDocumentType->system_id()
DomElement->get_attribute_node()
DomElement->get_attribute()
DomElement->get_elements_by_tagname()
DomElement->has_attribute()
DomElement->remove_attribute()
DomElement->set_attribute_node()
DomElement->set_attribute()
DomElement->tagname()
DomNode->add_namespace
DomNode->append_child
DomNode->append_sibling
DomNode->attributes
DomNode->child_nodes
DomNode->clone_node
DomNode->dump_node
DomNode->first_child
DomNode->get_content
DomNode->has_attributes
DomNode->has_child_nodes
DomNode->insert_before
DomNode->is_blank_node
DomNode->last_child
DomNode->next_sibling
DomNode->node_name
DomNode->node_type
DomNode->node_value
DomNode->owner_document
DomNode->parent_node
DomNode->prefix
DomNode->previous_sibling
DomNode->remove_child
DomNode->replace_child
DomNode->replace_node
DomNode->set_content
DomNode->set_name
DomNode->set_namespace
DomNode->unlink_node
DomProcessingInstruction->data
DomProcessingInstruction->target
DomXsltStylesheet->process()
DomXsltStylesheet->result_dump_file()
DomXsltStylesheet->result_dump_mem()
domxml_new_doc
domxml_open_file
domxml_open_mem
domxml_version
domxml_xmltree
domxml_xslt_stylesheet_doc
domxml_xslt_stylesheet_file
domxml_xslt_stylesheet
domxml_xslt_version
xpath_eval_expression
xpath_eval
xpath_new_context
xpath_register_ns_auto
xpath_register_ns
xptr_eval
xptr_new_context
eXTReMe Tracker