Je suis la fonction ci-dessous, j'ai du mal à sortir le DOMDocument sans ajouter les wrappers de balises XML, HTML, body et p avant la sortie du contenu. La solution suggérée:
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
Ne fonctionne que lorsque le contenu ne contient aucun élément de niveau bloc. Cependant, quand c'est le cas, comme dans l'exemple ci-dessous avec l'élément h1, la sortie résultante de saveXML est tronquée à ...
<p> Si vous aimez </p>
On m'a signalé cet article comme une solution de contournement possible, mais je ne comprends pas comment l'implémenter dans cette solution (voir les tentatives commentées ci-dessous).
Aucune suggestion?
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;
}
la source
DOMDocument
qui affecte également le code dans cette réponse. Afaik,DOMDocument
interprète toujours les données d'entrée comme 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 ne sont pas latin-1. Sinon, la sortie sera interrompue par exemple pour les caractères multi-octets UTF-8.Supprimez simplement les nœuds directement après avoir chargé le document avec loadHTML ():
la source
<!DOCTYPE
fonctionne. La deuxième ligne saute si<body>
a plus d'une note enfant.Utilisez à la
saveXML()
place et transmettez-lui le documentElement comme argument.http://php.net/domdocument.savexml
la source
saveHTML
aussi bien ( par exemple )loadHTML
libxml utilise le module d'analyseur HTML et qui insérera le squelette HTML manquant. Par conséquent,$dom->documentElement
sera l'élément HTML racine. J'ai corrigé votre exemple de code. Il devrait maintenant faire ce que Scott demande.Le problème avec la première réponse est qu'elle
LIBXML_HTML_NOIMPLIED
est instable .Il peut réorganiser les éléments (en particulier, déplacer la balise de fermeture de l'élément supérieur vers le bas du document), ajouter des
p
balises aléatoires , et peut-être une variété d'autres problèmes [1] . Cela peut supprimer les baliseshtml
etbody
pour vous, mais au prix d'un comportement instable. En production, c'est un drapeau rouge. En bref:N'utilisez pas
LIBXML_HTML_NOIMPLIED
. Utilisez plutôtsubstr
.Pensez-y. Les longueurs de
<html><body>
et</body></html>
sont fixes et aux deux extrémités du document - leurs tailles ne changent jamais, pas plus que leurs positions. Cela nous permet d'utilisersubstr
pour les couper:( CE N'EST PAS LA SOLUTION FINALE CEPENDANT! Voir ci-dessous pour la réponse complète , continuez à lire pour le contexte)
On coupe
12
le début du document parce que<html><body>
= 12 caractères (<<>>+html+body
= 4 + 4 + 4), et on recule et on coupe 15 la fin parce que\n</body></html>
= 15 caractères (\n+//+<<>>+body+html
= 1 + 2 + 4 + 4 + 4)Notez que j'utilise toujours
LIBXML_HTML_NODEFDTD
omettre l'!DOCTYPE
inclusion. Premièrement, cela simplifie lasubstr
suppression des balises HTML / BODY. Deuxièmement, nous ne supprimons pas le doctype avecsubstr
parce que nous ne savons pas si le «default doctype
» sera toujours quelque chose d'une longueur fixe. Mais, plus important encore,LIBXML_HTML_NODEFDTD
empêche l'analyseur DOM d'appliquer un doctype non HTML5 au document - ce qui empêche au moins l'analyseur de traiter les éléments qu'il ne reconnaît pas comme du texte libre.Nous savons pertinemment que les balises HTML / BODY ont des longueurs et des positions fixes, et nous savons que les constantes comme
LIBXML_HTML_NODEFDTD
ne sont jamais supprimées sans un certain type d'avis de dépréciation, donc la méthode ci-dessus devrait bien se dérouler dans le futur, MAIS ...... la seule mise en garde est que l'implémentation DOM pourrait changer la façon dont les balises HTML / BODY sont placées dans le document - par exemple, en supprimant la nouvelle ligne à la fin du document, en ajoutant des espaces entre les balises ou en ajoutant des nouvelles lignes.
Cela peut être résolu en recherchant les positions des balises d'ouverture et de fermeture
body
et en utilisant ces décalages comme pour nos longueurs à découper. Nous utilisonsstrpos
etstrrpos
pour trouver les décalages de l'avant et de l'arrière, respectivement:En conclusion, une répétition de la réponse finale et pérenne :
Pas de doctype, pas de balise html, pas de balise body. Nous ne pouvons qu'espérer que l'analyseur DOM recevra bientôt une nouvelle couche de peinture et que nous pourrons éliminer plus directement ces balises indésirables.
la source
$html = $dom -> saveHTML();
au lieu de$dom -> saveHTML();
plusieurs fois?Une astuce intéressante consiste à utiliser
loadXML
et ensuitesaveHTML
. Les baliseshtml
etbody
sont insérées auload
stade, pas ausave
stade.NB que c'est un peu piraté et que vous devriez utiliser la réponse de Jonah si vous pouvez la faire fonctionner.
la source
utiliser DOMDocumentFragment
la source
Nous sommes en 2017, et pour cette question de 2011, je n'aime aucune des réponses. Beaucoup de regex, de grandes classes, loadXML etc ...
Solution simple qui résout les problèmes connus:
Facile, simple, solide, rapide. Ce code fonctionnera avec les balises HTML et l'encodage comme:
Si quelqu'un trouve une erreur, veuillez le dire, je l'utiliserai moi-même.
Modifier , Autres options valides qui fonctionnent sans erreurs (très similaires à celles déjà données):
Vous pouvez ajouter du corps vous-même pour éviter toute chose étrange sur la furure.
Troisième option:
la source
mb_convert_encoding
et en ajoutant<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>
et en modifiant ensubstr
conséquence. Btw, la vôtre est la solution la plus élégante ici. J'ai voté pour.Je suis un peu en retard dans le club mais je ne voulais pas partager une méthode que j'ai découverte. Tout d'abord, j'ai les bonnes versions pour loadHTML () pour accepter ces options intéressantes, mais
LIBXML_HTML_NOIMPLIED
je n'ai pas fonctionné sur mon système. Les utilisateurs signalent également des problèmes avec l'analyseur (par exemple ici et ici ).La solution que j'ai créée est en fait assez simple.
Le HTML à charger est placé dans un
<div>
élément de sorte qu'il a un conteneur contenant tous les nœuds à charger.Ensuite, cet élément conteneur est supprimé du document (mais le DOMElement de celui-ci existe toujours).
Ensuite, tous les enfants directs du document sont supprimés. Cela inclut tout ajouté
<html>
,<head>
et<body>
balises (efficacementLIBXML_HTML_NOIMPLIED
option) ainsi que la<!DOCTYPE html ... loose.dtd">
déclaration (efficaceLIBXML_HTML_NODEFDTD
).Ensuite, tous les enfants directs du conteneur sont à nouveau ajoutés au document et il peut être généré.
XPath fonctionne comme d'habitude, veillez simplement à ce qu'il y ait plusieurs éléments de document maintenant, donc pas un seul nœud racine:
la source
Aucune des autres solutions au moment de la rédaction de cet article (juin 2012) n'était en mesure de répondre complètement à mes besoins, j'en ai donc écrit une qui traite les cas suivants:
<doctype>
,<xml>
,<html>
,<body>
, et<p>
tags)<p>
seul.Voici donc une solution qui résout ces problèmes:
J'ai également écrit quelques tests qui vivraient dans cette même classe:
Vous pouvez vérifier que cela fonctionne pour vous-même.
DomDocumentWorkaround::testAll()
renvoie ceci:la source
D'accord, j'ai trouvé une solution plus élégante, mais c'est juste fastidieux:
D'accord, j'espère que cela n'oublie rien et aide quelqu'un?
la source
Utilisez cette fonction
la source
preg_replace
parce que l'utilisation de méthodes basées sur DOMDocument pour supprimer les balises html et body ne préservait pas l'encodage UTF-8 :(Si la solution d'indicateurs à laquelle Alessandro Vendruscolo a répondu ne fonctionne pas, vous pouvez essayer ceci:
$bodyTag
contiendra votre code HTML traité complet sans tous ces wraps HTML, à l'exception du<body>
balise, qui est la racine de votre contenu. Ensuite, vous pouvez utiliser une expression régulière ou une fonction de découpage pour le supprimer de la chaîne finale (aprèssaveHTML
) ou, comme dans le cas ci-dessus, itérer sur tous ses enfants, en enregistrant leur contenu dans une variable temporaire$finalHtml
et en le renvoyant (ce que je crois être plus sûr).la source
Je suis tombé sur ce sujet pour trouver un moyen de supprimer le wrapper HTML. L'utilisation
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
fonctionne très bien, mais j'ai un problème avec utf-8. Après beaucoup d'efforts, j'ai trouvé une solution. Je le poste ci-dessous car tout le monde a le même problème.Le problème causé par
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Le problème:
Solution 1:
Solution 2:
la source
J'ai du mal avec cela sur RHEL7 exécutant PHP 5.6.25 et LibXML 2.9. (Vieux trucs en 2018, je sais, mais c'est Red Hat pour vous.)
J'ai trouvé que la solution très votée suggérée par Alessandro Vendruscolo casse le HTML en réorganisant les balises. C'est à dire:
devient:
Cela vaut pour les deux options qu'il vous suggère d'utiliser:
LIBXML_HTML_NOIMPLIED
etLIBXML_HTML_NODEFDTD
.La solution suggérée par Alex va à mi-chemin pour le résoudre, mais elle ne fonctionne pas si elle
<body>
a plus d'un nœud enfant.La solution qui fonctionne pour moi est la suivante:
Tout d'abord, pour charger le DOMDocument, j'utilise:
Pour enregistrer le document après avoir massé le DOMDocument, j'utilise:
Je suis le premier à convenir que ce n’est pas une solution très élégante - mais cela fonctionne.
la source
L'ajout de la
<meta>
balise déclenchera le comportement de correction deDOMDocument
. La bonne partie est que vous n'avez pas du tout besoin d'ajouter cette balise. Si vous ne souhaitez pas utiliser un encodage de votre choix, passez-le simplement comme argument de constructeur.http://php.net/manual/en/domdocument.construct.php
Production
Merci à @Bart
la source
J'avais cette exigence aussi et j'aimais la solution publiée par Alex ci-dessus. Il y a cependant quelques problèmes: si l'
<body>
élément contient plus d'un élément enfant, le document résultant ne contiendra que le premier élément enfant de<body>
, pas tous. De plus, j'avais besoin du décapage pour gérer les choses de manière conditionnelle - uniquement lorsque vous aviez un document avec les en-têtes HTML. Alors je l'ai affiné comme suit. Au lieu de le supprimer<body>
, je l'ai transformé en un<div>
, et j'ai supprimé la déclaration XML et<html>
.la source
Tout comme les autres membres, je me suis d'abord délecté de la simplicité et de la puissance impressionnante de la réponse @Alessandro Vendruscolo. La possibilité de simplement transmettre certaines constantes marquées au constructeur semblait trop belle pour être vraie. Pour moi, ça l'était. J'ai les versions correctes de LibXML ainsi que de PHP, mais quoi qu'il en soit, cela ajouterait encore la balise HTML à la structure de nœud de l'objet Document.
Ma solution fonctionnait bien mieux que d'utiliser le ...
Drapeaux ou ....
Suppression de nœuds, qui devient désordonnée sans ordre structuré dans le DOM. Encore une fois, les fragments de code n'ont aucun moyen de prédéterminer la structure DOM.
J'ai commencé ce voyage en voulant un moyen simple de parcourir le DOM comme le fait JQuery ou du moins d'une manière qui avait un ensemble de données structurées soit un seul lien, soit doublement lié ou une traversée de nœuds arborescente. Je me fichais de savoir combien de temps je pouvais analyser une chaîne comme le fait HTML et avoir également l'incroyable puissance des propriétés de la classe d'entité de nœud à utiliser en cours de route.
Jusqu'à présent, DOMDocument Object m'a laissé vouloir ... Comme avec beaucoup d'autres programmeurs, il semble ... Je sais que j'ai vu beaucoup de frustration dans cette question, donc depuis que j'ai ENFIN .... (après environ 30 heures d'essais et d'échecs test de type) J'ai trouvé un moyen de tout obtenir. J'espère que ça aidera quelqu'un...
Tout d'abord, je suis cynique de TOUT ... lol ...
J'aurais passé toute ma vie avant d'être d'accord avec quiconque sur le fait qu'une classe tierce est de toute façon nécessaire dans ce cas d'utilisation. J'étais et je ne suis pas fan de l'utilisation d'une structure de classe tierce, mais je suis tombé sur un excellent analyseur. (environ 30 fois sur Google avant de céder, alors ne vous sentez pas seul si vous l'avez évité car cela avait l'air boiteux de quelque manière que ce soit ...)
Si vous utilisez des fragments de code et que vous avez besoin du code propre et non affecté par l'analyseur de quelque manière que ce soit, sans utiliser de balises supplémentaires, utilisez simplePHPParser .
C'est incroyable et agit beaucoup comme JQuery. Je ne suis pas souvent impressionné mais cette classe utilise beaucoup de bons outils et je n'ai pas encore eu d'erreurs d'analyse. Je suis un grand fan de pouvoir faire ce que fait cette classe.
Vous pouvez trouver ses fichiers à télécharger ici , ses instructions de démarrage ici , et son API ici . Je recommande vivement d'utiliser cette classe avec ses méthodes simples qui peuvent faire de
.find(".className")
la même manière qu'une méthode de recherche JQuery serait utilisée ou même des méthodes familières telles quegetElementByTagName()
ougetElementById()
...Lorsque vous enregistrez une arborescence de nœuds dans cette classe, cela n'ajoute rien du tout. Vous pouvez simplement dire
$doc->save();
et il renvoie l'arbre entier dans une chaîne sans aucun problème.Je vais maintenant utiliser cet analyseur pour tous les projets à bande passante non plafonnée à l'avenir.
la source
J'ai PHP 5.3 et les réponses ici n'ont pas fonctionné pour moi.
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
remplacé tout le document par seulement le premier enfant, j'avais beaucoup de paragraphes et seul le premier était en cours d'enregistrement, mais la solution m'a donné un bon point de départ pour écrire quelque chose sans queregex
je laisse quelques commentaires et je suis presque sûr que cela peut être amélioré, mais si quelqu'un a le même problème que moi cela peut être un bon point de départ.Ensuite, nous pourrions l'utiliser comme ceci:
Notez que cela
appendChild
accepte unDOMNode
afin que nous n'ayons pas besoin de créer de nouveaux éléments, nous pouvons simplement réutiliser ceux existants qui implémentent deDOMNode
tels élémentsDOMElement
peuvent être importants pour garder le code «sain» lors de la manipulation de plusieurs documents HTML / XMLla source
LIBXML_HTML_NOIMPLIED
car il ne le fait que partiellement. La suppression du doctype est efficaceLIBXML_HTML_NODEFDTD
.Je fais face à 3 problèmes avec la
DOMDocument
classe.1- Cette classe charge html avec le codage ISO et les caractères utf-8 ne s'affichent pas en sortie.
2- Même si on donne
LIBXML_HTML_NOIMPLIED
à la méthode loadHTML, jusqu'à ce que notre html d'entrée ne contient pas de balise racine, il ne sera pas analysé correctement.3- Cette classe considère les balises HTML5 invalides.
J'ai donc remplacé cette classe pour résoudre ces problèmes et j'ai changé certaines méthodes.
Maintenant, j'utilise
DOMEditor
au lieu deDOMDocument
et cela a bien fonctionné pour moi jusqu'à présentla source
Je suis également tombé sur ce problème.
Malheureusement, je ne me sentais pas à l'aise d'utiliser l'une des solutions fournies dans ce fil, alors je suis allé en vérifier une qui me satisferait.
Voici ce que j'ai inventé et cela fonctionne sans problème:
En substance, cela fonctionne de la même manière que la plupart des solutions fournies ici, mais au lieu de faire du travail manuel, il utilise le sélecteur xpath pour sélectionner tous les éléments du corps et concatène leur code html.
la source
descendant-or-self::body/p/*
.mon serveur a php 5.3 et ne peut pas mettre à niveau donc ces options
ne sont pas pour moi.
Pour résoudre ce problème, je dis à la fonction SaveXML d'imprimer l'élément Body, puis remplacez simplement le "body" par "div"
voici mon code, j'espère qu'il aide quelqu'un:
l'utf-8 est pour le support hébreu.
la source
La réponse d'Alex est correcte, mais peut provoquer l'erreur suivante sur les nœuds vides:
Voici mon petit mod:
L'ajout de trim () est également une bonne idée pour supprimer les espaces.
la source
J'ai peut-être trop tard. Mais peut-être que quelqu'un (comme moi) a encore ce problème.
Donc, rien de ce qui précède n'a fonctionné pour moi. Comme $ dom-> loadHTML ferme également les balises ouvertes, ajoutez non seulement des balises html et body.
Donc, ajouter un élément <div> ne fonctionne pas pour moi, car j'ai parfois comme 3-4 div non fermés dans le morceau html.
Ma solution:
1.) Ajoutez un marqueur à couper, puis chargez le morceau html
2.) faites ce que vous voulez avec le document
3.) enregistrez html
4.) avant de le renvoyer, supprimez les balises <p> </ p> du marqueur, étrangement elles n'apparaissent que sur [MARK] mais pas sur [/ MARK] ...!?
5.) tout supprimer avant et après le marqueur
6.) le renvoyer
Ce serait beaucoup plus facile si LIBXML_HTML_NOIMPLIED fonctionnait pour moi. Cela devrait, mais ce n'est pas le cas. PHP 5.4.17, version de libxml 2.7.8.
Je trouve vraiment étrange, j'utilise l'analyseur HTML DOM et ensuite, pour corriger ce "truc", je dois utiliser regex ... Le but était de ne pas utiliser de regex;)
la source
< div >< div > ... < /div >
. Je cherche toujours des solutions.Pour toute personne utilisant Drupal, il existe une fonction intégrée pour le faire:
https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x
Code de référence:
la source
Vous pouvez utiliser tidy avec show-body-only:
Mais rappelez-vous: supprimez certaines balises comme les icônes Font Awesome: Problèmes d'indentation de HTML (5) avec PHP
la source
la source
Cette bibliothèque facilite la traversée / modification du DOM et prend également en charge la suppression des wrappers doctype / html pour vous:
https://github.com/sunra/php-simple-html-dom-parser
la source