Проблема с верхним ответом заключается в том, что LIBXML_HTML_NOIMPLIED
является нестабильным .
. Он может переупорядочивать элементы (в частности, перемещая закрывающий тег верхнего элемента в конец документа),добавить случайные p
теги и, возможно, множество других вопросов [1] .Он может удалить теги html
и body
для вас, но за счет нестабильного поведения.На производстве это красный флаг.Короче говоря:
Не используйте LIBXML_HTML_NOIMPLIED
. Вместо этого используйте substr
.
Подумайте об этом.Длины <html><body>
и </body></html>
фиксированы и находятся на обоих концах документа - их размеры никогда не меняются и не меняют своих положений.Это позволяет нам использовать substr
, чтобы вырезать их:
$dom = new domDocument;
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);
echo substr($dom->saveHTML(), 12, -15); // the star of this operation
( ЭТО НЕ ФИНАЛЬНОЕ РЕШЕНИЕ ОДНАКО! Полный ответ см. Ниже , продолжайте читать для контекста)
Мы отсекаем 12
от начала документа, потому что <html><body>
= 12 символов (<<>>+html+body
= 4 + 4 + 4), и мы идем назад и срезаем 15 с конца, потому что \n</body></html>
= 15 символов (\n+//+<<>>+body+html
= 1 + 2 + 4 + 4 + 4)
Обратите внимание, что я все еще использую LIBXML_HTML_NODEFDTD
, исключая !DOCTYPE
из числа включенных.Во-первых, это упрощает удаление substr
тегов HTML / BODY.Во-вторых, мы не удаляем тип документа с помощью substr
, потому что мы не знаем, будет ли 'default doctype
' всегда иметь фиксированную длину.Но, самое главное, LIBXML_HTML_NODEFDTD
останавливает синтаксический анализатор DOM от применения к документу не-HTML5-документа, что по крайней мере не позволяет парсеру обрабатывать элементы, которые он не распознает как свободный текст.
Мы знаем, чтоДело в том, что теги HTML / BODY имеют фиксированную длину и позиции, и мы знаем, что такие константы, как LIBXML_HTML_NODEFDTD
, никогда не удаляются без какого-либо уведомления об устаревании, поэтому приведенный выше метод должен хорошо перейти в будущее НО ...
... единственное предостережение в том, что реализация DOM может изменить способ размещения тегов HTML / BODY в документе - например, удалениесимвол новой строки в конце документа, добавление пробелов между тегами или добавление символов новой строки.
Это можно исправить, выполнив поиск позиций открывающих и закрывающих тегов для body
и используя эти смещения какдля наших длин, чтобы урезать.Мы используем strpos
и strrpos
, чтобы найти смещения спереди и сзади соответственно:
$dom = new domDocument;
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);
$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
// PositionOf<body> + 6 = Cutoff offset after '<body>'
// 6 = Length of '<body>'
$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());
// ^ PositionOf</body> - LengthOfDocument = Relative-negative cutoff offset before '</body>'
echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);
В закрытии, повторение окончательного, будущего ответа :
$dom = new domDocument;
$dom->loadHTML($html, LIBXML_HTML_NODEFDTD);
$trim_off_front = strpos($dom->saveHTML(),'<body>') + 6;
$trim_off_end = (strrpos($dom->saveHTML(),'</body>')) - strlen($dom->saveHTML());
echo substr($dom->saveHTML(), $trim_off_front, $trim_off_end);
Нет doctype, нет html-тега, нет тега body.Мы можем только надеяться, что парсер DOM скоро получит новый слой краски, и мы сможем более прямо устранить эти нежелательные теги.