22:53
Класс для работы с XPath — Лисья нора
§ Код класса
<?php libxml_use_internal_errors(true); class xpath { protected DOMDocument $dom; protected DOMXPath $xpath; /** * @param string $content * @throws Exception */ public function __construct(string $content) { $this->dom = new DOMDocument(); if ($content == '') { throw new Exception("Content for empty string"); } $this->dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8')); $this->xpath = new DOMXPath($this->dom); $this->dom->normalizeDocument(); libxml_clear_errors(); return $this; } /** * @desc What -- что именно искать, Where - порядковый номер или false, если надо все * # -- HTML-код * $ -- TEXT * @ -- Нода * @param $query * @param null $what * @param int|null $where * @return array|mixed|string|void|null * @throws Exception */ public function query($query, $what = null, mixed $where = -1) { $rows = []; $result = $this->xpath->query($query); // Была ошибка при запросе if ($error = libxml_get_last_error()) { throw new Exception("XQuery [" . trim($error->message) . "] for: $query"); } // Запрос на все поля N-го результата if (is_integer($what)) { [$where, $what] = [$what, null]; } // Нет результатов if ($result->length === 0) { libxml_clear_errors(); return []; } foreach ($result as $n => $item) { $row = [ '@' => $item, '$' => $item->nodeValue, '#' => '', ]; $dom = new DOMDocument(); // Сканировать атрибуты if (is_object($item->attributes)) { foreach ((object)$item->attributes as $ds) { $row[$ds->nodeName] = $ds->nodeValue; } } // HTML-код try { $dom->appendChild($dom->importNode($item, true)); $row['#'] = preg_replace('~(^<[^>]*>|</[^>]*>$)~', '', trim(html_entity_decode($dom->saveHTML()))); } catch (Exception) { $row['#'] = ''; } unset($dom); // Выборка определенного сообщения if ($what !== null) { $row = $row[$what] ?? null; } // Был достигнут определенный номер if ($where === $n) { $rows = $row; break; } else { $rows[] = $row; } } libxml_clear_errors(); return $rows; } }