Как избежать автоматического закрытия открытых элементов HTML с помощью DOMDocument :: saveHTML - PullRequest
2 голосов
/ 25 сентября 2019

Я хочу добавить пользовательские атрибуты данных в контейнеры div и ul, если этот контейнер использует определенный класс.Я начинаю с фрагментов HTML, которые содержат либо действительный HTML (полный div с его содержимым и закрывающим </div>), либо просто открывающий div (без его содержимого и закрывающего </div>).

Вот пример содержимого, с которого я могу начать:

<div id='gallery-7222-1' class='gallery galleryid-7222 gallery-columns-3 gallery-size-thumbnail'>

Вот что я пробовал до сих пор:

// grab all containers from the HTML.
$dom_doc = new DOMDocument();

/*
 * $html here can be the example I posted above.
 * LIBXML_HTML_NOIMPLIED and LIBXML_HTML_NODEFDTD are used
 * to avoid adding a doctype and wrapping the whole output in HTML tags.
 */
$dom_doc->loadHTML( $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD );

// Let's look for lists and divs.
$ul_tags  = $dom_doc->getElementsByTagName( 'ul' );
$div_tags = $dom_doc->getElementsByTagName( 'div' );

/*
 * Loop through each ul, and add the data.
 * I do more things in there, like checking for what class the ul has,
 * but I've simplified things here. 
 */
foreach ( $ul_tags as $ul_tag ) {
    $ul_tag->setAttribute( 'data-foo', 'bar' );
}

/*
 * Loop through each div, and add the data.
 * I do more things in there, like checking for what class the div has,
 * but I've simplified things here. 
 */
foreach ( $div_tags as $div_tag ) {
    $div_tag->setAttribute( 'data-foo', 'bar' );    
}

// Save our updated HTML.
$html = $dom_doc->saveHTML();

Возвращенный HTML-код включает в себя новый атрибут данных, нотакже заключительный </div>, который я действительно не хочу здесь.Вы можете увидеть это здесь: https://ideone.com/sVfAOn

Сначала я подумал о том, чтобы просто удалить закрывающую </div> с помощью substr, но я не могу этого сделать: - В некоторых случаях мой исходный HTML действительно включаетзакрывающий тег div, который я хочу сохранить.- Иногда я могу редактировать строку, которая вместо этого включает ul.

Как бы я мог помешать saveHTML() быть таким умным здесь и попытаться исправить мой HTML для меня?

Спасибо!

1 Ответ

0 голосов
/ 27 сентября 2019

Нет, вы не можете убедить анализатор HTML не анализировать HTML.Лучшим решением было бы переосмыслить ваш подход к тому, как вы получаете данные в первую очередь, и убедиться, что вы не получаете фрагменты.

Если это не удастся, вы можете сначала попытаться обработать его как XML, чтобы убедиться, что он ломается.:

<?php
libxml_use_internal_errors(true);
$dom_doc = new DOMDocument();
$remove = "";
// try loading it as xml
if (!$dom_doc->loadXml($html)) {
    // it failed, get the error message
    $err = libxml_get_last_error()->message ?? "";
    // is it because of an unclosed element?
    // find out which element it's breaking on
    if (preg_match("/end of data in tag (.*?) /", $err, $matches)) {
        $remove = "</$matches[1]>";
    }
}
$dom_doc->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

// do stuff

$html = str_replace($remove, "", $dom_doc->saveHTML());

Конечно, это предполагает, что вы имеете дело с HTML, который в противном случае является чистым и не вызовет кучу других ошибок.Если бы это было так, вам нужно было бы проверить libxml_get_errors() на наличие ошибки незамкнутого элемента.

...