xpath_eval
(PHP 4 >= 4.0.4)
xpath_eval — Evaluates the XPath Location Path in the given string
Описание
XPathContext
XPathObject xpath_eval
( XPathContext $xpath_context
, string $xpath_expression
[, domnode $contextnode
] )
The optional contextnode can be specified for doing relative XPath queries.
See also xpath_new_context().
[an error occurred while processing the directive]
- 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
Коментарии
$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.
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
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;
}
<?
$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);
?>
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;
}
If you want to apply an XPath-Expression to a particular node:
$ctx->xpath_eval("xpath",$node);
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.
Querying documents closed inside a namespace can be tricky
http://bugs.php.net/bug.php?id=11903
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.