§ Код класса
1<?php
2
3libxml_use_internal_errors(true);
4
5class xpath
6{
7 protected DOMDocument $dom;
8 protected DOMXPath $xpath;
9
10
14 public function __construct(string $content)
15 {
16 $this->dom = new DOMDocument();
17
18 if ($content == '') {
19 throw new Exception("Content for empty string");
20 }
21
22 $this->dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'));
23 $this->dom->normalizeDocument();
24 $this->xpath = new DOMXPath($this->dom);
25
26 libxml_clear_errors();
27 return $this;
28 }
29
30
41 public function query($query, $what = null, mixed $where = -1)
42 {
43 $rows = [];
44 $result = $this->xpath->query($query);
45
46
47 if ($error = libxml_get_last_error()) {
48 throw new Exception("XQuery [" . trim($error->message) . "] for: $query");
49 }
50
51
52 if (is_integer($what)) {
53 [$where, $what] = [$what, null];
54 }
55
56
57 if ($result->length === 0) {
58 libxml_clear_errors();
59 return [];
60 }
61
62 foreach ($result as $n => $item)
63 {
64 $row = [
65 '@' => $item,
66 '$' => $item->nodeValue,
67 '#' => '',
68 ];
69
70 $dom = new DOMDocument();
71
72
73 if (is_object($item->attributes)) {
74 foreach ((object)$item->attributes as $ds) {
75 $row[$ds->nodeName] = $ds->nodeValue;
76 }
77 }
78
79
80 try {
81
82 $dom->appendChild($dom->importNode($item, true));
83 $row['#'] = preg_replace('~(^<[^>]*>|</[^>]*>$)~', '', trim(html_entity_decode($dom->saveHTML())));
84
85 } catch (Exception) {
86 $row['#'] = '';
87 }
88
89 unset($dom);
90
91
92 if ($what !== null) {
93 $row = $row[$what] ?? null;
94 }
95
96
97 if ($where === $n) {
98 $rows = $row;
99 break;
100 } else {
101 $rows[] = $row;
102 }
103 }
104
105 libxml_clear_errors();
106 return $rows;
107 }
108}