SimpleXMLElement::xpath

(PHP 5 >= 5.2.0)

SimpleXMLElement::xpathRuns XPath query on XML data

Description

public array SimpleXMLElement::xpath ( string $path )

The xpath method searches the SimpleXML node for children matching the XPath path.

Parameters

path

An XPath path

Return Values

Returns an array of SimpleXMLElement objects or FALSE in case of an error.

Examples

Example #1 Xpath

<?php
$string 
= <<<XML
<a>
 <b>
  <c>text</c>
  <c>stuff</c>
 </b>
 <d>
  <c>code</c>
 </d>
</a>
XML;

$xml = new SimpleXMLElement($string);

/* Search for <a><b><c> */
$result $xml->xpath('/a/b/c');

while(list( , 
$node) = each($result)) {
    echo 
'/a/b/c: ',$node,"\n";
}

/* Relative paths also work... */
$result $xml->xpath('b/c');

while(list( , 
$node) = each($result)) {
    echo 
'b/c: ',$node,"\n";
}
?>

The above example will output:

/a/b/c: text
/a/b/c: stuff
b/c: text
b/c: stuff

Notice that the two results are equal.

See Also

Коментарии

xpath() can also be used to select elements by their attributes. For a good XPath reference check out: http://www.w3schools.com/xpath/xpath_syntax.asp

<?php
$string 
= <<<XML
<sizes>
    <size label="Square" width="75" height="75" />
    <size label="Thumbnail" width="100" height="62" />
    <size label="Small" width="112" height="69" />
    <size label="Large" width="112" height="69" />
</sizes>
XML;

$xml simplexml_load_string($string);
$result $xml->xpath("//size[@label='Large']");

// print the first (and only) member of the array
echo $result[0]->asXml();
?>

The script would print: 
<size label="Large" width="112" height="69"/>
2005-07-10 21:16:03
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Автор:
Note that this function does not ALWAYS return an array. It seems that if the specified path is not found in the document, it will return false. You need to check for the false value before using foreach, if you wish to avoid a warning (and often to handle errors or control program flow in this situation).
2005-12-18 17:23:19
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
If you want to search multiple values from xml on the behalf or one value then this code can be helpfull to you.

if there is:
<Record>
  <country>Pakistan</country>
  <code>+92</code>
  <Value>100<Value>
</Record>

then try this one:
<?php
$sxe 
simplexml_load_file("countries.XML");
foreach(
$sxe->xpath('//RECORD') as $item) {

   
$row simplexml_load_string($item->asXML());
   
$v $row->xpath('//country[. ="Pakistan"]');
    if(
$v[0]){
        print 
$item->country;
        print 
$item->code;
        print 
$item->value;
    }
   
}
?>
2008-05-05 08:05:48
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
xpath doesn't seem to be able to handle single quotes embedded in the query itself. For instance, I want to find geo coordinates in an xml file based on country name. 

xml snippet:

<zones>
<zone country="Cote d'Ivoire" fullName="Yamoussoukro" geo="6.82,-5.28" id="1050"><url prefix="1001" value="fiji.html" /><url prefix="1002" value="C" /></zone>
</zones>

The following code does not work:

<?php
$xml 
simplexml_load_file("my.xml");
$result $xml->xpath("//zone[@country='Cote d\'Ivoire']");

foreach ( 
$result[0]->attributes() as $key => $val ) {
    print 
"<div class='coords'>$key$val</div>\n";
}
?>

I have tried many variations on the embedded single quote (i.e. escape codes) but with no result. W3C offers no explanation either. 

In addition, there doesn't seem to be any way of embedding wildcards in the attribute value (you can embed wildcards in the attribute name). Otherwise the following might be a reasonable substitute in this context:

<?php $result $xml->xpath("//zone[@country='Cote d*Ivoire']"); ?>
2008-06-18 15:17:44
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Автор:
If you want to find easly all records satisfying some condition in XML data like 

....
   <book id="bk101">
      <author>Gambardella, Matthew</author>
      <title>XML Developer's Guide</title>
      <genre>Computer</genre>
      <price>44.95</price>
   </book>
   <book id="bk102">
      <author>Ralls, Kim</author>
      <title>Midnight Rain</title>
      <genre>Fantasy</genre>
      <price>5.95</price>
   </book>
...

try example below

<?php

$xmlStr 
file_get_contents('data/books.xml');
$xml = new SimpleXMLElement($xmlStr);
// seach records by tag value:
// find all book records with price higher than 40$
$res $xml->xpath("book/price[.>'40']/parent::*");
print_r($res);

?>

