Issues (26)

src/selectors/XPathSelector.php (1 issue)

1
<?php declare(strict_types = 1);
2
namespace Templado\Engine;
3
4
use DOMNode;
5
use DOMNodeList;
6
use DOMXPath;
7
8
class XPathSelector implements Selector {
9
10
    /** @var string */
11
    private $queryString;
12
13
    /** @var array<string, string> */
14
    private $prefixMap = [];
15
16 57
    public function __construct(string $query) {
17 57
        $this->queryString = $query;
18 57
    }
19
20 6
    public function registerPrefix(string $prefix, string $uri): void {
21 6
        $this->prefixMap[$prefix] = $uri;
22 6
    }
23
24 57
    public function select(DOMNode $context): Selection {
25 57
        $backup = $this->toggleErrorHandling(true);
26 57
        $result = $this->getXPath($context)->query(
27 57
            $this->queryString,
28 19
            $context
29
        );
30
31 57
        if (!$result instanceof DOMNodeList) {
0 ignored issues
show
$result is always a sub-type of DOMNodeList.
Loading history...
32 42
            $error = \libxml_get_last_error();
33 42
            $this->toggleErrorHandling($backup);
34
35 42
            throw new XPathSelectorException(
36 42
                \sprintf(
37 42
                    '%s: "%s"',
38 42
                    \trim($error->message),
39 42
                    $this->queryString
40
                ),
41 42
                $error->code
42
            );
43
        }
44 15
        $this->toggleErrorHandling($backup);
45
46 15
        return new Selection($result);
47
    }
48
49 57
    private function getXPath(DOMNode $node): DOMXPath {
50 57
        $xp = new DOMXPath($node->ownerDocument);
51 57
        $xp->registerPhpFunctions();
52
53 57
        if (empty($this->prefixMap) || isset($this->prefixMap['html'])) {
54 51
            $this->prefixMap['html'] = 'http://www.w3.org/1999/xhtml';
55
        }
56
57 57
        foreach ($this->prefixMap as $prefix => $uri) {
58 57
            $xp->registerNamespace($prefix, $uri);
59
        }
60
61 57
        return $xp;
62
    }
63
64 57
    private function toggleErrorHandling(bool $mode): bool {
65 57
        $backup = \libxml_use_internal_errors($mode);
66 57
        \libxml_clear_errors();
67
68 57
        return $backup;
69
    }
70
}
71