PHP 7.1.0 Released

xpath_eval

(PHP 4)

xpath_eval ارزیابی محل مسیر XPath در رشته داده شده

Description

XPathObject XPathContext::xpath_eval ( string $xpath_expression [, domnode $contextnode ] )
XPathObject xpath_eval ( XPathContext $xpath_context , string $xpath_expression [, domnode $contextnode ] )

contextnode اختیاری برای پرس و جوی نسبی XPath استفاده می‌شود.

xpath_new_context() را ببینید.

add a note add a note

User Contributed Notes 9 notes

up
0
brandon dot whitehead at orst dot edu
13 years ago
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.
up
0
fabiostt[X_AT_X]libero[X_DOT_X].it
13 years ago
Querying documents closed inside a namespace can be tricky

http://bugs.php.net/bug.php?id=11903
up
0
tk dot lists at fastmail dot fm
13 years ago
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.
up
0
chregu at php dot net
14 years ago
If you want to apply an XPath-Expression to a particular node:

$ctx->xpath_eval("xpath",$node);
up
0
arthur at ischium dot net
14 years ago
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;
    }
up
0
bate at php dot net
14 years ago
<?
$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);
?>
up
0
sbarnum@pointsystems com
14 years ago
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;
}
up
0
ziw at ifirst dot ru
15 years ago
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
up
0
mfkahn2_NOSPAM at yahoo dot com
15 years ago
$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.
To Top