133 votes

DOMDocument saveHTML sans enveloppe HTML?

Je n la fonction ci-dessous, j'ai du mal à la sortie de la DOMDocument sans elle, ajoutant le xml, html, du corps et de balise p wrappers avant la sortie de son contenu. Le correctif proposé...

$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));

Ne fonctionne que lorsque le contenu n'a pas d'éléments de niveau bloc à l'intérieur. Cependant, lorsqu'il le fait, comme dans l'exemple ci-dessous avec l'élément h1, le résultat de saveXML est tronqué...

<p>Si vous aimez</p>

J'ai été rappelé à ce post comme une solution de contournement possible, mais je ne peux pas comprendre comment le mettre en œuvre dans cette solution (voir en commentaire tentatives ci-dessous).

Toutes les suggestions?

function rseo_decorate_keyword($postarray) {
    global $post;
    $keyword = "Jasmine Tea"
    $content = "If you like <h1>jasmine tea</h1> you will really like it with Jasmine Tea flavors. This is the last ocurrence of the phrase jasmine tea within the content. If there are other instances of the keyword jasmine tea within the text what happens to jasmine tea."
    $d = new DOMDocument();
    @$d->loadHTML($content);
    $x = new DOMXpath($d);
    $count = $x->evaluate("count(//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and (ancestor::b or ancestor::strong)])");
    if ($count > 0) return $postarray;
    $nodes = $x->query("//text()[contains(translate(., 'ABCDEFGHJIKLMNOPQRSTUVWXYZ', 'abcdefghjiklmnopqrstuvwxyz'), '$keyword') and not(ancestor::h1) and not(ancestor::h2) and not(ancestor::h3) and not(ancestor::h4) and not(ancestor::h5) and not(ancestor::h6) and not(ancestor::b) and not(ancestor::strong)]");
    if ($nodes && $nodes->length) {
        $node = $nodes->item(0);
        // Split just before the keyword
        $keynode = $node->splitText(strpos($node->textContent, $keyword));
        // Split after the keyword
        $node->nextSibling->splitText(strlen($keyword));
        // Replace keyword with <b>keyword</b>
        $replacement = $d->createElement('strong', $keynode->textContent);
        $keynode->parentNode->replaceChild($replacement, $keynode);
    }
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->item(1));
//  $postarray['post_content'] = $d->saveXML($d->getElementsByTagName('body')->childNodes);
return $postarray;
}

267voto

Toutes ces réponses sont maintenant mal, parce que de PHP 5.4 et Libxml 2.6 loadHTML a maintenant un $option paramètre qui indique Libxml sur la façon dont il doit analyser le contenu.

Par conséquent, si l'on charge le HTML avec ces options

$html->loadHTML($content, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);

lorsque vous effectuez saveHTML() il n'y aura pas d' doctype, n <html>, et pas d' <body>.

LIBXML_HTML_NOIMPLIED désactive l'ajout automatique de l'implicite html/éléments de carrosserie LIBXML_HTML_NODEFDTD empêche un défaut doctype être ajouté quand l'un n'est pas trouvé.

Documentation complète sur Libxml paramètres est ici

(À noter qu' loadHTML docs disent que Libxml 2.6 est nécessaire, mais LIBXML_HTML_NODEFDTD n'est disponible que dans Libxml 2.7.8 et LIBXML_HTML_NOIMPLIED est disponible dans Libxml 2.7.7)

78voto

Alex Points 3747

Il suffit de retirer les nœuds directement après le chargement du document avec loadHTML():

# remove <!DOCTYPE 
$doc->removeChild($doc->firstChild);            

# remove <html><body></body></html> 
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);

21voto

Jonah Points 5434

Utiliser saveXML() au lieu de cela, et passer le documentElement comme argument.

$innerHTML = '';
foreach ($document->getElementsByTagName('p')->item(0)->childNodes as $child) {
    $innerHTML .= $document->saveXML($child);
}
echo $innerHTML;

http://php.net/domdocument.savexml

18voto

jcp Points 11

utilisation DOMDocumentFragment

$html = 'what you want';
$doc = new DomDocument();
$fragment = $doc->createDocumentFragment();
$fragment->appendXML($html);
$doc->appendChild($fragment);
echo $doc->saveHTML();

15voto

lonesomeday Points 95456

Une astuce est d'utiliser loadXML puis saveHTML. L' html et body balises sont insérées à l' load stade, pas le save stade.

$dom = new DOMDocument;
$dom->loadXML('<p>My DOMDocument contents are here</p>');
echo $dom->saveHTML();

NB que c'est un peu hacky et vous devez l'utiliser de Jonas réponse si vous pouvez l'obtenir pour fonctionner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X