Парсер DOM, который допускает тег </ in <script>в стиле HTML5 - PullRequest
47 голосов
/ 27 октября 2010

Обновление : html5lib (нижняя часть вопроса), кажется, близко, мне просто нужно улучшить мое понимание того, как он используется.

Я пытаюсь найти HTML5-совместимый парсер DOM для PHP 5.3.В частности, мне нужно получить доступ к следующим HTML-подобным CDATA внутри тега скрипта:

<script type="text/x-jquery-tmpl" id="foo">
    <table><tr><td>${name}</td></tr></table>
</script>

Большинство синтаксических анализаторов прекращают синтаксический анализ преждевременно, потому что HTML 4.01 завершает синтаксический анализ тега скрипта , когда находит ETAGO(</) внутри тега <script>.Однако HTML5 допускает </ перед </script>.Все парсеры, которые я пробовал до сих пор, либо потерпели неудачу, либо они настолько плохо документированы, что я не понял, работают они или нет.

Мои требования:

  1. Настоящий парсер, а не хакерские выражения.
  2. Возможность загружать полные страницы или фрагменты HTML.
  3. Возможность извлекать скрипт содержимое назад, выбирая по атрибуту id тега.

Ввод:

<script id="foo"><td>bar</td></script>

Пример сбоя вывода (без закрытия </td>):

<script id="foo"><td>bar</script>

Некоторые парсеры и их результаты:


DOMDocument (не удается)

Источник:

<?php

header('Content-type: text/plain');
$d = new DOMDocument;
$d->loadHTML('<script id="foo"><td>bar</td></script>');
echo $d->saveHTML();

Выход:

Warning: DOMDocument::loadHTML(): Unexpected end tag : td in Entity, line: 1 in /home/adam/public_html/2010/10/26/dom.php on line 5
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head><script id="foo"><td>bar</script></head></html>


FluentDOM (не работает)

Источник:

<?php

header('Content-type: text/plain');
require_once 'FluentDOM/src/FluentDOM.php';
$html = "<html><head></head><body><script id='foo'><td></td></script></body></html>";
echo FluentDOM($html, 'text/html');

Выход:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><head></head><body><script id="foo"><td></script></body></html>


phpQuery (не удается)

Источник:

<?php

header('Content-type: text/plain');

require_once 'phpQuery.php';

phpQuery::newDocumentHTML(<<<EOF
<script type="text/x-jquery-tmpl" id="foo">
<td>test</td>
</script>
EOF
);

echo (строка) pq ('# foo');

Вывод:

<script type="text/x-jquery-tmpl" id="foo">
<td>test
</script>


html5lib (проходит)

Возможно многообещающе.Можно ли получить содержимое тега script#foo?

Источник:

<?php

header('Content-type: text/plain');

include 'HTML5/Parser.php';

$html = "<!DOCTYPE html><html><head></head><body><script id='foo'><td></td></script></body></html>";
$d = HTML5_Parser::parse($html);

echo $d->saveHTML();

Вывод:

<html><head></head><body><script id="foo"><td></td></script></body></html>

Ответы [ 5 ]

11 голосов
/ 24 мая 2012

У меня была такая же проблема, и, очевидно, вы можете взломать этот путь, загрузив документ в формате XML и сохранив его как HTML:)

$d = new DOMDocument;
$d->loadXML('<script id="foo"><td>bar</td></script>');
echo $d->saveHTML();

Но, разумеется, для работы loadXML разметка должна быть безошибочной.

5 голосов
/ 04 ноября 2010

FluentDOM использует DOMDocument, но блокирует уведомления о загрузке и предупреждения. У него нет собственного парсера. Вы можете добавить свои собственные загрузчики (например, тот, который использует html5lib).

5 голосов
/ 27 октября 2010

Re: html5lib

Вы нажимаете на вкладку загрузки и загружаете версию парсера для PHP .

Вы распаковываете архив в локальной папке

 tar -zxvf html5lib-php-0.1.tar.gz
 x html5lib-php-0.1/
 x html5lib-php-0.1/VERSION
 x html5lib-php-0.1/docs/
 ... etc

Вы изменяете каталоги и создаете файл с именем hello.php

cd html5lib-php-0.1
touch hello.php 

Вы помещаете следующий код PHP в hello.php

$html = '<html><head></head><body>
<script type="text/x-jquery-tmpl" id="foo">
<table><tr><td>${name}</td></tr></table>
</script> 
</body></html>';
$dom = HTML5_Parser::parse($html); 
var_dump($dom->saveXml()); 
echo "\nDone\n";

Вы запускаетеhello.php из командной строки

php hello.php

Анализатор проанализирует дерево документа и вернет объект DOMDocument, которым можно манипулировать, как любым другим объектом DOMDocument.

4 голосов
/ 25 октября 2011

Я добавил теги комментариев (<!-- ... -->) в свои блоки шаблонов jQuery (блоки CDATA также не работали), и DOMDocument не коснулся внутреннего HTML.

Затем, прежде чем использовать шаблоны jQuery, я написалскрипт для удаления комментариев.

$(function() {
    $('script[type="text/x-jquery-tmpl"]').text(function() {
        // The comment node in this context is actually a text node.
        return $.trim($(this).text()).replace(/^<!--([\s\S]*)-->$/, '$1');
    });
});

Не идеально, но я не был уверен в лучшем обходном пути.

3 голосов
/ 19 сентября 2013

Я столкнулся с этой проблемой.

PHP Dom Document анализирует html внутри тега script, и это может фактически привести к совершенно другому dom.

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

Очевидно, что содержимое скрипта недоступно для вашего объекта dom, потому что оно пустое.

С помощью следующих строк php-кода вы можете «исправить» эту проблему. Имейте в виду, что теги script в тегах scripts могут вызвать ошибку.

$scripts = array();
// this will select all script tags non-greedy. If you have a script tag in your script tag, it will cause problems.
preg_match_all("/((<script.*>)(.*))\/script>/sU", $html, $scripts);
// Make content of scripts empty
$html = str_replace($scripts[3], '', $html);

// Do DOM Document stuff here

// Put script contents back
$html = str_replace($scripts[2], $scripts[1], $html);

Надеюсь, это поможет некоторым людям: -).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...