web-dev-qa-db-fra.com

Comment insérer du HTML dans PHP DOMNode?

Est-il possible d'insérer un modèle HTML dans un DOMNode existant sans que le contenu soit codé?

J'ai essayé de faire ça avec:

$dom->createElement('div', '<h1>Hello world</h1>');
$dom->createTextNode('<h1>Hello world</h1>');

La sortie est à peu près la même, avec la seule différence que le premier code l'envelopperait dans un div. J'ai essayé de charger HTML à partir d'une chaîne, mais je ne sais pas comment ajouter du contenu de corps à un autre DOMDocument.

En javascript, ce processus semble être assez simple et évident.

27
Nazariy

Cela fonctionne avec un autre DOMDocument pour analyser le code HTML. Mais vous devez importer les nœuds dans le document principal avant de pouvoir les utiliser:

$newDiv = $dom->createElement('div');
$tmpDoc = new DOMDocument();
$tmpDoc->loadHTML($str);
foreach ($tmpDoc->getElementsByTagName('body')->item(0)->childNodes as $node) {
    $node = $dom->importNode($node, true);
    $newDiv->appendChild($node);
}

Et comme fonction pratique:

function appendHTML(DOMNode $parent, $source) {
    $tmpDoc = new DOMDocument();
    $tmpDoc->loadHTML($source);
    foreach ($tmpDoc->getElementsByTagName('body')->item(0)->childNodes as $node) {
        $node = $parent->ownerDocument->importNode($node, true);
        $parent->appendChild($node);
    }
}

Ensuite, vous pouvez simplement faire ceci:

$elem = $dom->createElement('div');
appendHTML($elem, '<h1>Hello world</h1>');
25
Gumbo

Vous pouvez utiliser

Exemple:

// just some setup
$dom = new DOMDocument;
$dom->loadXml('<html><body/></html>');
$body = $dom->documentElement->firstChild;

// this is the part you are looking for    
$template = $dom->createDocumentFragment();
$template->appendXML('<h1>This is <em>my</em> template</h1>');
$body->appendChild($template);

// output
echo $dom->saveXml();

Sortie:

<?xml version="1.0"?>
<html><body><h1>This is <em>my</em> template</h1></body></html>

Si vous souhaitez importer depuis un autre DOMDocument, remplacez les trois lignes par

$tpl = new DOMDocument;
$tpl->loadXml('<h1>This is <em>my</em> template</h1>');
$body->appendChild($dom->importNode($tpl->documentElement, TRUE));

Utiliser TRUE comme deuxième argument de importNode effectuera une importation récursive de l'arborescence de nœuds.


Si vous devez importer du HTML (mal formé), remplacez loadXml par loadHTML. Cela déclenchera l’analyseur HTML de libxml (ce que ext/DOM utilise en interne):

libxml_use_internal_errors(true);
$tpl = new DOMDocument;
$tpl->loadHtml('<h1>This is <em>malformed</em> template</h2>');
$body->appendChild($dom->importNode($tpl->documentElement, TRUE));
libxml_use_internal_errors(false);

Notez que libxml tentera de corriger le balisage, par exemple. cela changera le </h2> de fermeture incorrect en </h1>.

39
Gordon

Comme je ne veux pas me débattre avec XML, il génère des erreurs plus rapidement et je ne suis pas partisan de préfixer un @ pour empêcher la sortie d’erreurs. Le loadHTML fait le meilleur travail à mon avis et c'est aussi simple que cela:

$doc = new DOMDocument();
$div = $doc->createElement('div');

// use a helper to load the HTML into a string
$helper = new DOMDocument();
$helper->loadHTML('<a href="#">This is my HTML Link.</a>');

// now the magic!
// import the document node of the $helper object deeply (true)
// into the $div and append as child.
$div->appendChild($doc->importNode($helper->documentElement, true));

// add the div to the $doc
$doc->appendChild($div);

// final output
echo $doc->saveHTML();
5
Markus Zeller

Voici un exemple simple en utilisant DOMDocumentFragment :

$doc = new DOMDocument();
$doc->loadXML("<root/>");
$f = $doc->createDocumentFragment();
$f->appendXML("<foo>text</foo><bar>text2</bar>");
$doc->documentElement->appendChild($f);
echo $doc->saveXML();

Voici la fonction d'assistance pour remplacer DOMNode:

/** 
 * Helper function for replacing $node (DOMNode) 
 * with an XML code (string) 
 * 
 * @var DOMNode $node 
 * @var string $xml 
 */ 
public function replaceNodeXML(&$node, $xml) { 
  $f = $this->dom->createDocumentFragment(); 
  $f->appendXML($xml); 
  $node->parentNode->replaceChild($f,$node); 
}

Source: Ancien article "Modèle basé sur PHP5 Dom".

Et voici une autre suggestion publiée par Pian0_M4n pour utiliser valeur attribut comme solution de contournement:

$dom = new DomDocument;

// main object
$object = $dom->createElement('div');

// html attribute
$attr = $dom->createAttribute('value');
// ugly html string
$attr->value = "<div>&nbsp; this is a really html string &copy;</div><i></i> with all the &copy; that XML hates!";
$object->appendChild($attr);

// jquery fix (or javascript as well)
$('div').html($(this).attr('value')); // and it works! 
$('div').removeAttr('value'); // to clean-up

Pas d'idéal, mais au moins ça marche.

0
kenorb