Jak zdobyć innerHTML z DOMNode?


96

Jakiej funkcji używasz do uzyskania innerHTML danego DOMNode w implementacji PHP DOM? Czy ktoś może podać niezawodne rozwiązanie?

Oczywiście zewnętrznyHTML też się nada.

Odpowiedzi:


152

Porównaj ten zaktualizowany wariant z uwagą użytkownika instrukcji obsługi PHP nr 89718 :

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

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

    return $innerHTML; 
} 
?> 

Przykład:

<?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); 
} 
?> 

Dzięki. To działa dobrze. Nie powinno $ dom-> preserveWhiteSpace = false; być przed załadowaniem dokumentu?
Dawid Ohia

@ JohnM2: Tak, powinno .
hakre

Dodatkowe uwagi: Od PHP 5.3.6 możesz oszczędzić tymczasowe DOMDocument. Również może chcieć zastąpić trimze związkiem ltrim(lub nawet usunąć go całkowicie), aby zachować trochę białe znaki jak łamanie wierszy.
hakre

Taka funkcja powinna zostać dodana do klasy DomDocument.
Nate

3
Musiałem zmienić deklarację funkcji, aby oczekiwać a DOMElementzamiast a, DOMNodeponieważ przekazywałem zwrot z DOMDocument::getElementById(). Na wypadek, gdyby ktoś podniósł się o coś.
miken32

25

Oto wersja w funkcjonalnym stylu programowania :

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

13

Aby zwrócić htmlelement, możesz użyć C14N () :

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

2
C14N podejmie próbę konwersji kodu HTML na prawidłowy XML. Na przykład <br> zmieni się na <br> </br>
ajaybc

Jest to brudny sposób na zrzucenie kodu HTML elementu bez konieczności używania metody saveHTML, która wyświetli tagi html, head i body.
CONvid19

9

Uproszczona wersja odpowiedzi Haima Evgi:

<?php

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

    $html = '';

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

    return $html;
}

Przykładowe użycie:

<?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>
*/

Nie ma potrzeby ustawiania preserveWhiteSpaceani formatOutput.


4

Oprócz ładnej wersji Trincota z array_mapi, implodeale tym razem z array_reduce:

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

Nadal nie rozumiem, dlaczego nie ma reduce()metody, która akceptuje zarówno tablice, jak i iteratory.


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

Oto inne podejście oparte na komentarzu Drupelli na php.net, które dobrze się sprawdziło w moim projekcie. Definiuje on innerHTML(), tworząc nowy DOMDocument, importując i dołączając do niego węzeł docelowy, zamiast jawnie iterować po węzłach potomnych.

InnerHTML

Zdefiniujmy tę funkcję pomocniczą:

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 );
}

gdzie możemy dołączyć / wykluczyć zewnętrzny znacznik docelowy poprzez drugi argument wejściowy.

Przykład użycia

Tutaj wyodrębniamy wewnętrzny kod HTML dla znacznika docelowego podanego przez „pierwszy” atrybut 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>
}

Przykład na żywo:

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


1

Stara kwerenda, ale jest do tego wbudowana metoda. Po prostu przekaż węzeł docelowy do DomDocument->saveHtml().

Pełny przykład:

$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);

Wynik: <p>ciao questa è una <b>prova</b>.</p>


Ostrzeżenie: DOMDocument :: saveHTML () oczekuje, że parametr 1 będzie DOMNode, obiekt podany
Ivan Gusev
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.