PHP XPath and XSLT

PHP XPath and XSLT with libxslt

DOMXPath evaluates XPath 1.0 through libxml2 3,427 , and the xsl extension wraps libxslt 3,427 , an XSLT 1.0 processor, so the browser stylesheet of XSLTProcessor in the Browser runs unchanged on the server:

transform.php: XPath queries and an XSLT 1.0 transformationPHP
<?php
$doc = new DOMDocument();
$doc->load('booknest-catalog.xml');
$xpath = new DOMXPath($doc);                       // XPath 1.0, through libxml2
printf("%d in stock, prices total %s\n",
    $xpath->evaluate('count(//book[supply/availability = "in-stock"])'),
    $xpath->evaluate('sum(//price)'));
foreach ($xpath->query('//book[pages > 400]/title') as $title) {
    echo $title->textContent, PHP_EOL;
}
$style = new DOMDocument();
$style->load('shelf1.xsl');                        // the XSLT 1.0 stylesheet of Section 2.24.1
$xslt = new XSLTProcessor();                       // ext/xsl, built on libxslt
$xslt->importStylesheet($style);
$xslt->setParameter('', 'min', '30');
echo $xslt->transformToXml($doc);
Output
5 in stock, prices total 134.74
Patterns of the Deep Web
<?xml version="1.0"?>
<ul><li><b>Patterns of the Deep Web</b> $39.50</li></ul>

For XSLT 3.0 and XPath 3.1 in PHP, SaxonC (Saxonica's C/PHP edition) provides a PHP extension, or call Saxon 726,956 or BaseX 693,830 as a service. That is the server-side home for the stylesheets that browsers are about to stop running.


PHP Validation

DOMDocument supports two schema languages for validating a loaded document: XSD, via schemaValidate() (file) and schemaValidateSource() (string), and RelaxNG, via relaxNGValidate() (file) and relaxNGValidateSource() (string). RelaxNG Compact is not supported – only RelaxNG's XML syntax.

The example below loads zoo.xml and validates it against a RelaxNG schema (zoo.rng) and an XSD schema (zoo.xsd). Both calls emit PHP warnings instead of returning a clean boolean result, because the loaded document does not match either schema as given here – illustrating the diagnostics PHP produces on a validation mismatch rather than a silent pass/fail. For working zoo.xml/schema pairs, see the XSD and Relax NG reference pages.
ch08-validate.phpPHP
<!DOCTYPE html>
<html><head></head><body><?php

$doc = new DOMDocument();
$doc->load('zoo.xml');
$doc->relaxNGValidate('zoo.rng');
$doc->schemaValidate('zoo.xsd');

?></body></html>
Output
Warning: DOMDocument::relaxNGValidate(): Expecting no namespace for element zoo in C:\Program Files\Zend\Apache2\htdocs\xml\zoo.php on line 5

Warning: DOMDocument::schemaValidate(): Element '{http://www.w3.org/2001/XMLSchema}complexType': The content is not valid. Expected is (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))). in C:\Program Files\Zend\Apache2\htdocs\xml\zoo.php on line 6

Warning: DOMDocument::schemaValidate(): Invalid Schema in C:\Program Files\Zend\Apache2\htdocs\xml\zoo.php on line 6

PHP XPath

Query a loaded DOMDocument with its companion class, DOMXPath. evaluate() returns a native PHP value (number, string, or boolean) when the XPath expression's result is not a node-set, and a DOMNodeList otherwise. query() always returns a DOMNodeList, even for an expression such as count(...) that yields a number – converting that DOMNodeList to a string (for example via echo) raises a fatal error.

DOMXPath

readonly DOMDocument $document;
__construct(DOMDocument $doc)
mixed evaluate 331 (string $expression [, DOMNode $contextnode [, bool $registerNodeNS = true]])
DOMNodeList query 331 (string $expression [, DOMNode $contextnode [, bool $registerNodeNS = true]])
bool registerNamespace 331 (string $prefix, string $namespaceURI)
void registerPhpFunctions 331 ([mixed $restrict])
ch08-xpath-people.xml, ch08-xpath-count.phpXML
merged-02-01-ch08-xpath-people.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!-- people.xml -->
<people>
   <person id="p3">
      <name>Eric Lee</name>
      <gender>m</gender>
      <age>35</age>
   </person>
   <person id="p4">
      <name>Serena</name>
      <gender>f</gender>
      <age>25</age>
   </person>
</people>
<!DOCTYPE html>
<html><head></head><body><?php

$doc = new DOMDocument();
$doc->load('people.xml');
$xpath = new DOMXPath($doc);
$query = 'count(/people/person/name)';
echo $xpath->evaluate($query);  //2
echo $xpath->query($query); // error

?></body></html>
Output
2
Catchable fatal error: Object of class DOMNodeList could not be converted to string in C:\Program Files\Zend\Apache2\htdocs\xml\people2.php on line 9

PHP XSLT

Apply an XSLT stylesheet to a loaded document with XSLTProcessor. Load the stylesheet into a DOMDocument and pass it to importStylesheet(), then transform the source document with transformToXML() (returns the result as a string), transformToDoc() (returns a DOMDocument), or transformToURI() (writes the result directly to a file or URI).

XSLTProcessor

string getParameter 331 (string $namespaceURI, string $localName)
int XsltProcessor::getSecurityPrefs 331 (void)
bool hasExsltSupport 331 (void)
void importStylesheet 331 (object $stylesheet)
void registerPHPFunctions 331 ([mixed $restrict])
bool removeParameter 331 (string $namespaceURI, string $localName)
bool setParameter 331 (string $namespace, string $name, string $value)
bool setProfiling 331 (string $filename)
int XsltProcessor::setSecurityPrefs 331 (int $securityPrefs)
DOMDocument transformToDoc 331 (DOMNode $doc)
int transformToURI 331 (DOMDocument $doc, string $uri)
string transformToXML 331 (DOMDocument $doc)

For the source XML document and XSLT stylesheet used below, see Basic Flow Control (there named a.xml and a.xslt; the same content is loaded here as ab.xml/ab.xslt). transformToXML() returns the transformation result as a string, which prints correctly; transformToDoc() returns a DOMDocument object, which cannot be implicitly converted to a string by echo.
ch08-xslt-transform.phpPHP
<?php
$xml = new DOMDocument;
$xml->load('ab.xml');
$xslt = new DOMDocument;
$xslt->load('ab.xslt');
$proc = new XSLTProcessor;
$proc->importStyleSheet($xslt);
echo $proc->transformToXML($xml); // string printed
echo $proc->transformToDoc($xml); // error
?>
Output
A B C
3 Dog
4 Fish

Catchable fatal error: Object of class DOMDocument could not be converted to string in C:\Program Files\Zend\Apache2\htdocs\xml\ab.php on line 9