Преобразуйте 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]
  1. знаете ли вы какие-либо библиотеки или пользовательские компоненты, которые уже выполняют это преобразование?
  2. знаете ли вы доступную документацию, в которой перечислены два синтаксических различия?

Моя главная проблема заключается в том, что может быть много различий, и я пытаюсь определить эти различия, и у меня есть проблемы с определением эти.

Вопрос можно было бы поставить и по-другому: Поскольку 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.

Author: Kev, 2012-08-03

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(), ее не нужно менять.

 7
Author: hakre, 2012-08-05 19:19:31

Не можете ли вы просто перевести id("...") в //*[@id="..."][1] в начале вашего выражения?

Например, если можно предположить, что у вас не будет скобок в выражениях id(...):

$queryRewritten =   preg_replace('/^id\(([^\)]+)\)/','//*[@id=$1][1]',$query);

Пример кода

ИЗМЕНИТЬ: исправлена замена, идентификатор() должен быть первым в выражении

 0
Author: Julien Ch., 2012-08-07 17:20:57

Это не полный ответ, но он слишком велик, чтобы помещать его в качестве комментария, и это может вам немного помочь.

Если у вас есть контроль над входным XML, то вместо того, чтобы использовать DTD для объявления атрибутов id, вы можете объявить их явно в самом XML-документе, добавив к атрибутам id префикс xml:.

Например, если у вас был XML

<foo id="x27"/>

И изменил его на

<foo xml:id="x27"/>

Тогда функция id() распознала бы этот атрибут как формальный тип XML id, а не просто как атрибут с именем id.

Я знаю, что этот "трюк" работает на процессоре Saxon, но должен признать, что я не пробовал его с PHP.

W3C xml: идентификатор

 0
Author: Nigel Alderton, 2012-08-08 23:59:17