Очистка устаревшего HTML-кода с помощью DOMXPath (преобразование вложенных тегов <div>в теги <p>) - PullRequest
0 голосов
/ 05 мая 2019

Я пытаюсь прочитать Rich Text, хранящийся в старой базе данных MS Access, в новом веб-приложении PHP.Обеззараженные данные будут отображаться пользователям, использующим CKEditor, который достаточно строг в разборе HTML-кода, соответствующего стандартам.Однако данные, хранящиеся в MS Access, часто плохо отформатированы или используют устаревший код HTML.

Ниже приведен пример фрагмента данных, которые я пытаюсь очистить:

<div align="right">Previous claim $ &nbsp;&nbsp;935.00<div align="right">&nbsp;&nbsp;This claim $1,572.50</div></div>

Эти данныеэто две строки текста, которые выровнены по правому краю, однако MS Access использовал устаревший атрибут align для стилизации тегов <div> вместо атрибута style и неправильноВложите их, когда в этом сценарии они должны быть последовательными.

Чтобы превратить данные этого примера в две строки текста, которые выровнены по правому краю и которые CKEditor будет читать и отображать, как предполагалось (т.е. текст отображается как выровненный по правому краю)Я пытаюсь заменить теги <div> на теги <p> и добавить атрибут встроенного стиля с выравниванием текста вправо, чтобы заменить устаревший атрибут выравнивания.

Я использую PHP DOMXPath для очисткиданные со следующим кодом:

$dom = new DOMDocument();
$dom->loadHTML($dataForCleaning, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

$xpath = new DOMXPath($dom);

foreach ($xpath->query('//div[@align]') as $node) {
    $alignment = $node->getAttribute('align');

    $newNode = $dom->createElement('p');
    $newNode->setAttribute("style", "text-align:".$alignment);
    $node->parentNode->insertBefore($newNode, $node);

    foreach ($node->childNodes as $child) {
        $newNode->appendChild($child);
    }

    $node->parentNode->removeChild($node);
}

Я использую insertBefore вместо appendChild, пытаясь сохранить последовательность элементов одинаковой,но именно это и вызывает проблемы в этом примере вложенных данных.

Для не вложенных тегов <div> в качестве входных данных, подлежащих очистке, исправленный выходной html является правильным.Однако в этом вложенном примере <div> выходные данные заканчиваются следующим образом:

<p style="text-align:right">Previous claim $ &nbsp;&nbsp;935.00</p>

Обратите внимание, что вторая строка текста ( Это утверждение ... ) была удалена, так какэто было внутри вложенного <div> как потомка к родителю <div>

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

Заранее благодарен за любую помощь и руководство.-Марк

1 Ответ

0 голосов
/ 05 мая 2019

Есть пара вещей, которые я изменил. Во-первых, вместо того, чтобы просто добавить существующий узел, я получаю его для клонирования узла и добавления копии (в $newNode->appendChild($child->cloneNode(true));), а во-вторых, когда вы перемещаете вложенный узел, я думаю, что XPath больше не указывает на этот перемещенный узел. Поэтому вместо этого я проверяю при копировании дочерних узлов, есть ли у вас такой же шаблон узла <div align="right">, и если да, я создаю новый узел в новом формате и добавляю его вместо этого ...

foreach ($xpath->query('//div[@align]') as $node) {
    $alignment = $node->getAttribute('align');

    $newNode = $dom->createElement('p');
    $newNode->setAttribute("style", "text-align:".$alignment);

    $node->parentNode->insertBefore($newNode, $node);
    foreach ($node->childNodes as $child) {
        if ( $child instanceof DOMElement && $child->localName == "div"
                && $child->attributes->getNamedItem("align")->nodeValue == "right" )    {
            $subNode = $dom->createElement('p', $child->nodeValue );
            $subNode->setAttribute("style", "text-align:".$alignment);
            $newNode->appendChild($subNode);
        }
        else    {
            $newNode->appendChild($child->cloneNode(true));
        }
    }

    $node->parentNode->removeChild($node);
}

который для образца, который вы дадите, выведет ...

<p style="text-align:right">
    Previous claim $ &nbsp;&nbsp;935.00
    <p style="text-align:right">&nbsp;&nbsp;This claim $1,572.50</p>
</p>
...