Парсер DOM, который допускает тег </ in <script> в стиле HTML5
Обновление: html5lib
(нижняя часть вопроса), кажется, близко, мне просто нужно улучшить мое понимание того, как оно используется.
Я пытаюсь найти HTML5-совместимый DOM-парсер для PHP 5.3. В частности, мне нужно получить доступ к следующим HTML-подобным CDATA внутри тега script:
<script type="text/x-jquery-tmpl" id="foo">
<table><tr><td>${name}</td></tr></table>
</script>
Большинство синтаксических анализаторов прекращают анализ преждевременно, потому что HTML 4.01 завершает синтаксический анализ тега сценария, когда находит ETAGO (</
) внутри <script>
тег. Тем не менее, HTML5 позволяет </
до </script>
, Все парсеры, которые я пробовал до сих пор, либо потерпели неудачу, либо они настолько плохо документированы, что я не понял, работают они или нет.
Мои требования:
- Настоящий парсер, а не хак регулярных выражений.
- Возможность загрузки полных страниц или фрагментов HTML.
- Возможность вытащить содержимое скрипта обратно, выбирая по атрибуту 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 (string) 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 ответов
У меня была та же проблема, и, видимо, вы можете взломать свой путь через это, загрузив документ в формате XML, и сохранить его как HTML:)
$d = new DOMDocument;
$d->loadXML('<script id="foo"><td>bar</td></script>');
echo $d->saveHTML();
Но, конечно, разметка должна быть безошибочной, чтобы loadXML работал.
Я просто узнаю (в моем случае).
попробуйте изменить параметр параметров loadHTML
с помощью LIBXML_SCHEMA_CREATE
в DOMDocument
$dom = new DOMDocument;
libxml_use_internal_errors(true);
//$dom->loadHTML($buffer, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$dom->loadHTML($buffer, LIBXML_SCHEMA_CREATE);
FluentDOM использует DOMDocument, но блокирует уведомления о загрузке и предупреждения. У него нет собственного парсера. Вы можете добавить свои собственные загрузчики (например, тот, который использует html5lib).
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.
Я добавил комментарии теги (<!-- ... -->
) в моих шаблонных блоках 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');
});
});
Не идеально, но я не был уверен в лучшем обходном пути.
Я столкнулся с этой точной проблемой.
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);
Я надеюсь, что это поможет некоторым людям:-).