У меня есть PHP-код, который удаляет все узлы, у которых есть хотя бы один атрибут. Вот мой код:

<?php

$data = <<<DATA
<div>
    <p>These line shall stay</p>
    <p class="myclass">Remove this one</p>
    <p>But keep this</p>
    <div style="color: red">and this</div>
</div>
DATA;

$dom = new DOMDOcument();
$dom->loadHTML($data, LIBXML_HTML_NOIMPLIED);
$dom->removeChild($dom->doctype);

$xpath = new DOMXPath($dom);

$lines_to_be_removed = $xpath->query("//*[count(@*)>0]");

foreach ($lines_to_be_removed as $line) {
    $line->parentNode->removeChild($line);
}

// just to check
echo $dom->saveHTML();
?>

Как вы видите на скрипке, это текущий вывод кода выше:

<div>
    <p>These line shall stay</p>

    <p>But keep this</p>

</div>

Пока это желаемый результат:

<div>
    <p>These line shall stay</p>
    Remove this one
    <p>But keep this</p>
    and this
</div>

Как я могу это сделать?

4
Martin AJ 5 Сен 2016 в 02:37

2 ответа

Это приведет к удалению всех тегов с атрибутами class и style , так что это не доказательство:

<?php

$data = <<<DATA
<div>
    <p>These line shall stay</p>
    <p class="myclass">Remove this one</p>
    <p>But keep this</p>
    <div style="color: red">and this</div>
</div>
DATA;

$dom = new DOMDOcument();
$dom->loadHTML($data, LIBXML_HTML_NOIMPLIED);
$dom->removeChild($dom->doctype);

$xpath = new DOMXPath($dom);

$lines_to_be_removed = $xpath->query("//*[count(@class)>0 or count(@style)>0]");

foreach ($lines_to_be_removed as $line) {
    $line->parentNode->removeChild($line);
}

// just to check
echo $dom->saveHTML();
?>

Обратите внимание на эту строку:

 $lines_to_be_removed = $xpath->query("//*[count(@class)>0] or count(@style)>0]");
1
dede 5 Сен 2016 в 00:48

Вы можете использовать replaceChild() с текстовым содержимым этого узла:

foreach ($lines_to_be_removed as $line) {
  $line->parentNode->replaceChild($dom->createTextNode($line->textContent),$line);
}

// <div>
//   <p>These line shall stay</p>
//   Remove this one
//   <p>But keep this</p>
//   and this
// </div>

Однако это может оказаться проблематичным с вашей нотацией // вашего селектора xpath и рекурсии.


Использование более ручного подхода для копирования дочернего содержимого целевых узлов в родительские узлы.

$data = '
<div>
  <div>1A</div>
  <div class="foo">1B
    <div>2C</div>
    <div class="foo">2D</div>
    <div>2E</div>
    <div class="foo">2F
      <div>3G</div>
      <div class="foo">3H</div>
    </div>
  </div>
</div>';

$dom = new DOMDOcument();
$dom->loadHTML($data, LIBXML_HTML_NOIMPLIED);
$dom->removeChild($dom->doctype);

SomeFunctionName( $dom->documentElement );

$html = $dom->saveHTML();

function SomeFunctionName( $parent )
{
  $nodesToDelete = array();
  if( $parent->hasChildNodes() )
  {
    foreach( $parent->childNodes as $node )
    {
      SomeFunctionName( $node );
      if( $node->hasAttributes() and count( $node->attributes ) > 0 )
      {
        foreach( $node->childNodes as $childNode )
        {
          $node->parentNode->insertBefore( clone $childNode, $node );
        }
        $nodesToDelete[] = $node;
      }
    }
  }
  foreach( $nodesToDelete as $delete)
  {
    $delete->parentNode->removeChild( $delete );
  }
}

// <div>
//   <div>1A</div>
//   1B
//     <div>2C</div>
//     2D
//     <div>2E</div>
//     2F
//       <div>3G</div>
//       3H
//       <div>3I</div>
//       3J
// </div>

Если вы хотите вложить дочерние элементы в новый контейнер «div», замените этот фрагмент кода

    foreach( $parent->childNodes as $node )
    {
      SomeFunctionName( $node );
      if( $node->hasAttributes() and count( $node->attributes ) > 0 )
      {
        $newNode = $node->ownerDocument->createElement('div');
        foreach( $node->childNodes as $childNode )
        {
          $newNode->appendChild( clone $childNode );
        }
        $node->parentNode->insertBefore( $newNode, $node );
        $nodesToDelete[] = $node;
      }
    }

// <div>
//   <div>1A</div>
//   <div>1B
//     <div>2C</div>
//     <div>2D</div>
//     <div>2E</div>
//     <div>2F
//       <div>3G</div>
//       <div>3H</div>
//       <div>3I</div>
//       <div>3J</div>
//     </div>
//   </div>
// </div>
2
Scuzzy 5 Сен 2016 в 00:48