Wie bekomme ich innerHTML von DOMNode?

95

Welche Funktion verwenden Sie, um innerHTML eines bestimmten DOMNode in der PHP-DOM-Implementierung abzurufen? Kann jemand eine zuverlässige Lösung geben?

Natürlich reicht OuterHTML auch.

Dawid Ohia
quelle

Antworten:

151

Vergleichen Sie diese aktualisierte Variante mit dem PHP Manual User Note # 89718 :

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

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

    return $innerHTML; 
} 
?> 

Beispiel:

<?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); 
} 
?> 
Haim Evgi
quelle
Vielen Dank. Es funktioniert gut. Sollte nicht $ dom-> bewahrenWhiteSpace = false; vor dem Laden des Dokuments sein?
Dawid Ohia
@ JohnM2: Ja sollte es .
hakre
Zusätzliche Hinweise: Seit PHP 5.3.6 können Sie die temporäre ersparen DOMDocument. Möglicherweise möchten Sie auch das trimdurch ein ersetzen ltrim(oder es sogar vollständig entfernen), um ein wenig Leerzeichen wie Zeilenumbrüche zu erhalten.
hakre
Eine solche Funktion sollte der DomDocument-Klasse hinzugefügt werden.
Nate
3
Ich musste die Funktionsdeklaration ändern, um a DOMElementanstelle von a zu erwarten, DOMNodeda ich die Rückgabe von übergeben habe DOMDocument::getElementById(). Nur für den Fall, dass es jemand anderen auslöst.
miken32
25

Hier ist eine Version in einem funktionalen Programmierstil :

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

Um das htmleines Elements zurückzugeben, können Sie C14N () verwenden :

$dom = new DOMDocument();
$dom->loadHtml($html);
$x = new DOMXpath($dom);
foreach($x->query('//table') as $table){
    echo $table->C14N();
}
CONvid19
quelle
2
C14N versucht, den HTML-Code in ein gültiges XML zu konvertieren. Zum Beispiel wird <br> <br> <
br
Es ist eine schmutzige Methode, den HTML-Code des Elements zu sichern, ohne saveHTML verwenden zu müssen, das HTML-, Kopf- und Body-Tags ausgibt.
CONvid19
9

Eine vereinfachte Version von Haim Evgis Antwort:

<?php

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

    $html = '';

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

    return $html;
}

Anwendungsbeispiel:

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

Es besteht keine Notwendigkeit zu setzen preserveWhiteSpaceoder formatOutput.

Alf Eaton
quelle
4

Zusätzlich zu Trincots netter Version mit array_mapund implodediesmal aber mit array_reduce:

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

Ich verstehe immer noch nicht, warum es keine reduce()Methode gibt, die Arrays und Iteratoren gleichermaßen akzeptiert.

Grippe
quelle
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);
  }
}
Chris
quelle
2

Hier ist ein weiterer Ansatz, der auf diesem Kommentar von Drupella auf php.net basiert und für mein Projekt gut funktioniert hat. Es definiert das, innerHTML()indem ein neuer DOMDocumentZielknoten erstellt, importiert und an diesen angehängt wird, anstatt explizit über untergeordnete Knoten zu iterieren.

InnerHTML

Definieren wir diese Hilfsfunktion:

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

Hier können wir das äußere Ziel-Tag über das zweite Eingabeargument ein- / ausschließen.

Anwendungsbeispiel

Hier extrahieren wir den inneren HTML-Code für ein Ziel-Tag, das durch das "erste" ID-Attribut angegeben wird:

$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>
}

Live-Beispiel:

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

Birgire
quelle
1

Alte Abfrage, aber es gibt eine eingebaute Methode, um das zu tun. Übergeben Sie einfach den Zielknoten an DomDocument->saveHtml().

Vollständiges Beispiel:

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

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

Marco Marsala
quelle
Warnung: DOMDocument :: saveHTML () erwartet, dass Parameter 1 DOMNode ist, Objekt angegeben
Ivan Gusev