Я - функция ниже, я пытаюсь вывести DOMDocument без добавления XML, HTML, body и p оболочек тегов перед выводом содержимого. Предлагаемое исправление:
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
Работает только тогда, когда в содержимом нет элементов уровня блока. Однако когда это происходит, как в примере ниже с элементом h1, результирующий вывод saveXML усекается до ...
<p> Если хотите </p>
Мне указали на этот пост в качестве возможного обходного пути, но я не могу понять, как реализовать его в этом решении (см. Закомментированные попытки ниже).
Какие-либо предложения?
function rseo_decorate_keyword($postarray) {
global $post;
$keyword = "Jasmine Tea"
$content = "If you like <h1>jasmine tea</h1> you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea."
$d = new DOMDocument();
@$d->loadHTML($content);
$x = new DOMXpath($d);
$count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])");
if ($count > 0) return $postarray;
$nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h1) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]");
if ($nodes && $nodes->length) {
$node = $nodes->item(0);
// Split just before the keyword
$keynode = $node->splitText(strpos($node->textContent, $keyword));
// Split after the keyword
$node->nextSibling->splitText(strlen($keyword));
// Replace keyword with <b>keyword</b>
$replacement = $d->createElement('strong', $keynode->textContent);
$keynode->parentNode->replaceChild($replacement, $keynode);
}
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
// $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1));
// $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes);
return $postarray;
}
источник
DOMDocument
которая также влияет на код в этом ответе. AfaikDOMDocument
всегда интерпретирует входные данные как latin-1, если во входных данных не указана другая кодировка . Другими словами:<meta charset="…">
кажется, что тег нужен для входных данных, отличных от latin-1. В противном случае вывод будет прерван, например, для многобайтовых символов UTF-8.Просто удалите узлы сразу после загрузки документа с помощью loadHTML ():
источник
<!DOCTYPE
работает. Вторая строка разрывается, если<body>
имеется более одной дочерней заметки.Используйте
saveXML()
вместо этого и передайте ему documentElement в качестве аргумента.http://php.net/domdocument.savexml
источник
saveHTML
а также ( пример )loadHTML
libxml использует модуль парсера HTML, который вставляет недостающий скелет HTML. Следовательно,$dom->documentElement
будет корневым элементом HTML. Я исправил ваш пример кода. Теперь он должен сделать то, о чем просит Скотт.Проблема с верхним ответом в том, что
LIBXML_HTML_NOIMPLIED
он нестабилен .Он может переупорядочивать элементы (в частности, перемещая закрывающий тег верхнего элемента в нижнюю часть документа), добавлять случайные
p
теги и, возможно, решать множество других проблем [1] . Это может удалитьhtml
иbody
тег для вас, но за счет неустойчивого поведения. В производстве это красный флаг. Коротко:Не используйте
LIBXML_HTML_NOIMPLIED
. Вместо этого используйтеsubstr
.Подумай об этом. Длины
<html><body>
и</body></html>
фиксированы на обоих концах документа - их размеры никогда не меняются, как и их положение. Это позволяет нам использоватьsubstr
для их удаления:( ОДНАКО ЭТО НЕ ОКОНЧАТЕЛЬНОЕ РЕШЕНИЕ! Полный ответ см. Ниже. , продолжайте читать, чтобы контекст)
Мы отрезаем
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. Во-вторых, мы не удаляем doctype с помощью,substr
потому что мы не знаемdefault doctype
, всегда ли ' ' будет иметь фиксированную длину. Но, что наиболее важно,LIBXML_HTML_NODEFDTD
синтаксический анализатор DOM не может применить к документу тип документа, отличный от HTML5, что, по крайней мере, не позволяет синтаксическому анализатору обрабатывать элементы, которые он не распознает как свободный текст.Мы точно знаем, что теги HTML / BODY имеют фиксированную длину и положение, и мы знаем, что такие константы, как
LIBXML_HTML_NODEFDTD
никогда не удаляются без какого-либо уведомления об устаревании, поэтому вышеупомянутый метод должен развернуться в будущем, НО ...... единственное предостережение заключается в том, что реализация DOM может изменить способ размещения тегов HTML / BODY в документе - например, удаление новой строки в конце документа, добавление пробелов между тегами или добавление новой строки.
Это можно исправить, выполнив поиск позиций открывающего и закрывающего тегов
body
и используя эти смещения для обрезки нашей длины. Мы используемstrpos
и,strrpos
чтобы найти смещения спереди и сзади соответственно:В заключение повторю окончательный ответ, рассчитанный на будущее :
Нет doctype, нет тега html, нет тега body. Мы можем только надеяться, что парсер DOM скоро получит новый слой краски, и мы сможем более непосредственно устранить эти нежелательные теги.
источник
$html = $dom -> saveHTML();
вместо$dom -> saveHTML();
повторно?Изящный трюк - использовать
loadXML
а затемsaveHTML
.html
Иbody
теги вставляются наload
стадии, а не наsave
сцене.NB, что это немного взломано, и вы должны использовать ответ Ионы, если вы можете заставить его работать.
источник
использовать DOMDocumentFragment
источник
Сейчас 2017 год, и на этот вопрос 2011 года мне не нравится ни один из ответов. Много регулярных выражений, большие классы, loadXML и т. Д.
Простое решение, решающее известные проблемы:
Легко, просто, надежно, быстро. Этот код будет работать с тегами HTML и кодировкой, например:
Если кто-нибудь найдет ошибку, скажите, я сам этим воспользуюсь.
Изменить , другие допустимые параметры, которые работают без ошибок (очень похожие на уже указанные):
Вы можете добавить тело самостоятельно, чтобы предотвратить появление каких-либо посторонних предметов на меху.
Третий вариант:
источник
mb_convert_encoding
и вместо этого добавляя<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>
и изменяяsubstr
соответственно. Кстати, твое здесь самое элегантное решение. Upvoted.Я немного опоздал в клуб, но не хотел не делиться методом, о котором узнал. Прежде всего, у меня есть подходящие версии для loadHTML (), чтобы принимать эти прекрасные параметры, но
LIBXML_HTML_NOIMPLIED
они не работали в моей системе. Также пользователи сообщают о проблемах с парсером (например здесь и здесь ).Решение, которое я создал, на самом деле довольно простое.
HTML для загрузки помещается в
<div>
элемент, поэтому у него есть контейнер, содержащий все загружаемые узлы.Затем этот элемент контейнера удаляется из документа (но его DOMElement все еще существует).
Затем удаляются все прямые дочерние элементы документа. Это включает в себя любой добавлено
<html>
,<head>
и<body>
тегах (эффективноLIBXML_HTML_NOIMPLIED
опция), а также<!DOCTYPE html ... loose.dtd">
декларация (эффективноLIBXML_HTML_NODEFDTD
).Затем все прямые дочерние элементы контейнера снова добавляются в документ и его можно выводить.
XPath работает как обычно, просто позаботьтесь о том, чтобы теперь было несколько элементов документа, а не один корневой узел:
источник
Ни одно из других решений на момент написания этой статьи (июнь 2012 г.) не смогло полностью удовлетворить мои потребности, поэтому я написал решение, которое обрабатывает следующие случаи:
<doctype>
,<xml>
,<html>
,<body>
, и<p>
теги)<p>
покое.Итак, вот решение, которое устраняет эти проблемы:
Я также написал несколько тестов, которые будут жить в том же классе:
Вы можете сами проверить, работает ли это.
DomDocumentWorkaround::testAll()
возвращает это:источник
Хорошо, я нашел более элегантное решение, но это просто утомительно:
Хорошо, надеюсь, это ничего не упускает и кому-то помогает?
источник
Используйте эту функцию
источник
preg_replace
потому что использование основанных на DOMDocument методов удаления тегов html и body не сохраняло кодировку UTF-8 :(Если решение flags, на которое ответил Алессандро Вендрусколо , не работает, вы можете попробовать следующее:
$bodyTag
будет содержать ваш полный обработанный HTML-код без всех этих HTML-оберток, за исключением<body>
тега, который является корнем вашего контента. Затем вы можете использовать регулярное выражение или функцию обрезки, чтобы удалить его из конечной строки (послеsaveHTML
) или, как в случае выше, перебрать все его дочерние элементы, сохраняя их содержимое во временную переменную$finalHtml
и возвращая его (что я считаю безопаснее).источник
Я наткнулся на эту тему, чтобы найти способ удалить оболочку HTML. С помощью
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
отлично работает, но у меня проблема с utf-8. После долгих усилий я нашел решение. Я публикую это ниже, потому что у кого-то такая же проблема.Проблема возникла из-за
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Эта проблема:
Решение 1:
Решение 2:
источник
Я борюсь с этим на RHEL7 с PHP 5.6.25 и LibXML 2.9. (Я знаю старые вещи 2018 года, но это Red Hat для вас.)
Я обнаружил, что решение, предложенное Алессандро Вендрусколо, за которое было много голосов, нарушает HTML, переставляя теги. То есть:
будет выглядеть так:
Это касается обоих вариантов, которые он предлагает вам использовать:
LIBXML_HTML_NOIMPLIED
иLIBXML_HTML_NODEFDTD
.Решение, предложенное Алексом, идет наполовину, но оно не работает, если у
<body>
него более одного дочернего узла.Для меня работает следующее решение:
Во-первых, чтобы загрузить DOMDocument, я использую:
Чтобы сохранить документ после массажа DOMDocument, я использую:
Я первый согласен с тем, что это не очень элегантное решение, но оно работает.
источник
Добавление
<meta>
тега вызовет исправление поведенияDOMDocument
. Хорошо то, что вам вообще не нужно добавлять этот тег. Если вы не хотите использовать кодировку по вашему выбору, просто передайте ее как аргумент конструктора.http://php.net/manual/en/domdocument.construct.php
Вывод
Спасибо @Bart
источник
У меня тоже было это требование, и мне понравилось решение, опубликованное Алексом выше. Однако есть пара проблем: если
<body>
элемент содержит более одного дочернего элемента, итоговый документ будет содержать только первый дочерний элемент<body>
, а не все из них. Кроме того, мне нужна была зачистка, чтобы обрабатывать вещи условно - только когда у вас есть документ с заголовками HTML. Я уточнил это следующим образом. Вместо удаления<body>
я преобразовал его в a<div>
и удалил объявление XML и<html>
.источник
Как и другие участники, я сначала упивался простотой и потрясающей силой ответа @Alessandro Vendruscolo. Возможность просто передать некоторые помеченные константы конструктору казалась слишком хорошей, чтобы быть правдой. Для меня это было. У меня есть правильные версии как LibXML, так и PHP, однако независимо от того, что он все равно добавит тег HTML в структуру узлов объекта Document.
Мое решение сработало лучше, чем использование ...
Флаги или ....
Удаление узла, которое становится беспорядочным без структурированного порядка в DOM. Опять же, фрагменты кода не могут предопределить структуру DOM.
Я начал это путешествие, желая найти простой способ выполнить обход DOM, как это делает JQuery, или, по крайней мере, каким-то образом, чтобы иметь структурированный набор данных либо односвязным, либо двусвязным, либо обходом узлов дерева. Мне было все равно, как долго я могу анализировать строку так, как это делает HTML, а также обладать удивительной мощью свойств класса сущности узла, чтобы использовать на этом пути.
До сих пор объект DOMDocument оставил мне желание ... Как и многие другие программисты, кажется ... Я знаю, что видел много разочарований в этом вопросе, так как я НАКОНЕЦ ... (после примерно 30 часов попыток и неудач) Типовое тестирование) Я нашел способ получить все это. Я надеюсь, что это поможет кому-то...
Во-первых, я цинично отношусь ко ВСЕМ ... лол ...
Я бы потратил целую жизнь, прежде чем согласился бы с кем-либо, что сторонний класс в любом случае нужен в этом случае использования. Я очень был и НЕ являюсь поклонником использования какой-либо сторонней структуры классов, однако я наткнулся на отличный парсер. (примерно 30 раз в Google, прежде чем я сдался, так что не чувствуйте себя одиноким, если вы избегали этого, потому что это выглядело хромым или неофициальным в любом случае ...)
Если вы используете фрагменты кода и нуждаетесь в чистом коде, который никак не влияет на анализатор, без использования дополнительных тегов, используйте simplePHPParser .
Это потрясающе и очень похоже на JQuery. Меня это не часто впечатляет, но этот класс использует множество хороших инструментов, и у меня пока не было ошибок парсинга. Я большой поклонник того, что умеет делать этот класс.
Вы можете найти его файлы для загрузки здесь , инструкции по запуску здесь и его API здесь . Я настоятельно рекомендую использовать этот класс с его простыми методами, которые могут делать
.find(".className")
то же самое, что и метод поиска JQuery, или даже знакомые методы, такие какgetElementByTagName()
илиgetElementById()
...Когда вы сохраняете дерево узлов в этом классе, оно вообще ничего не добавляет. Вы можете просто сказать,
$doc->save();
и он выводит все дерево в строку без каких-либо проблем.Теперь я буду использовать этот синтаксический анализатор для всех проектов без ограничения полосы пропускания в будущем.
источник
У меня PHP 5.3, и ответы здесь мне не помогли.
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
заменил весь документ только первым дочерним элементом, у меня было много абзацев, и только первый сохранялся, но решение дало мне хорошую отправную точку, чтобы написать что-то безregex
комментариев, и я почти уверен, что это можно улучшить, но если у кого-то такая же проблема, как у меня, это может быть хорошей отправной точкой.Тогда мы могли бы использовать это так:
Обратите внимание, что
appendChild
принимает,DOMNode
поэтому нам не нужно создавать новые элементы, мы можем просто повторно использовать существующие, которые реализуют,DOMNode
например,DOMElement
это может быть важно для сохранения кода «в здравом уме» при манипулировании несколькими документами HTML / XML.источник
LIBXML_HTML_NOIMPLIED
поскольку делает это только частично. Удаление doctype эффективноLIBXML_HTML_NODEFDTD
.У меня с
DOMDocument
классом 3 проблемы .1- Этот класс загружает html с кодировкой ISO, а символы utf-8 не отображаются на выходе.
2 Даже если мы дадим
LIBXML_HTML_NOIMPLIED
флаг методу loadHtml, пока наш вход HTML не содержит корневой тег, он не будет правильно синтаксического анализа.3- Этот класс считает теги HTML5 недопустимыми.
Поэтому я переопределил этот класс для решения этих проблем и изменил некоторые методы.
Теперь я использую
DOMEditor
вместо,DOMDocument
и до сих пор у меня это хорошо работалоисточник
Я тоже столкнулся с этой проблемой.
К сожалению, я не чувствовал себя комфортно, используя какое-либо из решений, представленных в этой ветке, поэтому я пошел проверить то, которое меня удовлетворит.
Вот что я придумал, и он работает без проблем:
По сути, он работает аналогично большинству представленных здесь решений, но вместо ручного труда он использует селектор xpath для выбора всех элементов в теле и объединяет их HTML-код.
источник
descendant-or-self::body/p/*
.мой сервер получил php 5.3 и не может обновиться, поэтому эти параметры
не для меня.
Чтобы решить эту проблему, я говорю функции SaveXML напечатать элемент Body, а затем просто заменить «body» на «div».
вот мой код, надеюсь, он кому-то поможет:
utf-8 предназначен для поддержки иврита.
источник
Ответ Alex правильный, но может вызвать следующую ошибку на пустых узлах:
А вот и мой маленький мод:
Добавление trim () также является хорошей идеей для удаления пробелов.
источник
Возможно, я опоздал. Но, возможно, у кого-то (вроде меня) все еще есть эта проблема.
Итак, у меня ничего из вышеперечисленного не помогло. Потому что $ dom-> loadHTML также закрывает открытые теги, а не только добавляет теги html и body.
Поэтому добавление элемента <div> у меня не работает, потому что у меня иногда бывает 3-4 незакрытых div в html-фрагменте.
Мое решение:
1.) Добавьте маркер для вырезания, затем загрузите фрагмент HTML.
2.) делайте с документом все, что хотите
3.) сохраните html
4.) прежде чем вернуть его, удалите теги <p> </ p> с маркера, как ни странно, он появляется только на [MARK], но не на [/ MARK] ...!?
5.) удалить все до и после маркера
6.) вернуть
Было бы намного проще, если бы LIBXML_HTML_NOIMPLIED работал у меня. Можно, но это не так. PHP 5.4.17, libxml версии 2.7.8.
Я нахожу действительно странным, я использую парсер HTML DOM, а затем, чтобы исправить эту "штуку", мне нужно использовать регулярное выражение ... Все дело в том, чтобы не использовать регулярное выражение;)
источник
< div >< div > ... < /div >
. Я все еще ищу решения.Для всех, кто использует Drupal, есть встроенная функция для этого:
https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x
Код для справки:
источник
Вы можете использовать tidy с show-body-only:
Но помните: tidy удалите некоторые теги, такие как значки Font Awesome: проблемы с отступом HTML (5) с помощью PHP
источник
источник
Эта библиотека упрощает просмотр / изменение DOM, а также заботится об удалении для вас оберток doctype / html:
https://github.com/sunra/php-simple-html-dom-parser
источник