Як отримати внутрішнійHTML DOMNode?


96

Яку функцію ви використовуєте для отримання innerHTML заданого DOMNode у реалізації PHP DOM? Хтось може дати надійне рішення?

Звичайно, це зробить і зовнішній HTML.

Відповіді:


152

Порівняйте цей оновлений варіант із PHP User Note # 89718 :

<?php 
function DOMinnerHTML(DOMNode $element) 
{ 
    $innerHTML = ""; 
    $children  = $element->childNodes;

    foreach ($children as $child) 
    { 
        $innerHTML .= $element->ownerDocument->saveHTML($child);
    }

    return $innerHTML; 
} 
?> 

Приклад:

<?php 
$dom= new DOMDocument(); 
$dom->preserveWhiteSpace = false;
$dom->formatOutput       = true;
$dom->load($html_string); 

$domTables = $dom->getElementsByTagName("table"); 

// Iterate over DOMNodeList (Implements Traversable)
foreach ($domTables as $table) 
{ 
    echo DOMinnerHTML($table); 
} 
?> 

Дякую. Це чудово працює. Не повинен $ dom-> зберегтиWhiteSpace = false; бути до завантаження документа?
Dawid Ohia

@ JohnM2: Так, слід .
hakre

Додаткові примітки: З PHP 5.3.6 ви можете пощадити тимчасове DOMDocument. Крім того, один може знадобитися замінити trimз ltrim(або навіть видалити його повністю) , щоб зберегти біт пробільні як розриви рядків.
hakre

Таку функцію слід додати до класу DomDocument.
Nate

3
Мені довелося змінити декларацію функції, щоб очікувати DOMElementзамість a, DOMNodeоскільки я передавав повернення з DOMDocument::getElementById(). Про всяк випадок, коли це когось іншого спіткає.
miken32

25

Ось версія у функціональному стилі програмування :

function innerHTML($node) {
    return implode(array_map([$node->ownerDocument,"saveHTML"], 
                             iterator_to_array($node->childNodes)));
}

13

Щоб повернути htmlелемент, ви можете використовувати C14N () :

$dom = new DOMDocument();
$dom->loadHtml($html);
$x = new DOMXpath($dom);
foreach($x->query('//table') as $table){
    echo $table->C14N();
}

2
C14N спробує перетворити HTML у дійсний XML. Наприклад, <br> стане <br> </br>
ajaybc

Це брудний спосіб скинути HTML-елемент елемента, не використовуючи saveHTML, який виводить теги html, head і body.
CONvid19,

9

Спрощена версія відповіді Хаїма Евгі:

<?php

function innerHTML(\DOMElement $element)
{
    $doc = $element->ownerDocument;

    $html = '';

    foreach ($element->childNodes as $node) {
        $html .= $doc->saveHTML($node);
    }

    return $html;
}

Приклад використання:

<?php

$doc = new \DOMDocument();
$doc->loadHTML("<body><div id='foo'><p>This is <b>an <i>example</i></b> paragraph<br>\n\ncontaining newlines.</p><p>This is another paragraph.</p></div></body>");

print innerHTML($doc->getElementById('foo'));

/*
<p>This is <b>an <i>example</i></b> paragraph<br>

containing newlines.</p>
<p>This is another paragraph.</p>
*/

Немає необхідності встановлювати preserveWhiteSpaceабо formatOutput.


4

На додаток до приємної версії trincot з array_mapі, implodeале цього разу з array_reduce:

return array_reduce(
   iterator_to_array($node->childNodes),
   function ($carry, \DOMNode $child) {
        return $carry.$child->ownerDocument->saveHTML($child);
   }
);

Досі не розумію, чому не існує reduce()методу, який приймає масиви та ітератори однаково.


3
function setnodevalue($doc, $node, $newvalue){
  while($node->childNodes->length> 0){
    $node->removeChild($node->firstChild);
  }
  $fragment= $doc->createDocumentFragment();
  $fragment->preserveWhiteSpace= false;
  if(!empty($newvalue)){
    $fragment->appendXML(trim($newvalue));
    $nod= $doc->importNode($fragment, true);
    $node->appendChild($nod);
  }
}

2

Ось ще один підхід, заснований на цьому коментарі Друпелли на php.net, який добре працював для мого проекту. Він визначає innerHTML(), створюючи новий DOMDocument, імпортуючи та додаючи до нього цільовий вузол, замість явної ітерації над дочірніми вузлами.

InnerHTML

Давайте визначимо цю допоміжну функцію:

function innerHTML( \DOMNode $n, $include_target_tag = true ) {
  $doc = new \DOMDocument();
  $doc->appendChild( $doc->importNode( $n, true ) );
  $html = trim( $doc->saveHTML() );
  if ( $include_target_tag ) {
      return $html;
  }
  return preg_replace( '@^<' . $n->nodeName .'[^>]*>|</'. $n->nodeName .'>$@', '', $html );
}

де ми можемо включити / виключити зовнішній цільовий тег через другий вхідний аргумент.

Приклад використання

Тут ми витягуємо внутрішній HTML для цільового тегу, заданого атрибутом "first" id:

$html = '<div id="first"><h1>Hello</h1></div><div id="second"><p>World!</p></div>';
$doc  = new \DOMDocument();
$doc->loadHTML( $html );
$node = $doc->getElementById( 'first' );

if ( $node instanceof \DOMNode ) {

    echo innerHTML( $node, true );
    // Output: <div id="first"><h1>Hello</h1></div>    

    echo innerHTML( $node, false );
    // Output: <h1>Hello</h1>
}

Живий приклад:

http://sandbox.onlinephpfunctions.com/code/2714ea116aad9957c3c437d46134a1688e9133b8


1

Старий запит, але для цього є вбудований метод. Просто передайте цільовий вузол DomDocument->saveHtml().

Повний приклад:

$html = '<div><p>ciao questa è una <b>prova</b>.</p></div>';
$dom = new DomDocument($html);
@$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$node = $xpath->query('.//div/*'); // with * you get inner html without surrounding div tag; without * you get inner html with surrounding div tag
$innerHtml = $dom->saveHtml($node);
var_dump($innerHtml);

Вихід: <p>ciao questa è una <b>prova</b>.</p>


Попередження: DOMDocument :: saveHTML () очікує, що параметром 1 буде DOMNode, задано об’єкт
Іван Гусєв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.