Ich bin die Funktion unten, ich kämpfen , um die DOMDocument ohne es anhängt die XML, HTML, zur Ausgabe von Körper und p - Tag - Wrapper vor der Ausgabe des Inhalts. Die vorgeschlagene Lösung:
$postarray['post_content'] = $d->saveXML($d->getElementsByTagName('p')->item(0));
Funktioniert nur, wenn der Inhalt keine Elemente auf Blockebene enthält. Wenn dies jedoch der Fall ist, wie im folgenden Beispiel mit dem Element h1, wird die resultierende Ausgabe von saveXML auf ... abgeschnitten.
<p> Wenn Sie möchten </ p>
Ich wurde auf diesen Beitrag als mögliche Problemumgehung hingewiesen, kann aber nicht verstehen, wie er in diese Lösung implementiert werden kann (siehe auskommentierte Versuche unten).
Irgendwelche Vorschläge?
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;
}
quelle
DOMDocument
dass auch Sie den Code in dieser Antwort betrifft. AfaikDOMDocument
interpretiert Eingabedaten immer als Latin-1, es sei denn, die Eingabe gibt einen anderen Zeichensatz an . Mit anderen Worten: Das<meta charset="…">
Tag scheint für Eingabedaten benötigt zu werden, die nicht Latin-1 sind. Andernfalls wird die Ausgabe für z. B. UTF-8-Multibyte-Zeichen unterbrochen.Entfernen Sie einfach die Knoten direkt nach dem Laden des Dokuments mit loadHTML ():
quelle
<!DOCTYPE
funktioniert. Die zweite Zeile wird unterbrochen, wenn<body>
mehr als eine untergeordnete Note vorhanden ist.Verwenden Sie
saveXML()
stattdessen und übergeben Sie das documentElement als Argument.http://php.net/domdocument.savexml
quelle
saveHTML
auch ( Beispiel )loadHTML
tun, verwendet libxml das HTML-Parser-Modul, wodurch das fehlende HTML-Skelett eingefügt wird. Folglich$dom->documentElement
wird das Stamm-HTML-Element sein. Ich habe Ihren Beispielcode korrigiert. Es sollte jetzt tun, was Scott verlangt.Das Problem mit der Top-Antwort ist, dass
LIBXML_HTML_NOIMPLIED
es instabil ist .Es kann Elemente neu anordnen (insbesondere das schließende Tag des oberen Elements an den unteren Rand des Dokuments verschieben), zufällige
p
Tags hinzufügen und möglicherweise eine Reihe anderer Probleme [1] . Es kann die Tagshtml
undbody
für Sie entfernen , jedoch auf Kosten eines instabilen Verhaltens. In der Produktion ist das eine rote Fahne. Zusamenfassend:Nicht benutzen
LIBXML_HTML_NOIMPLIED
. Verwenden Sie stattdessensubstr
.Denk darüber nach. Die Längen von
<html><body>
und</body></html>
sind fest und an beiden Enden des Dokuments - ihre Größen ändern sich nie und ihre Positionen auch nicht. Dies ermöglicht es uns,substr
sie wegzuschneiden:( Dies ist jedoch nicht die endgültige Lösung! Siehe unten für die vollständige Antwort , lesen Sie weiter für den Kontext)
Wir schneiden
12
vom Anfang des Dokuments weg, weil<html><body>
= 12 Zeichen (<<>>+html+body
= 4 + 4 + 4), und wir gehen rückwärts und schneiden 15 vom Ende ab, weil\n</body></html>
= 15 Zeichen (\n+//+<<>>+body+html
= 1 + 2 + 4 + 4 + 4)Beachten Sie, dass ich immer noch
LIBXML_HTML_NODEFDTD
weglasse, dass das!DOCTYPE
nicht aufgenommen wird. Dies vereinfacht zunächst dassubstr
Entfernen der HTML / BODY-Tags. Zweitens entfernen wir den Doctype nicht mit,substr
weil wir nicht wissen, ob das 'default doctype
' immer eine feste Länge haben wird. Aber am wichtigsten,LIBXML_HTML_NODEFDTD
der DOM-Parser keinen Nicht-HTML5-Doctype auf das Dokument anwendet. Dies verhindert zumindest, dass der Parser Elemente behandelt, die er nicht als losen Text erkennt.Wir wissen, dass die HTML / BODY-Tags feste Längen und Positionen haben, und wir wissen, dass Konstanten wie diese
LIBXML_HTML_NODEFDTD
niemals ohne irgendeine Art von Verfallserklärung entfernt werden, daher sollte die obige Methode auch in Zukunft funktionieren , ABER ...... die einzige Einschränkung ist, dass die DOM-Implementierung könnte den Weg in HTML / BODY - Tags im Dokument platziert werden ändern - zum Beispiel, das Newline am Ende des Dokuments zu entfernen, das Hinzufügen Leerzeichen zwischen den Tags oder dem Hinzufügen von Zeilenumbrüchen.
Dies kann behoben werden, indem nach den Positionen der öffnenden und schließenden Tags gesucht
body
wird und diese Offsets für unsere Längen zum Abschneiden verwendet werden. Wir verwendenstrpos
undstrrpos
finden die Offsets von vorne bzw. hinten:Abschließend eine Wiederholung der endgültigen, zukunftssicheren Antwort :
Kein Doctype, kein HTML-Tag, kein Body-Tag. Wir können nur hoffen, dass der DOM-Parser bald einen neuen Anstrich erhält, und wir können diese unerwünschten Tags direkter beseitigen.
quelle
$html = $dom -> saveHTML();
statt$dom -> saveHTML();
wiederholt?Ein ordentlicher Trick ist es,
loadXML
und dann zu verwendensaveHTML
. Die Tagshtml
undbody
werden auf derload
Bühne eingefügt , nicht auf dersave
Bühne.NB, dass dies ein bisschen hacky ist und Sie Jonahs Antwort verwenden sollten, wenn Sie es zum Laufen bringen können.
quelle
Verwenden Sie DOMDocumentFragment
quelle
Es ist 2017 und für diese Frage 2011 mag ich keine der Antworten. Viele Regex, große Klassen, loadXML etc ...
Einfache Lösung, die die bekannten Probleme löst:
Einfach, einfach, solide, schnell. Dieser Code funktioniert in Bezug auf HTML-Tags und Codierung wie:
Wenn jemand einen Fehler findet, sagen Sie bitte, ich werde diesen selbst verwenden.
Bearbeiten , Andere gültige Optionen, die fehlerfrei funktionieren (sehr ähnlich zu den bereits angegebenen):
Sie können selbst Körper hinzufügen, um seltsame Dinge auf dem Fell zu verhindern.
Dreißig Option:
quelle
mb_convert_encoding
und stattdessen entsprechend hinzufügen<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body>
und ändernsubstr
. Übrigens ist Ihre Lösung hier die eleganteste. Upvoted.Ich bin etwas spät im Club, wollte aber keine Methode teilen, von der ich erfahren habe. Zunächst habe ich die richtigen Versionen für loadHTML (), um diese netten Optionen zu akzeptieren, aber
LIBXML_HTML_NOIMPLIED
auf meinem System nicht funktioniert. Auch Benutzer melden Probleme mit dem Parser (zum Beispiel hier und hier ).Die Lösung, die ich erstellt habe, ist ziemlich einfach.
Zu ladendes HTML wird in ein
<div>
Element eingefügt, sodass es einen Container enthält, der alle zu ladenden Knoten enthält.Dann wird dieses Containerelement aus dem Dokument entfernt (aber das DOMElement davon existiert noch).
Dann werden alle direkten untergeordneten Elemente aus dem Dokument entfernt. Dazu gehören jede hinzugefügt
<html>
,<head>
und<body>
Tags (effektivLIBXML_HTML_NOIMPLIED
Option) sowie die<!DOCTYPE html ... loose.dtd">
Erklärung (effektivLIBXML_HTML_NODEFDTD
).Dann werden alle direkten untergeordneten Elemente des Containers erneut zum Dokument hinzugefügt und es kann ausgegeben werden.
XPath funktioniert wie gewohnt. Achten Sie jedoch darauf, dass jetzt mehrere Dokumentelemente vorhanden sind, also kein einziger Stammknoten:
quelle
Keine der anderen Lösungen zum Zeitpunkt dieses Schreibens (Juni 2012) konnte meine Anforderungen vollständig erfüllen, daher habe ich eine geschrieben, die die folgenden Fälle behandelt:
<doctype>
,<xml>
,<html>
,<body>
, und<p>
Tags)<p>
alleine eingewickelt .Hier ist eine Lösung, die diese Probleme behebt:
Ich habe auch einige Tests geschrieben, die in derselben Klasse leben würden:
Sie können überprüfen, ob es für Sie funktioniert.
DomDocumentWorkaround::testAll()
gibt dies zurück:quelle
Okay, ich habe eine elegantere Lösung gefunden, aber es ist einfach langweilig:
Okay, hoffentlich lässt dies nichts aus und hilft jemandem?
quelle
Verwenden Sie diese Funktion
quelle
preg_replace
weil die Verwendung von DOMDocument-basierten Methoden zum Entfernen der HTML- und Body-Tags die UTF-8-Codierung nichtWenn die von Alessandro Vendruscolo beantwortete Flags-Lösung nicht funktioniert, können Sie Folgendes versuchen:
$bodyTag
enthält Ihren vollständig verarbeiteten HTML-Code ohne all diese HTML-Wraps, mit Ausnahme des<body>
Tags, das die Wurzel Ihres Inhalts darstellt. Dann können Sie einen regulären Ausdruck oder eine Trimmfunktion verwenden, um ihn aus der endgültigen Zeichenfolge (nachsaveHTML
) zu entfernen, oder, wie im obigen Fall, alle seine Kinder durchlaufen, ihren Inhalt in einer temporären Variablen speichern$finalHtml
und ihn zurückgeben (was ich glaube) sicherer).quelle
Ich habe Probleme damit auf RHEL7 mit PHP 5.6.25 und LibXML 2.9. (Altes Zeug im Jahr 2018, ich weiß, aber das ist Red Hat für dich.)
Ich habe festgestellt, dass die von Alessandro Vendruscolo vorgeschlagene vielbeachtete Lösung den HTML- Code durch Neuanordnung von Tags zerstört. Dh:
wird:
Dies gilt für beide Optionen, die er Ihnen vorschlägt:
LIBXML_HTML_NOIMPLIED
undLIBXML_HTML_NODEFDTD
.Die von Alex vorgeschlagene Lösung reicht zur Hälfte aus, funktioniert jedoch nicht, wenn
<body>
mehr als ein untergeordneter Knoten vorhanden ist.Die Lösung, die für mich funktioniert, ist die folgende:
Um das DOMDocument zu laden, verwende ich zunächst:
Um das Dokument nach dem Massieren des DOMDocument zu speichern, verwende ich:
Ich bin der erste, der zustimmt, dass dies keine sehr elegante Lösung ist - aber es funktioniert.
quelle
Das Hinzufügen des
<meta>
Tags löst das Fixierungsverhalten von ausDOMDocument
. Das Gute daran ist, dass Sie dieses Tag überhaupt nicht hinzufügen müssen. Wenn Sie keine Codierung Ihrer Wahl verwenden möchten, übergeben Sie sie einfach als Konstruktorargument.http://php.net/manual/en/domdocument.construct.php
Ausgabe
Danke an @Bart
quelle
Ich hatte auch diese Anforderung und mochte die Lösung, die Alex oben gepostet hat. Es gibt jedoch einige Probleme: Wenn das
<body>
Element mehr als ein untergeordnetes Element enthält, enthält das resultierende Dokument nur das erste untergeordnete Element von<body>
, nicht alle. Außerdem brauchte ich das Strippen, um die Dinge bedingt zu behandeln - nur wenn Sie ein Dokument mit den HTML-Überschriften hatten. Also habe ich es wie folgt verfeinert. Anstatt es zu entfernen<body>
, habe ich es in a umgewandelt<div>
und die XML-Deklaration und entfernt<html>
.quelle
Ähnlich wie bei anderen Mitgliedern schwelgte ich zuerst in der Einfachheit und unglaublichen Kraft der Antwort von @Alessandro Vendruscolo. Die Fähigkeit, einfach einige markierte Konstanten an den Konstruktor zu übergeben, schien zu gut, um wahr zu sein. Für mich war es. Ich habe die richtigen Versionen von LibXML und PHP, unabhängig davon, wie das HTML-Tag zur Knotenstruktur des Document-Objekts hinzugefügt wird.
Meine Lösung hat viel besser funktioniert als die ...
Flaggen oder ....
Knotenentfernung, die ohne strukturierte Reihenfolge im DOM chaotisch wird. Wiederum haben Codefragmente keine Möglichkeit, die DOM-Struktur vorzugeben.
Ich habe diese Reise begonnen, um einen einfachen Weg zu finden, wie DQuery DOM-Traversal durchführt, oder zumindest auf eine Art und Weise, bei der ein strukturierter Datensatz entweder einfach verknüpft, doppelt verknüpft oder mit einem Baum verknüpft ist. Es war mir egal, wie lange ich eine Zeichenfolge wie HTML analysieren konnte und auch die erstaunliche Leistung der Eigenschaften der Knotenentitätsklasse hatte, die ich unterwegs verwenden konnte.
Bisher hat mich DOMDocument Object verlassen ... Wie bei vielen anderen Programmierern scheint es ... Ich weiß, dass ich in dieser Frage viel Frust gesehen habe, seit ich ENDLICH ... (nach ungefähr 30 Stunden Versuch und Misserfolg) Typprüfung) Ich habe einen Weg gefunden, alles zu bekommen. Ich hoffe das hilft jemandem ...
Zunächst einmal bin ich zynisch gegenüber ALLEN ... lol ...
Ich wäre ein Leben lang gegangen, bevor ich jemandem zugestimmt hätte, dass in diesem Anwendungsfall ohnehin eine Klasse von Drittanbietern benötigt wird. Ich war und bin kein Fan von Klassenstrukturen von Drittanbietern, aber ich bin auf einen großartigen Parser gestoßen. (Ungefähr 30 Mal in Google, bevor ich nachgab. Fühlen Sie sich also nicht allein, wenn Sie es vermieden haben, weil es in irgendeiner Weise inoffiziell lahm aussah ...)
Wenn Sie Codefragmente verwenden und den Code sauber und vom Parser in keiner Weise beeinflusst benötigen, ohne dass zusätzliche Tags verwendet werden, verwenden Sie simplePHPParser .
Es ist erstaunlich und verhält sich sehr ähnlich wie JQuery. Ich habe nicht oft beeindruckt, aber diese Klasse verwendet viele gute Tools und ich hatte noch keine Analysefehler. Ich bin ein großer Fan davon, das tun zu können, was diese Klasse tut.
Die Dateien zum Herunterladen finden Sie hier , die Startanweisungen hier und die API hier . Ich empfehle dringend, diese Klasse mit ihren einfachen Methoden zu verwenden, die auf
.find(".className")
die gleiche Weise wie eine JQuery-Suchmethode verwendet werden können, oder sogar mit bekannten Methoden wiegetElementByTagName()
odergetElementById()
...Wenn Sie einen Knotenbaum in dieser Klasse speichern, wird überhaupt nichts hinzugefügt. Sie können einfach sagen
$doc->save();
und es gibt den gesamten Baum ohne viel Aufhebens in eine Zeichenfolge aus.Ich werde diesen Parser jetzt in Zukunft für alle Projekte ohne Bandbreite verwenden.
quelle
Ich habe PHP 5.3 und die Antworten hier haben bei mir nicht funktioniert.
$doc->replaceChild($doc->firstChild->firstChild->firstChild, $doc->firstChild);
Ersetzte das gesamte Dokument nur durch das erste Kind, ich hatte viele Absätze und nur der erste wurde gespeichert, aber die Lösung gab mir einen guten Ausgangspunkt, um etwas zu schreiben, ohneregex
einige Kommentare zu hinterlassen, und ich bin mir ziemlich sicher, dass dies verbessert werden kann, aber wenn Jemand hat das gleiche Problem wie ich, es kann ein guter Ausgangspunkt sein.Dann könnten wir es so verwenden:
Beachten Sie, dass a
appendChild
akzeptiert wird,DOMNode
sodass wir keine neuen Elemente erstellen müssen. Wir können nur vorhandene Elemente wiederverwenden, die implementiertDOMNode
werden.DOMElement
Dies kann wichtig sein, um den Code bei der Bearbeitung mehrerer HTML / XML-Dokumente "vernünftig" zu haltenquelle
LIBXML_HTML_NOIMPLIED
da es das nur teilweise tut. Das Entfernen des Doctype ist effektivLIBXML_HTML_NODEFDTD
.Ich bin auf dieses Thema gestoßen, um einen Weg zu finden, HTML-Wrapper zu entfernen. Die Verwendung
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
funktioniert hervorragend, aber ich habe ein Problem mit utf-8. Nach viel Mühe fand ich eine Lösung. Ich poste es unten für jeden, der das gleiche Problem hat.Das Problem verursacht wegen
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Das Problem:
Lösung 1:
Lösung 2:
quelle
Ich habe 3 Probleme mit dem
DOMDocument
Unterricht.1- Diese Klasse lädt HTML mit ISO-Codierung und utf-8-Zeichen, die in der Ausgabe nicht angezeigt werden.
2- Auch wenn wir geben
LIBXML_HTML_NOIMPLIED
Flag loadhtml Methode, bis unsere Eingabe html kein Root - Tag enthält, wird es nicht Parse richtig sein.3- Diese Klasse betrachtet die HTML5-Tags als ungültig.
Also habe ich diese Klasse überschrieben, um diese Probleme zu lösen, und einige der Methoden geändert.
Jetzt benutze ich
DOMEditor
stattDOMDocument
und es hat bisher gut für mich funktioniertquelle
Ich bin auch auf dieses Problem gestoßen.
Leider fühlte ich mich mit einer der in diesem Thread bereitgestellten Lösungen nicht wohl, also ging ich zu einer, die mich zufriedenstellte.
Folgendes habe ich erfunden und es funktioniert ohne Probleme:
Im Wesentlichen funktioniert es ähnlich wie die meisten hier bereitgestellten Lösungen, aber anstatt manuelle Arbeit zu leisten, verwendet es den xpath-Selektor, um alle Elemente im Körper auszuwählen und ihren HTML-Code zu verketten.
quelle
descendant-or-self::body/p/*
.Mein Server hat PHP 5.3 und kann diese Optionen nicht aktualisieren
sind nicht für mich.
Um dies zu lösen, fordere ich die SaveXML-Funktion auf, das Body-Element zu drucken und dann einfach den "body" durch "div" zu ersetzen.
Hier ist mein Code, hoffe er hilft jemandem:
Das utf-8 dient der hebräischen Unterstützung.
quelle
Die Antwort von Alex ist korrekt, kann aber auf leeren Knoten folgenden Fehler verursachen:
Hier kommt mein kleiner Mod:
Das Hinzufügen von trim () ist auch eine gute Idee, um Leerzeichen zu entfernen.
quelle
Ich vielleicht zu spät. Aber vielleicht hat jemand (wie ich) noch dieses Problem.
Also hat keines der oben genannten für mich funktioniert. Da $ dom-> loadHTML auch offene Tags schließt, fügen Sie nicht nur HTML- und Body-Tags hinzu.
Das Hinzufügen eines <div> -Elements funktioniert bei mir nicht, da ich manchmal 3-4 nicht geschlossene div im HTML-Teil mag.
Meine Lösung:
1.) Fügen Sie zum Schneiden einen Marker hinzu und laden Sie dann das HTML-Stück
2.) Machen Sie mit dem Dokument, was Sie wollen.
3.) Speichern Sie HTML
4.) Bevor Sie es zurückgeben, entfernen Sie <p> </ p> -Tags vom Marker. Seltsamerweise erscheint es nur auf [MARK], nicht aber auf [/ MARK] ...!?
5.) Entfernen Sie alles vor und nach dem Marker
6.) gib es zurück
Es wäre viel einfacher, wenn LIBXML_HTML_NOIMPLIED für mich funktionieren würde. Es sollte, aber es ist nicht. PHP 5.4.17, libxml Version 2.7.8.
Ich finde es wirklich seltsam, ich benutze den HTML-DOM-Parser und um dieses "Ding" zu reparieren, muss ich Regex verwenden ... Der springende Punkt war, keinen Regex zu verwenden;)
quelle
< div >< div > ... < /div >
. Ich suche immer noch nach Lösungen.Für jeden, der Drupal verwendet, gibt es eine integrierte Funktion, um dies zu tun:
https://api.drupal.org/api/drupal/modules!filter!filter.module/function/filter_dom_serialize/7.x
Code als Referenz:
quelle
Sie können ordentlich mit Show-Body-only verwenden:
Aber denken Sie daran: Entfernen Sie ordentlich einige Tags wie Font Awesome-Symbole: Probleme beim Einrücken von HTML (5) mit PHP
quelle
quelle
Diese Bibliothek erleichtert das Durchlaufen / Ändern des DOM und sorgt auch dafür, dass die Doctype / HTML-Wrapper für Sie entfernt werden:
https://github.com/sunra/php-simple-html-dom-parser
quelle