Замените span в PHP, но держите содержимое внутри - PullRequest
0 голосов
/ 15 февраля 2020

У меня есть следующая строка:

<span style="font-size: 13px;">
   <span style="">
      <span style="">
         <span style="font-family: Roboto, sans-serif;">
            <span style="">
               Some text content
            </span>
         </span>
      </span>
   </span>
</span>

, и я хочу изменить эту строку следующим образом, используя PHP:

<span style="font-size: 13px;">
   <span style="font-family: Roboto, sans-serif;">
      Some text content
   </span>
</span>

Я не имею ни малейшего представления, как сделайте это, потому что когда я пытаюсь использовать str_replace для замены <span style="">, я не знаю, как заменить </span> и сохранить содержимое внутри. Моя следующая проблема в том, что я точно не знаю, сколько <span style=""> у меня в строке. У меня также есть не только 1 из этих блоков в моей строке.

Заранее спасибо за вашу помощь, и, возможно, извините за мой глупый вопрос - я все еще учусь.

Ответы [ 2 ]

0 голосов
/ 15 февраля 2020

Для более общего способа изменения документа HTML взгляните на XSLT (преобразования языка расширяемой таблицы стилей). PHP имеет библиотеку XSLT.

Затем у вас есть документ XML с вашими правилами преобразования:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="html" indent="yes"/>

    <!-- remove spans with empty styles -->
    <xsl:template match="*[@style and string-length(./@style) = 0]">
        <xsl:apply-templates />
    </xsl:template>

    <!-- catch all to copy any elements that aren't matched in other templates -->
    <xsl:template match="*">
        <xsl:copy select=".">
            <!-- copy the attributes of the element -->
            <xsl:copy-of select="@*" />
            <!-- continue applying templates to this element's children -->
            <xsl:apply-templates select="*" />
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Затем ваши PHP:

$sourceHtml = new DOMDocument();
$sourceHtml->load('source.html');

$xsl = new DOMDocument();
$xsl->load('transform.xsl');

$xsltProcessor = new XSLTProcessor;
$xsltProcessor->importStyleSheet($xsl); // attach the xsl rules

echo $xsltProcessor->transformToXML($sourceHtml);

$transformedHtml = $xsltProcessor->transformToDoc($sourceHtml);
$transformedHtml->saveHTMLFile('transformed.html');

XSLT сверхмощен для такого рода вещей, и вы можете устанавливать всевозможные правила для отношений между родителями и братьями и сестрами и соответственно изменять атрибуты и контент.

0 голосов
/ 15 февраля 2020

Это легко сделать с помощью правильного парсера HTML. PHP имеет DOMDocument, который может анализировать X / HTML в объектную модель документа , которой затем можно манипулировать, как вы хотите.

Хитрость Решение этой проблемы заключается в возможности рекурсивного обхода дерева DOM, поиска каждого узла и замены тех, которые вам не нужны. Для этого я написал короткий вспомогательный метод, расширив DOMDocument здесь ...

$html = <<<'HTML'
<span style="font-size: 13px;">
   <span style="">
      <span style="">
         <span style="font-family: Roboto, sans-serif;">
            <span style="">
               Some text content
            </span>
         </span>
      </span>
   </span>
</span>
HTML;

class MyDOMDocument extends DOMDocument {
    public function walk(DOMNode $node, $skipParent = false) {
        if (!$skipParent) {
            yield $node;
        }
        if ($node->hasChildNodes()) {
            foreach ($node->childNodes as $n) {
                yield from $this->walk($n);
            }
        }
    }
}

libxml_use_internal_errors(true);

$dom = new MyDOMDocument;
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

$keep = $remove = [];

foreach ($dom->walk($dom->childNodes->item(0)) as $node) {
    if ($node->nodeName !== "span") { // we only care about span nodes
        continue;
    }
    // we'll get rid of all span nodes that don't have the style attribute
    if (!$node->hasAttribute("style") || !strlen($node->getAttribute("style"))) {
        $remove[] = $node;
        foreach($node->childNodes as $child) {
            $keep[] = [$child, $node];
        }
    }
}

// you have to modify them one by one in reverse order to keep the inner nodes
foreach($keep as [$a, $b]) {
    $b->parentNode->insertBefore($a, $b);
}
foreach($remove as $a) {
    if ($a->parentNode) {
        $a->parentNode->removeChild($a);
    }
}

// Now we should have a rebuilt DOM tree with what we expect:
echo $dom->saveHTML();

Вывод:

<span style="font-size: 13px;">


         <span style="font-family: Roboto, sans-serif;">

               Some text content

         </span>


</span>
...