Преобразуйте Javascript XPath в действительный PHP-запрос() XPath|нормализуйте JS XPath -->PHP
Это допустимый XPath в Javascript:
id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]
И это превратилось в действительный PHP XPath, который будет использоваться с DOMXPath->query()
//*[@id="priceInfo"]//div[@class="standardProdPricingGroup"]//span[1]
- знаете ли вы какие-либо библиотеки или пользовательские компоненты, которые уже выполняют это преобразование?
- знаете ли вы доступную документацию, в которой перечислены два синтаксических различия?
Моя главная проблема заключается в том, что может быть много различий, и я пытаюсь определить эти различия, и у меня есть проблемы с определением эти.
Вопрос можно было бы поставить и по-другому: Поскольку Javascript может иметь разные допустимые форматы XPath, как их нормализовать для работы с PHP.
В одном из обновлений также упоминается, что функция id() является допустимой XPath, если существует допустимый DTD, содержащий это определение. У меня нет власти над входным DTD, и если есть способ найти решение, которое работает без какого-либо конкретного DTD, это было бы потрясающе.
Обновление:
Я хотите преобразовать первый формат во второй с помощью алгоритма. Мой вклад - это первый, а не второй. Я не могу это изменить.
Как указал @Nison Maël, 2-й формат является допустимым Javascript XPath, как представлено здесь: http://jsbin.com/elatum/2/edit к сожалению, это только усугубляет проблему "фрагментации" Javascript XPath.
@salathe указал, что действительный запрос Javascript XPath отлично работает в PHP, если задокументированный ввод имеет действительный DTD (@Dimitre Новатчев упомянул об этом в комментарии, но упустил из виду важность). К сожалению, у меня нет контроля над входным DTD, поэтому теперь мне нужно найти способ преодолеть это или найти решение, которое работает даже без действительного DTD.
3 answers
Просто видя, что Салате на самом деле ответила так же, но принимая во внимание ваш комментарий и подчеркивая это немного больше:
Вам не нужно указывать какой-либо DTD. Пока вы используете функции DOMDocument::loadHTML
или DOMDocument::loadHTMLFile
, атрибут HTML id
фактически зарегистрирован для функции xpath id()
. С демонстрационным HTML-кодом, приведенным в http://jsbin.com/elatum/2/edit , вы даже получаете ошибку при загрузке документа:
Предупреждение: DOMDocument::loadhtmlfile():ИДЕНТИФИКАТОР Цена уже определена в...
Что уже является признаком того, что это истинный атрибут идентификатора, потому что он жалуется на дубликаты. Связанный пример кода выглядит следующим образом:
$xpath = 'id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]';
$doc = new DOMDocument();
$doc->loadHTMLFile(__DIR__ . '/../data/file-11796340.html');
$xp = new DOMXPath($doc);
$r = $xp->query($xpath);
echo $xpath, "\n";
echo $r ? $r->length : 0, ' elements found', "\n";
if (!$r) return;
foreach($r as $node) {
echo " - ", $node->nodeValue, "\n";
}
Вывод:
id("priceInfo")/div[@class="standardProdPricingGroup"]/span[1]
1 elements found
- hello
В случае, если вам нужно больше контроля, сначала запустите xpath, чтобы пометить все атрибуты HTML id
как идентификатор для xpath:
$r = $xp->query("//*[@id]");
if ($r) foreach($r as $node) {
$node->setIdAttribute('id', true);
}
Затем вы можете использовать тот же xpath с функцией id()
, ее не нужно менять.
Не можете ли вы просто перевести id("...")
в //*[@id="..."][1]
в начале вашего выражения?
Например, если можно предположить, что у вас не будет скобок в выражениях id(...)
:
$queryRewritten = preg_replace('/^id\(([^\)]+)\)/','//*[@id=$1][1]',$query);
ИЗМЕНИТЬ: исправлена замена, идентификатор() должен быть первым в выражении
Это не полный ответ, но он слишком велик, чтобы помещать его в качестве комментария, и это может вам немного помочь.
Если у вас есть контроль над входным XML, то вместо того, чтобы использовать DTD для объявления атрибутов id
, вы можете объявить их явно в самом XML-документе, добавив к атрибутам id
префикс xml:
.
Например, если у вас был XML
<foo id="x27"/>
И изменил его на
<foo xml:id="x27"/>
Тогда функция id() распознала бы этот атрибут как формальный тип XML id
, а не просто как атрибут с именем id
.
Я знаю, что этот "трюк" работает на процессоре Saxon, но должен признать, что я не пробовал его с PHP.