Comment saveHTML de DOMDocument sans enveloppe HTML?
Je suis à la fonction ci-dessous, j'ai du mal à la sortie de la DOMDocument sans elle, ajoutant le XML, HTML, corps et p tag 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).
Des 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;
}
Vous devez vous connecter pour publier un commentaire.
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
lors
saveHTML()
il n'y aura pasdoctype
, pas de<html>
, et pas de<body>
.Documentation complète sur Libxml paramètres est ici
(Notez que
loadHTML
docs disent que Libxml 2.6 est nécessaire, maisLIBXML_HTML_NODEFDTD
est uniquement disponible en Libxml 2.7.8 etLIBXML_HTML_NOIMPLIED
est disponible dans Libxml 2.7.7)DOMDocument
qui affecte également le code dans cette réponse. Autant que je sache,DOMDocument
toujours interprète les données d'entrée que le latin-1 , sauf si l'entrée spécifie un jeu de caractères différent. En d'autres termes: La<meta charset="…">
balise semble être nécessaire pour les données d'entrée qui n'est pas latin-1. Sinon, la sortie sera cassé pour l'e. g. UTF-8 caractères multioctets.mb_convert_encoding
comme décrit ici: stackoverflow.com/a/8218649/2477364 je dirais que nous sommes dans le besoin d'une bonne unique-HTML-traitement des éléments.echo
ing HTML éléments de l'ensemble est donc 2000.Seulement de supprimer les nœuds directement après le chargement du document avec loadHTML():
<!DOCTYPE
œuvres. Le deuxième ligne des pauses si<body>
a plus d'un enfant remarque.Utilisation
saveXML()
au lieu de cela, et passer le documentElement comme un argument.http://php.net/domdocument.savexml
saveHTML
ainsi (exemple)loadHTML
libxml utilise l'analyseur HTML module et qui permet d'insérer du HTML manquant squelette. Par conséquent,$dom->documentElement
sera la racine de l'élément HTML. J'ai corrigé ton code d'exemple. Il devrait maintenant faire ce qu'il demande.echo $document->saveHTML();
et de voir par vous-même. Apparemment, le problème est (comme @lonesomeday dit), c'est de la manipulation de la majoration de la charge.utilisation DOMDocumentFragment
Une astuce consiste à utiliser
loadXML
et puissaveHTML
. Lehtml
etbody
balises sont insérées à laload
stade, pas lesave
scène.NB que c'est un peu hacky et vous devez l'utiliser de Jonas réponse si vous pouvez l'obtenir pour fonctionner.
De la question avec le haut réponse est que
LIBXML_HTML_NOIMPLIED
est instable.Il peut réorganiser les éléments (en particulier, le déplacement de l'élément de plus haut niveau de clôture de l'étiquette au bas du document), ajouter de l'aléatoire
p
balises, et peut-être une variété d'autres problèmes de[1]. Il peut supprimer leshtml
etbody
balises pour vous, mais au prix d'un comportement instable. Dans la production, c'est un drapeau rouge. En bref:Ne pas utiliser
LIBXML_HTML_NOIMPLIED
. Au lieu de cela, utilisersubstr
.Penser. Les longueurs de
<html><body>
et</body></html>
sont fixes et aux deux extrémités du document - leur taille ne change jamais, ni leurs positions. Cela nous permet d'utilisersubstr
à réduire l'écart:(CE N'EST PAS LA SOLUTION FINALE, CEPENDANT! Voir ci-dessous pour la réponse complète, continuez à lire pour le contexte)
Nous couper
12
à l'écart depuis le début de ce document parce que<html><body>
= 12 caractères (<<>>+html+body
= 4+4+4), et nous revenir en arrière et de coupe de 15 à la fin parce que\n</body></html>
= 15 caractères (\n+//+<<>>+body+html
= 1 + 2 + 4 + 4 + 4)Avis que j'ai toujours utiliser
LIBXML_HTML_NODEFDTD
omettre le!DOCTYPE
d'être inclus. Tout d'abord, cela simplifie lasubstr
suppression de l'HTML/balises de CORPS. Deuxièmement, nous ne supprimons pas le doctype avecsubstr
parce que nous ne savons pas si le 'par défaut doctype
" sera toujours quelque chose d'une longueur fixe. Mais, plus important encore,LIBXML_HTML_NODEFDTD
arrête le DOM parser de l'application d'un non-doctype HTML5 pour le document, ce qui permet au moins d'empêcher l'analyseur de traiter des éléments qu'il ne reconnaît pas comme lâche texte.Nous savons pour un fait que le HTML/BODY balises sont de longueurs fixes et des positions, et nous savons que les constantes comme
LIBXML_HTML_NODEFDTD
ne sont jamais supprimés sans un certain type de la dépréciation de l'avis, si la méthode ci-dessus devraient rouler dans le futur, MAIS......le seul inconvénient est que le DOM de la mise en œuvre pourrait changement dans la manière de HTML/BODY balises sont placées dans le document - par exemple, en supprimant le caractère de saut de ligne à la fin du document, en ajoutant des espaces entre les balises, ou d'ajouter des retours à la ligne.
Cela peut être résolu par la recherche pour les positions d'ouverture et de fermeture des balises pour
body
, et l'utilisation de ces décalages comme pour nos longueurs à découper. Nous utilisonsstrpos
etstrrpos
à trouver les décalages de l'avant et à l'arrière, respectivement:En clôture, une répétition de la finale, l'avenir de réponse:
Pas de doctype, pas de balise html, pas de balise body. Nous pouvons seulement espérer que les DOM parser recevront une couche de peinture fraîche bientôt et l'on peut le plus directement éliminer ces indésirables balises.
$html = $dom -> saveHTML();
au lieu de$dom -> saveHTML();
à plusieurs reprises?Je suis un peu en retard dans le club, mais ne veulent pas pas partager une méthode que j'ai découvert. Tout d'abord, j'ai eu le droit à des versions pour loadHTML() pour accepter ces options de nice, mais
LIBXML_HTML_NOIMPLIED
ne fonctionne pas sur mon système. Aussi les utilisateurs signalent des problèmes avec l'analyseur (par exemple ici et ici).La solution que j'ai créé est en fait assez simple.
HTML à charger est mis dans une
<div>
élément de sorte qu'il a un récipient contenant tous les nœuds pour être chargé.Puis ce conteneur de l'élément est supprimé du document (mais la DOMElement de il existe toujours).
Ensuite, tous les enfants directs du document sont supprimés. Cela inclut l'ajout de
<html>
,<head>
et<body>
balises (effectivementLIBXML_HTML_NOIMPLIED
option) ainsi que le<!DOCTYPE html ... loose.dtd">
déclaration (effectivementLIBXML_HTML_NODEFDTD
).Ensuite, tous les enfants directs du conteneur sont ajoutés à nouveau le document et il peut être sortie.
XPath fonctionne comme d'habitude, il suffit de prendre soin qu'il existe de multiples éléments d'un document maintenant, donc pas un seul nœud racine:
C'est en 2017, et pour cette année 2011 Question que je n'aime pas les réponses.
Beaucoup de regex, de grandes classes, loadXML etc...
Facile solution qui résout les problèmes connus:
Facile, Simple, Solide, Rapide. Ce code fonctionnera concernant les balises HTML et de codage comme:
Si quelqu'un trouve une erreur , s'il vous plaît dites, je vais l'utiliser moi-même.
Modifier, d'Autres options de travail sans erreurs (très semblables à ceux déjà cités):
Vous pouvez ajouter de corps, vous-même afin de prévenir toute chose d'étrange sur la furure.
Thirt option:
mb_convert_encoding
et au lieu de l'ajout<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>
et la modification desubstr
en conséquence. Btw, la vôtre est la solution la plus élégante ici. Upvoted.Utiliser cette fonction
preg_replace
parce que DOMDocument à l'aide basée sur les méthodes de retrait de l'html et des balises de corps n'ont pas la préservation de l'encodage UTF-8 🙁Bon j'ai trouvé une solution plus élégante, mais c'est juste fastidieux:
Bien, j'espère que ce n'est pas rien omettre et de l'aide à quelqu'un?
@
appel thoAucune des autres solutions au moment d'écrire ces lignes (juin 2012) ont été en mesure de répondre complètement à mes besoins, j'ai donc écrit un qui gère les cas suivants:
<doctype>
,<xml>
,<html>
,<body>
, et<p>
tags)<p>
seul.Voici donc une solution qui résout ces problèmes:
J'ai aussi écrit quelques tests qui voudrait vivre dans la même classe:
Vous pouvez vérifier que cela fonctionne pour vous-même.
DomDocumentWorkaround::testAll()
retourne ceci:Si les indicateurs solution répondu par Alessandro Vendruscolo ne fonctionne pas, vous pouvez essayer ceci:
$bodyTag
contiendra votre plein traitées code HTML sans toutes ces HTML roulés, sauf pour les<body>
tag, qui est à la racine de votre contenu. Ensuite, vous pouvez utiliser une expression régulière ou un trim fonction pour supprimer de la chaîne finale (aprèssaveHTML
) ou, comme dans le cas ci-dessus, effectuer une itération sur l'ensemble de ses enfants, l'enregistrement de son contenu dans une variable temporaire$finalHtml
et de le retourner (ce que je crois être sûr).L'ajout de la
<meta>
tag déclenche la fixation de comportement deDOMDocument
. La bonne nouvelle est que vous n'avez pas besoin d'ajouter que la balise. Si vous voulez pas utiliser un encodage de votre choix, il suffit de passer comme un argument du constructeur.http://php.net/manual/en/domdocument.construct.php
Sortie
Grâce à @Bart
J'ai eu cette exigence, trop, et j'aimais la solution posté par Alex-dessus. Il ya un couple de questions, - si le
<body>
élément contient plus d'un élément enfant, le document qui en résulte ne contiendra uniquement le premier élément enfant de<body>
, pas tous d'entre eux. Aussi, j'avais besoin de le décapage de gérer les choses de façon conditionnelle seulement quand vous avez eu le document avec des balises de titre. J'ai donc affiné comme suit. Au lieu de supprimer<body>
, j'ai transformé à un<div>
, et dépouillé de la déclaration XML et<html>
.Comme beaucoup d'autres membres, j'ai d'abord émerveillé dans la simplicité et la puissance impressionnante de @Alessandro Vendruscolo réponse. La capacité de simplement passer un pavillon des constantes pour le constructeur semble trop beau pour être vrai. Pour moi, c'était. J'ai les versions correctes des deux LibXML ainsi que PHP toutefois, peu importe ce qu'il ne serait toujours ajouter la balise HTML pour le nœud de la structure de l'objet Document.
Ma solution a fonctionné mieux que d'utiliser la...
Drapeaux ou......
Ablation des ganglions, qui est malpropre, sans un ordre structuré et dans les DOM. Encore des fragments de code n'avons aucun moyen de déterminer par avance les DOM structure.
J'ai commencé ce voyage qui veulent un moyen simple de le faire DOM traversée comment JQuery t-elle ou, au moins, d'une certaine façon qui ont structuré un ensemble de données soit individuellement liée, doublement chaînée ou arbre avais nœud de la traversée. Je n'aimais pas la façon tant que j'ai pu analyser une chaîne de la façon dont le HTML et aussi l'incroyable puissance du nœud de l'entité des propriétés de la classe à utiliser le long du chemin.
La mesure Objet DOMDocument m'a laissé vouloir... Comme beaucoup d'autres programmeurs, il semble... je sais j'ai vu beaucoup de frustration dans cette question depuis que j'ai ENFIN.... (après environ 30 heures de essayer et échouer les essais de type), j'ai trouvé un moyen pour obtenir tout cela. J'espère que cela aide quelqu'un...
Tout d'abord, je suis cynique de TOUT... lol...
J'aurais allé une vie avant d'être d'accord avec quelqu'un que un tiers de la classe est de toute façon nécessaire dans ce cas d'utilisation. J'étais et je suis PAS un fan de l'utilisation de toute tierce partie, la structure de la classe cependant, je suis tombé sur un excellent analyseur. (environ 30 fois dans Google avant que j'ai donné en sorte de ne pas se sentir seul si vous avez évité parce qu'il a regardé lame de officieux de toute façon...)
Si vous êtes en utilisant des fragments de code et avoir besoin de l', code propre et ne sont pas affectés par l'analyseur de toute manière, sans balises supplémentaires utilisées ensuite utiliser simplePHPParser.
C'est incroyable et agit un peu comme JQuery. J'ai pas souvent impressionné mais cette classe rend l'utilisation de beaucoup de bon outils et je n'ai pas eu l'analyse des erreurs encore. Je suis un grand fan de pouvoir faire ce que cette classe n'.
Vous pouvez trouver ses fichiers à télécharger ici, son démarrage instructions ici, et son API ici. Je recommande fortement d'utiliser cette classe avec ses méthodes simples qui peuvent faire une
.find(".className")
de la même façon JQuery trouver la méthode ou les méthodes habituelles telles quegetElementByTagName()
ougetElementById()
...Lorsque vous enregistrez un nœud de l'arbre dans cette classe, il n'est pas ajouter quoi que ce soit. Vous pouvez simplement dire
$doc->save();
et sorties de l'arbre tout entier en une chaîne sans aucun problème.Je vais maintenant utiliser cet analyseur pour tous, non plafonné, de bande passante, des projets dans l'avenir.
J'ai PHP 5.3 et les réponses ici n'a pas de travail pour moi.
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
remplacé tous les documents avec seulement le premier enfant, j'ai eu beaucoup de paragraphes et seule la première a été enregistrée, mais la solution m'a donné un bon point de départ pour écrire quelque chose sansregex
j'ai laissé quelques commentaires et je suis sûr que cela peut être amélioré, mais si quelqu'un a le même problème que moi, il peut être un bon point de départ.Puis nous avons pu l'utiliser comme ceci:
Noter que
appendChild
accepte unDOMNode
donc nous n'avons pas besoin de créer de nouveaux éléments, nous pouvons réutiliser existants qui mettent en œuvre desDOMNode
commeDOMElement
cela peut être important de garder le code "sain d'esprit" lors de la manipulation de plusieurs HTML/XML documentsLIBXML_HTML_NOIMPLIED
comme il le fait seulement en partie. Retirer le doctype est effectivementLIBXML_HTML_NODEFDTD
.Je suis tombé sur ce sujet, afin de trouver un moyen de supprimer l'enveloppe HTML. À l'aide de
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
fonctionne très bien, mais j'ai un problème avec l'encodage utf-8. Après beaucoup d'efforts, j'ai trouvé une solution. Je poste ci-dessous pour quelqu'un a le même problème.Le problème causé en raison de
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Le problème:
Solution 1:
Solution 2:
Je suis aux prises avec ce sur RHEL7 l'exécution de PHP 5.6.25 et LibXML 2.9. (Vieux trucs en 2018, je sais, mais c'est la Red Hat pour vous.)
J'ai constaté que beaucoup upvoted solution proposée par Alessandro Vendruscolo rompt le HTML par la réorganisation de balises. I. e.:
devient:
Cela vaut pour les deux options, il vous suggère d'utiliser:
LIBXML_HTML_NOIMPLIED
etLIBXML_HTML_NODEFDTD
.La solution proposée par Alex passe la moitié de moyen de le résoudre, mais il ne fonctionne pas si
<body>
a plus d'un nœud enfant.La solution qui fonctionne pour moi est le follwing:
D'abord, pour charger le DOMDocument, j'utilise:
Pour enregistrer le document après masser le DOMDocument, j'utilise:
Je suis le premier à reconnaître que ce n'est pas une solution élégante, mais il fonctionne.
Je suis tombé sur cette question.
Malheureusement, je n'ai pas senti confortablement à l'aide de l'une des solutions proposées dans ce fil, alors je suis allé vérifier une qui puisse me satisfaire.
Voici ce que j'ai fait et ça fonctionne sans problème:
Dans essense il fonctionne de manière similaire à la plupart des solutions proposées ici, mais au lieu de faire des travaux manuels, il utilise xpath sélecteur pour sélectionner tous les éléments dans le corps et concatène leur code html.
descendant-or-self::body/p/*
.mon serveur a obtenu php 5.3 et ne peut pas mettre de sorte que ces options
ne sont pas pour moi.
Pour résoudre ce que je dis la SaveXML la Fonction d'impression de l'élément de Corps et ensuite il suffit de remplacer le "corps" avec "div"
voici mon code, j'espère que c'est aider quelqu'un:
l'utf-8 est de l'hébreu soutien.
Alex réponse est correcte, mais peut provoquer d'erreur suivant sur les nœuds vides:
Voici mon petit mod:
Ajouter la garniture() est aussi une bonne idée de supprimer l'espace.
J'ai peut-être trop tard. Mais peut-être quelqu'un (comme moi) a encore ce problème.
Donc, aucun de ces fonctionné pour moi. Parce que $dom->loadHTML aussi fermer les balises ouvertes ainsi, non seulement ajouter du code html et des balises de corps.
Il faut donc ajouter un < div > élément ne fonctionne pas pour moi, parce que j'ai parfois comme 3-4 unclosed div dans le code html pièce.
Ma solution:
1.) Ajouter un marqueur à la coupe, puis de charger le html pièce
2.) faire ce que vous voulez avec le document
3.) enregistrer html
4.) avant de vous le retourner, supprimer < p >< /p > balises de repère, étrangement, il est seulement apparaissent sur [MARK], mais pas sur [/MARQUE]...!?
5.) supprimer tout ce qui est avant et après le marqueur
6.) de retour, il
Il serait beaucoup plus facile si LIBXML_HTML_NOIMPLIED a fonctionné pour moi. Il devaient, mais il ne l'est pas. PHP 5.4.17, libxml Version 2.7.8.
Je trouve vraiment étrange, j'utilise le HTML DOM parser et puis, pour corriger cette "chose" que j'ai utiliser les regex... Le but était de ne pas utiliser les regex 😉
< div >< div > ... < /div >
. J'ai toujours à la recherche de solutions.Pour toute personne à l'aide de Drupal, il y a un construit en fonction pour ce faire:
https://api.drupal.org/api/drupal/modules!filtre!le filtre.le module de la fonction//filter_dom_serialize/7.x
Code de référence:
Cette bibliothèque facilite la traverse /modifier le DOM et prend soin de supprimer le doctype /html wrappers pour vous:
https://github.com/sunra/php-simple-html-dom-parser
Après l'expérimentation et la recherche pour des centaines de fois, je trouve que la meilleure pratique.