You will see response like:
Array (
[0] => SimpleXMLElement Object
        (
            [@attributes] => Array
                (
                    [id] => bk101
                )

            [author] => Gambardella, Matthew
            [title] => XML Developer's Guide
            [genre] => Computer
            [price] => 44.95
            [publish_date] => 2000-10-01
            [description] => An in-depth look at creating applications 
      with XML.
        )
...
2008-07-02 18:46:39
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
The simplest way to count nodes in a XML doc:

<?php
$xml 
= new SimpleXMLElement($xmlstr);

$xmlNode $xml->xpath('root/yourNodeName');
$nodeCount count($xmlNode);

echo 
$nodeCount;
?>
2009-06-11 18:23:51
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Автор:
Whether it returns a false or empty array for a non-existing path seems to depend on libxml version.

I tried the following code:

<?php
$data 
'<foo><bar></bar></foo>';
$xml simplexml_load_string($data);
print 
gettype($xml->xpath('/first/second'));
?>

On a machine with libxml 2.6.16 and PHP 5.2.8 I got back boolean. On a different machine with libxml 2.7.3 and PHP 5.2.8/5.2.9 I got back empty array.

You can check the libxml version from command line by executing: php --ri libxml

or simply look at phpinfo() output
2009-06-17 06:50:22
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Автор:
Seems like this function cannot return the result of XPath string() [1] function.  For example if you query xpath("string(a/@b)") you will get bool(false) although the node "a" may have the attribute "b" set to a non-empty string.

[1] http://www.w3.org/TR/xpath#section-String-Functions
2009-09-24 16:34:43
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Looks like the relative path is relative to the SimpleXMLElement object that you call the Xpath() method on.  Basically chopping off the root element.

<?php
$string 
= <<<XML
<foo>
  <bar>
    <a>
     <b>
      <c>text</c>
      <c>stuff</c>
     </b>
     <d>
      <c>code</c>
     </d>
    </a>
  </bar>
</foo>
XML;

$xml = new SimpleXMLElement($string);
/* Search for children using 2nds level relative <bar><a><b><c> */
$result $xml->xpath('a/b/c');
if (
$result
foreach(
$result as $node) {
   
drupal_set_message(t('a/b/c: @node.', array('@node' => $node)));
}
else
 
drupal_set_message(t('a/b/c: failed.'));
                     
/* it relative to the SimpleXMLElement Search for 2nds level relative <bar><a><b><c> but where is foo */
$bar $xml->bar;
$result $bar->xpath('a/b/c');
foreach(
$result as $node) {
   
drupal_set_message(t('bar->a/b/c: @node.', array('@node' => $node)));
}
?>

results in :
#
# a/b/c: failed.
# bar->a/b/c: text.
# bar->a/b/c: stuff.
2009-12-02 14:27:55
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
On a xml that have namespace you need to do this before your xpath request (or empty array will be return) :

<?php
$string 
str_replace('xmlns=''ns='$string); //$string is a string that contains xml...
?>
2010-02-11 06:08:32
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Having problems selecting information through xpath when there are namespaces in the XML? 

Try this quick and dirty solution, but it works:

<?php
$objImageXml 
= new SimpleXMLElement($objImageXml->asXML());
?>
2010-11-09 04:33:32
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Xpath actually knows which element is root regardless of element on which you execute it. Example:

<?php

$string 
= <<<XML
<a>
 <b>
  <c>text</c>
  <c>stuff</c>
 </b>
 <b>
  <c>code</c>
 </b>
</a>
XML;

header('content-type: text/plain');

$xml = new SimpleXMLElement($string);

//relative to root
$b0=$xml->b[0]->xpath('//c');
while(list( , 
$node) = each($b0)) {
    echo 
'b[0]: //c: ',$node,"\n";
}

$b1=$xml->b[1]->xpath('//c');
while(list( , 
$node) = each($b1)) {
    echo 
'b[1]: //c: ',$node,"\n";
}

echo 
"\n";

//relative to current element
$b0=$xml->b[0]->xpath('.//c');
while(list( , 
$node) = each($b0)) {
    echo 
'b[0]: .//c: ',$node,"\n";
}

$b1=$xml->b[1]->xpath('.//c');
while(list( , 
$node) = each($b1)) {
    echo 
'b[1]: .//c: ',$node,"\n";
}

?>

Will return:
b[0]: //c: text
b[0]: //c: stuff
b[0]: //c: code
b[1]: //c: text
b[1]: //c: stuff
b[1]: //c: code

b[0]: .//c: text
b[0]: .//c: stuff
b[1]: .//c: code
2011-01-12 04:21:58
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
If you want to search multiple values from xml on the behalf or one value then this code can be helpfull to you. 

if there is: 
<Record> 
  <country>Pakistan</country> 
  <code>+92</code> 
  <Value>100<Value> 
</Record> 

then try this one: 
<?php 
$sxe 
simplexml_load_file("countries.XML"); 
foreach(
$sxe->xpath('//RECORD') as $item) { 

   
$v $row->xpath('./country[. ="Pakistan"]'); 
    if(
$v[0]){ 
        print 
$item->country
        print 
$item->code
        print 
$item->value
    } 
   

?>
2014-09-13 16:36:43
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
To run an xpath query on an XML document that has a namespace, the namespace must be registered with SimpleXMLElement::registerXPathNamespace() before running the query. If the XML document namespace does not include a prefix, you must make up an arbitrary one, and then use it in your query.

<?php
$strXml
= <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<mydoc xmlns="http://www.url.com/myns">
    <message>Test message</message>
</mydoc>
XML;

$xmlDoc=new \SimpleXMLElement($strXml);

foreach(
$xmlDoc->getDocNamespaces() as $strPrefix => $strNamespace) {
    if(
strlen($strPrefix)==0) {
       
$strPrefix="a"//Assign an arbitrary namespace prefix.
   
}
   
$xmlDoc->registerXPathNamespace($strPrefix,$strNamespace);
}

print(
$xmlDoc->xpath("//a:message")[0]); //Use the arbitrary namespace prefix in the query.
?>

This will output:

Test message
2014-10-19 22:48:47
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Автор:
As mentioned already xpath will fail is the default namespace 'xmlns' is used like in:

<?php

$xmlstring 
$string = <<<XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <fileVersion appName="xl" />
</workbook>
XML;
?>

xpath cannot search through the xml without explicitly specifying a namespace.
There are 2 options :
1. rename the 'xmlns' into something else to trick xpath into believing that no default namespace is defined.
2. register a string as the default namespace and use that string in all your queries. Unfortunatly, an empty space will not work.
No other option currently exist until XPath2.0 becomes the default library.
2015-01-30 07:30:36
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Автор:
If you want this behavior for an multidimensional array you can use this:

<?php 
function apath(&$a$path$value NULL) {
   
$pathes explode('/',$path);
   
    if(
count($pathes) > 1) {
       
$firstPart array_shift($pathes);
        if(!isset(
$a[$firstPart])) {
           
$a[$firstPart] = array();
        }
        return 
apath($a[$firstPart], implode('/'$pathes), $value);
    } else {
        if(
$value){
           
$a[$path] = $value;
        } else {
            return 
$a[$path];
        }
    }


apath($a'user/name', array('prename' => 'foo''lastname' => 'bar'));

$a = array();
var_dump($a);
var_dump(apath($a'user/name/lastname'));

?>
Gives you this:

array(1) {
  ["user"]=>
  array(1) {
    ["name"]=>
    array(2) {
      ["prename"]=>
      string(5) "foo"
      ["lastname"]=>
      string(8) "bar"
    }
  }
}
string(8) "bar"
2016-10-11 12:11:51
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
I tried to use string functions in the xpath statements I'm passing, like

$oXml->xpath('substring(/foo/bar/text(), 0, 4)');

But no matter which syntax I'm trying I never the string functions to work. 

Is it possible, that the xpath method does not support function calls?
2017-01-31 14:43:31
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html
Автор:
You can also search for siblings with a condition. For example immagine to need the title for a desidered language which with the two siblings tags in this XML file

<?xml version="1.0" encoding="UTF-8"?>
<IDOC BEGIN="1">
...
<PRODUCT SEGMENT="1">
    <PRODUCTCODE>005</PRODUCTCODE>
    <LANG>E</LANG>
    <TITLE>Name</TITLE>
    <LANG_ISO>EN</LANG_ISO>
</PRODUCT>
<PRODUCT SEGMENT="1">
    <PRODUCTCODE>005</PRODUCTCODE>
    <LANG>I</LANG>
    <TITLE>Name I</TITLE>
    <LANG_ISO>IT</LANG_ISO>
</PRODUCT>
... 
</IDOC>

Let's break it down
<?php
"//PRODUCT" // find product tag
"//PRODUCT/LANG[.='E']" // whithin it find lang == "E"
"//PRODUCT/LANG[.='E']/../"  // go up one step
"//PRODUCT/LANG[.='E']/../TITLE" // get the title Tag content

// Combined search and find siblings ----------------------------
$xml simplexml_load_file("fname.xml");

// Search for the TITLE field which sibling is == "E" ----------
$title_E_array $xml->xpath("//PRODUCT/LANG[.='E']/../TITLE"); // By default gives back an array of  SimpleXmlElement 
$title = (string) $xml->xpath("//PRODUCT/LANG[.='E']/../TITLE")[0]; // in this way saves only the value as a string
?>
2022-09-28 12:56:33
http://php5.kiev.ua/manual/ru/simplexmlelement.xpath.html

    Поддержать сайт на родительском проекте КГБ