XPathQuery Class
XPathQuery extracts data from XML documents using XPath expressions. It has methods for a value, for a list of values, for a structure and for the DOM nodes, parameters that are quoted for you, context nodes and support for namespaces.
Basic Usage
use Derafu\Xml\XPathQuery;
// Initialize with an XML string, an XmlDocument or a DOMDocument.
$query = new XPathQuery($xmlString);
// Get a single value.
$value = $query->getValue('/root/element');
// Get multiple values.
$values = $query->getValues('/root/items/item');
// Get DOM nodes.
$nodes = $query->getNodes('/root/items/item');
// Get structured data.
$data = $query->get('/root');
An XML string that is not well formed throws an XmlParseException when the query is created. A query that fails throws an XmlQueryException (see Exceptions).
What Each Method Returns
| Method | Returns |
|---|---|
getValue($query) |
The value of the first node, as a string, or null if there is none. |
getValues($query) |
A list with the value of each node. A node without value is null. |
getNodes($query) |
A DOMNodeList with the nodes. |
get($query) |
The structure of what the query finds, as the next section says. |
The Structure That get() Returns
nullif no node is found.- A string if a node that has only text is found (an element without content is an empty string; an attribute is its value).
- An array if the node has child elements: the value of each child by its name, and a list for the elements that are repeated.
- A list of those, if several nodes are found.
It is the simple structure of the document: the attributes, the namespaces and the comments are not in it. For all of the XML use the decoder (see Array Structure).
For this XML:
<root>
<person>
<name>John</name>
<age>30</age>
</person>
<person>
<name>Jane</name>
<age>25</age>
</person>
</root>
The query $query->get('/root/person') returns:
[
['name' => 'John', 'age' => '30'],
['name' => 'Jane', 'age' => '25'],
]
And $query->get('/root/person[1]/name') returns 'John'.
Parameterized Queries
The values that go in a query are given as parameters: in the query the parameter is written :name, and in the array of parameters it is name. They are quoted for you, also when they have quotes:
$result = $query->get('//item[@id=:id and @type=:type]', [
'id' => '123',
'type' => 'product',
]);
$params = ['complex' => 'Value with "double" and \'single\' quotes'];
$result = $query->get('//element[text()=:complex]', $params);
Context Nodes
get(), getValue(), getValues() and getNodes() take a context node as the last parameter, to query from it:
// Get a context node.
$contextNode = $query->getNodes('//section')->item(0);
// Query within that context.
$result = $query->get('./item', [], $contextNode);
Working with Namespaces
By default the namespaces are ignored: the names in the query match the elements by their local name, whatever their namespace and prefix.
$xml = '<r xmlns="urn:d" xmlns:p="urn:p"><p:a>1</p:a><b>2</b></r>';
$query = new XPathQuery($xml);
$query->get('//a'); // "1": the element p:a, found by its name.
$query->get('//b'); // "2"
With the namespaces of the query as the second parameter they are used as the XPath says: the names have the prefix of the namespace that they are in.
$namespaces = ['d' => 'urn:d', 'p' => 'urn:p'];
$query = new XPathQuery($xml, $namespaces);
$query->get('//p:a'); // "1"
$query->get('//d:b'); // "2"
$query->get('//b'); // null: b is in the namespace urn:d, it is not a name without namespace.
The prefixes are the ones that you give, not the ones that the document uses: they can be different. It is the way to query a document whose prefixes you do not control.
Without registering the namespaces a name with a prefix (//p:a) is not valid.
Querying an XmlDocument
An XmlDocument can be given instead of a string. Also the one that the encoder gives:
$document = $encoder->encode($data);
$query = new XPathQuery($document, ['cbc' => 'urn:example:basic']);
$query->get('//cbc:ID');
XmlDocument::query() and getNodes() use XPathQuery without namespaces.
Error Handling
use Derafu\Xml\Exception\XmlQueryException;
try {
$result = $query->get('//invalid[xpath');
} catch (XmlQueryException $e) {
echo $e->getMessage();
// An error occurred while executing the XPath expression: ... Invalid predicate.
}