SimpleXMLElement::xpath
(PHP 5 >= 5.2.0)
SimpleXMLElement::xpath — Запускает XPath запрос к XML данным
Описание
public array SimpleXMLElement::xpath
( string
$path
)
Метод xpath ищет узлы SimpleXML с дочерними элементами,
совпадающими с XPath path
.
Список параметров
-
path
-
Путь XPath
Возвращаемые значения
Возвращает массив array объектов SimpleXMLElement или FALSE
в случае ошибки.
Примеры
Пример #1 Xpath
<?php
$string = <<<XML
<a>
<b>
<c>текст</c>
<c>вещь</c>
</b>
<d>
<c>код</c>
</d>
</a>
XML;
$xml = new SimpleXMLElement($string);
/* Поиск <a><b><c> */
$result = $xml->xpath('/a/b/c');
while(list( , $node) = each($result)) {
echo '/a/b/c: ',$node,"\n";
}
/* Относительные пути также работают... */
$result = $xml->xpath('b/c');
while(list( , $node) = each($result)) {
echo 'b/c: ',$node,"\n";
}
?>
Результат выполнения данного примера:
/a/b/c: текст /a/b/c: вещь b/c: текст b/c: вещь
Обратите внимание, что оба результата одинаковы.
Смотрите также
- SimpleXMLElement::registerXPathNamespace() - Создает префикс/пространство имен контекста для следующего XPath запроса
- SimpleXMLElement::getDocNamespaces() - Возвращает объявленное пространство имен в документе
- SimpleXMLElement::getNamespaces() - Получение пространств имен, используемых в документе
- Базовое использование SimpleXML
- Функция SimpleXMLElement::addAttribute() - Добавляет атрибут к SimpleXML-элементу
- Функция SimpleXMLElement::addChild() - Добавляет дочерний элемент к узлу XML
- Функция SimpleXMLElement::asXML() - Возвращает сформированный XML документ в виде строки используя SimpleXML элемент
- Функция SimpleXMLElement::attributes() - Возвращает атрибуты элемента
- Функция SimpleXMLElement::children() - Поиск дочерних элементов данного узла
- Функция SimpleXMLElement::__construct() - Создание нового SimpleXMLElement объекта
- Функция SimpleXMLElement::count() - Считает количество дочерних элементов у текущего элемента
- Функция SimpleXMLElement::getDocNamespaces() - Возвращает объявленное пространство имен в документе
- Функция SimpleXMLElement::getName() - Получение имени XML элемента
- Функция SimpleXMLElement::getNamespaces() - Получение пространств имен, используемых в документе
- Функция SimpleXMLElement::registerXPathNamespace() - Создает префикс/пространство имен контекста для следующего XPath запроса
- Функция SimpleXMLElement::saveXML() - Псевдоним SimpleXMLElement::asXML
- Функция SimpleXMLElement::__toString() - Returns the string content
- Функция SimpleXMLElement::xpath() - Запускает XPath запрос к XML данным
Коментарии
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"/>
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;
}
}
?>
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']"); ?>
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.
)
...
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...
?>
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
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
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.
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?
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
?>