DOMDocument und PHP5
Felix Riesterer
- php
0 Jörg Reinholz0 molily0 tami0 Felix Riesterer0 tami
Liebe Mitlesende,
heute wollte ich folgenden HTML-Code in ein DOMDocument laden:
$html = '<!DOCTYPE html>
<html lang="%1$s">
<head>
<meta charset="utf-8" />
<title>%2$s</title>
<meta name="description" content="%3$s - %4$s" />
</head>
<body>
<main id="_top">
</main>
<nav>
</nav>
<header>
<a href="/"></a>
</header>
<footer>
</footer>
</body>
</html>'
$doc = new DOMDocument;
$doc->loadHTML($html); // Error-Log zeigt Fehler
Mein Error-Log zeigt an, dass DOMDocument die Elemente <main>, <nav>, <header> und <footer> nicht kennt. Wie kann ich mir da sicher sein, dass alles mit rechten Dingen zugeht? Oder soll ich einfach @$doc->loadHTML() notieren, damit diese Meldungen unterdrückt werden? Oder gibt es schlauere Wege, damit umzugehen?
Liebe Grüße,
Felix Riesterer.
http://www.php.net/manual/de/domdocument.load.php
und
http://www.php.net/manual/de/domdocument.loadhtml.php
verweisen auf:
http://www.php.net/manual/de/domdocument.loadhtml.php
Dort findet sich:
(die als Option übergebene Konstante) LIBXML_NOERROR unterdrückt Fehlerausgaben.
(die als Option übergebene Konstante) LIBXML_NOWARNING unterdrückt Warnungen.
Also würde etwas wie $doc->load('book.xml', LIBXML_NOERROR+LIBXML_NOWARNING) Fehler und Warnungen unterdrücken.
Ansonsten scheint es sich zu lohnen auch bei http://www.php.net/manual/de/ref.libxml.php nachzulesen.
Jörg Reinholz
Lieber Jörg Reinholz,
den Zusammenhang zwischen DOMDocument und libxml muss man erst einmal verstanden haben... OK!
Also würde etwas wie $doc->load('book.xml', LIBXML_NOERROR+LIBXML_NOWARNING) Fehler und Warnungen unterdrücken.
Tut es nicht. Aber das hier tut es:
[link:http://www.php.net/manual/de/function.libxml-use-internal-errors.php@title=libxml_use_internal_errors](true);
Vielen Dank für den Pointer!
Liebe Grüße,
Felix Riesterer.
Hallo!
dass DOMDocument die Elemente <main>, <nav>, <header> und <footer> nicht kennt. Wie kann ich mir da sicher sein, dass alles mit rechten Dingen zugeht?
Dessen kannst du dir nicht sicher sein.
DomDocument#loadHTML nutzt einen speziellen Parsingmodus von libxml2, das eigentlich ein XML-Parser ist. Das hat mit dem, was in Browsern vor sich geht und im HTML5-Standard beschrieben ist, reichlich wenig zu tun.
Besser einen vollwertigen HTML5-Parser verwenden, wenn möglich:
http://masterminds.github.io/html5-php/
Grüße
Mathias
Lieber molily,
Besser einen vollwertigen HTML5-Parser verwenden, wenn möglich:
http://masterminds.github.io/html5-php/
dieser HTML5-Parser ist noch im alpha-Stadium... sollte ich da allen Ernstes zugreifen? Lieber wäre mir in solchen Fällen, ich könnte alles in eine Datei übertragen, wie der Parser, den mir Tom mit simple_html_dom schon angeboten hatte.
Für den Moment bin ich zufrieden, wenn mein Code zumindest wohlgeformt von DOMDocument wieder ausgespuckt wird, denn nach XML-Kriterien kann das Teil doch hoffentlich TagSoup aufbereiten!?
Liebe Grüße,
Felix Riesterer.
Hallo,
dieser HTML5-Parser ist noch im alpha-Stadium... sollte ich da allen Ernstes zugreifen?
Er hat Unit-Tests und folgt dem HTML5-Standard. Für das HTML-Parsing von libxml2 existieren vermutlich Unit-Tests, aber er folgt m.W. keinem Standard (weder SGML noch XML noch HTML5).
Lieber wäre mir in solchen Fällen, ich könnte alles in eine Datei übertragen
Was heißt »in eine Datei übertragen«?
Tausende Zeilen Code in eine PHP-Datei zu schreiben ist eher ein Zeichen von schlechtem Code. Dem Code des HTML5-Parsers sieht man an, dass er modern ist: Er folgt aktuellen Coding-Guidelines, nutzt Namensräume und pro Klasse eine Datei, lässt sich mit dem Composer installieren. Klar, das ist aufwändiger Code, aber HTML-Parsing ist kein Kinderspiel.
wie der Parser, den mir Tom mit simple_html_dom schon angeboten hatte.
Es kommt darauf an, was für HTML-Code du verarbeiten willst. Bei einem HTML5-Parser ist genau definiert, was für ein DOM-Baum herauskommt. libxml2 hat einen eigenen Umgang mit Tagsoup, und simple_html_dom sieht wie ein dilettantischer Parser aus, der nicht einmal eine Finite State Machine nutzt, sondern teilweise reguläre Ausdrücke. Robust und technisch korrekt wäre ein HTML5-Parser, ein anderer mag aus praktischen Erwägungen besser sein.
Mathias
Lieber molily,
Er hat Unit-Tests und folgt dem HTML5-Standard. Für das HTML-Parsing von libxml2 existieren vermutlich Unit-Tests, aber er folgt m.W. keinem Standard (weder SGML noch XML noch HTML5).
also sagst Du in Klartext übersetzt: Konzeptionell und herstellungstechnisch ist er dem in der DOMDocument-Klasse verwendeten libxml2 offensichtlich überlegen.
Das kann ich Dir glauben. Das wäre tatsächlich ein Argument, dass ich das Teil einsetze.
Lieber wäre mir in solchen Fällen, ich könnte alles in eine Datei übertragen
Was heißt »in eine Datei übertragen«?
Soll heißen: Durch einen wie-auch-immer-Automatismus die einzelnen PHP-Dateien des Parser-Projektes in eine Datei "minifizieren", damit ich in meinem Projekt nur eine PHP-Datei "pflegen" und inkludieren muss.
Mir ist klar, dass für "open source" eine derart verunstaltete PHP-Datei nicht pflegbar oder sinnvoll debug-bar ist, aber bei JavaScript-Projekten verwendet man doch auch mitunter minifizierte (oder uglifizierte) Code-Dateien. Warum sollte ich mir aus dem Projekt nicht eine derartige Datei generieren? Noch schöner wäre, das Projekt hätte soetwas bereits fertig im Angebot. Wenn die aber lieber mit einem anderen Automatismus namens Composer arbeiten, dann muss der Vorteile haben, die sich mir noch nicht erschließen.
Tausende Zeilen Code in eine PHP-Datei zu schreiben ist eher ein Zeichen von schlechtem Code.
Das mache ich nur, wenn ich externe libs verwende, die ich nicht selbst pflege, sondern die ich plug&play-artig in mein Projekt einbinden will. Was sollte daran verwerflich sein?
Dem Code des HTML5-Parsers sieht man an, dass er modern ist: Er folgt aktuellen Coding-Guidelines, nutzt Namensräume und pro Klasse eine Datei, lässt sich mit dem Composer installieren.
Das mit dem Composer habe ich noch nicht verstanden. Meine PHP-Fähigkeiten haben mit PHP 4.3 angefangen. Danach habe ich mich (im Wesentlichen über Mitlesen im Forum) nach und nach an eine objektorientierte Schreibe bei PHP gewöhnt (in JS gelang mir das früher, das Ergebnis war der Artikel, bei dessen Veröffentlichung Du mir tatkräftig unter die Arme gegriffen hattest). Trotzdem bin ich noch weit von "aktuellen Coding-Guidelines" entfernt, und was "der Composer" ist, kann ich nur erahnen. Sicherlich ist es eine Art Mischung aus PHP-Autoloading und einer anderen Art des gezielten Inkludierens von benötigten Script-Dateien. Zeit müsste man haben, das alles selbst zu studieren, dann verstünde ich nicht nur, was der Composer ist, sondern könnte ihn vielleicht selbst in meinen Projekten einsetzen...
Klar, das ist aufwändiger Code, aber HTML-Parsing ist kein Kinderspiel.
"Die Class" darf gerne so umfangreich wie notwendig sein. In meinem Projekt will ich sie auf übersichtliche Art einbinden können, ohne dass mir mein eigener Code in dem ganzen Fremdbibliotheken-Krams untergeht. Ein bisschen fürchte ich, früher oder später den Wald vor lauter Bäumen nicht mehr zu sehen.
wie der Parser, den mir Tom mit simple_html_dom schon angeboten hatte.
[...] simple_html_dom sieht wie ein dilettantischer Parser aus, der nicht einmal eine Finite State Machine nutzt, sondern teilweise reguläre Ausdrücke. Robust und technisch korrekt wäre ein HTML5-Parser,
Schon klar. Ich habe damit experimentiert, um von meinen eigenen RegExen etwas weg zu kommen. Nun möchte ich weiter in der Richtung studieren, um mein aktuelles Projekt besser und robuster zu machen. Mein erster Überraschungsmoment war HTMLTidy, welches mit HTML5 nur Mist angestellt hat. Dann dachte ich, naja, nehme ich doch DOMDocument als "Ersatz" und baue meinen HTML-Code als echtes DOM. Dann kann DOMDocument dafür sorgen, dass das Ergebnis valide und wohlgeformt ist, dann kann ich auf HTMLTidy völlig verzichten. Sogar eine Art "pretty printing" hätte ich mit DOMDocument bekommen können... aber gut. Dann schaue ich in den von Dir vorgeschlagenen Parser.
Liebe Grüße,
Felix Riesterer.
Hallo,
Mir ist klar, dass für "open source" eine derart verunstaltete PHP-Datei nicht pflegbar oder sinnvoll debug-bar ist, aber bei JavaScript-Projekten verwendet man doch auch mitunter minifizierte (oder uglifizierte) Code-Dateien. Warum sollte ich mir aus dem Projekt nicht eine derartige Datei generieren? Noch schöner wäre, das Projekt hätte soetwas bereits fertig im Angebot. Wenn die aber lieber mit einem anderen Automatismus namens Composer arbeiten, dann muss der Vorteile haben, die sich mir noch nicht erschließen.
Vorab, ich bin kein PHP-Entwickler, vielleicht können sich andere dazu äußern.
Composer ist eine Dependency- bzw. Paket-Verwaltung, die vorzugsweise in größeren PHP-Projekten eingesetzt wird. Vergleichbar mit npm/package.json bei Node.js oder Gems/Bundler bei Ruby. So etwas will man letztlich haben, wenn man größere Projekte schreibt und Fremdcode einbindet. Zumindest bei Node und Ruby, worüber ich Aussagen machen kann, ist das Best Practice, es gibt keine größere Software ohne.
Bei JavaScript-Projekten fasst man Dateien nur zusammen, um sie über HTTP performant auszuliefern. Bei Node.js tut man das schon nicht, weil das Öffnen und Lesen von Dateien kein Bottleneck ist. Bei sämtlichen serverseitigen Sprachen ist das eher untypisch. Hier steht die Modularisierung und die Warbarkeit des Codes im Vordergrund. Das Class-Autoloading des Composers erwartet meines Wissens Klassen als einzelne Dateien in gewissen Verzeichnissen, da spielt auch der Namensraum rein. Insofern ist es gar nicht so einfach, PHP-Code zusammenzufassen.
Wenn du das Zusammenfassen in einer Datei für vorteilhaft erachtest, kannst du das natürlich tun, aber es verträgt sich schlecht mit aktuellen Coding-Konventionen, soweit ich das beurteilen kann.
Grüße
Mathias
Hi,
Soll heißen: Durch einen wie-auch-immer-Automatismus die einzelnen PHP-Dateien des Parser-Projektes in eine Datei "minifizieren", damit ich in meinem Projekt nur eine PHP-Datei "pflegen" und inkludieren muss.
Ich kann dir nur davon abraten. Minifizieren bringt im PHP-Umfeld eher weniger, da die Datei nicht an den Browser übertragen werden muss. Wenn du den Parsing-Aufwand des PHP-Parser reduzieren willst, nimm besser einen Cache wie APC oder OPCache (Standard seit PHP 5.5).
Ansonsten arbeitet die ganze Welt mit Composer. Die Gründe sind vielfältig: du beschreibst deine Abhängigkeiten deklarativ (statt imperativ den Code einfach in deinen Source-Tree reinzukopieren), es bietet einen Update-Mechanismus an, und es generiert dir einen Autoloader.
Kurz: es ist einfach der derzeitige Standard. Ich kann dir nur raten, dich damit auseinanderzusetzen.
Tausende Zeilen Code in eine PHP-Datei zu schreiben ist eher ein Zeichen von schlechtem Code.
Das mache ich nur, wenn ich externe libs verwende, die ich nicht selbst pflege, sondern die ich plug&play-artig in mein Projekt einbinden will. Was sollte daran verwerflich sein?
Damit zwingst du den Parser, immer die komplette Datei zu parsen. Würdest du einen Autoloader (z.B: den von composer) nutzen, dann würde der Parser immer nur die Dateien lesen, die auch tatsächlich gebraucht werden.
"Die Class" darf gerne so umfangreich wie notwendig sein. In meinem Projekt will ich sie auf übersichtliche Art einbinden können, ohne dass mir mein eigener Code in dem ganzen Fremdbibliotheken-Krams untergeht. Ein bisschen fürchte ich, früher oder später den Wald vor lauter Bäumen nicht mehr zu sehen.
Mach einfach folgendes:
1. Lade dir die composer.phar herunter (siehe Composer-Intro), am einfachsten erstmal in deinen Projektordner.
2. Lege in deinem Projektordner eine Datei an mit dem Namen composer.json und dem Inhalt
{
"require" : {
"masterminds/html5": "1.*"
},
}
3. Öffne eine Shell, gehe zu deinem Projektordner und tippe ein
"php composer.phar install"
4. In deinem Code, mach ein require(_once) auf vendor/autoload.php
5. Verwende einfach die Klassen, ohne weiteres require'n von irgendwelchen Dateien.
Willst du die Abhängigkeit irgendwann mal aktualisieren, dann tippe ein "composer update".
Weiterhin solltest du composer.phar und das vendor-Verzeichnis nicht in deine Versionsverwaltung einchecken.
Composer ist kein Hexenwerk, sondern recht einfach. In 90% der Fälle reichen dir oben genannte Befehle, und dir steht eine ganze neue Welt an Bibliotheken zur Verfügung. Kannst ja mal suchen auf https://packagist.org/.
Bis die Tage,
Matti
Lieber Matti Mäkitalo,
herzlichen Dank für Deine ausführlichen Erläuterungen und die aufmunternden Worte!
Wenn du den Parsing-Aufwand des PHP-Parser reduzieren willst, nimm besser einen Cache wie APC oder OPCache (Standard seit PHP 5.5).
Mir scheint, seit ich alle PHP-Dateien grundsätzlich inkludiere, ist die Server-Antwort auf meinem lokalen Testsystem (Apache/Ubuntu) wesentlich schneller, da für jeden Aufruf derselbe Compiler-Vorgang benötigt wird. Das lässt sich offensichtlich prima cachen...
Ansonsten arbeitet die ganze Welt mit Composer. Die Gründe sind vielfältig: du beschreibst deine Abhängigkeiten deklarativ (statt imperativ den Code einfach in deinen Source-Tree reinzukopieren), es bietet einen Update-Mechanismus an, und es generiert dir einen Autoloader.
Und was ist mit meinen eigenen Klassen?
Mach einfach folgendes:
- Lade dir die composer.phar herunter (siehe Composer-Intro), am einfachsten erstmal in deinen Projektordner.
- Lege in deinem Projektordner eine Datei an mit dem Namen composer.json und dem Inhalt
{
"require" : {
"masterminds/html5": "1.*"
},
}- Öffne eine Shell, gehe zu deinem Projektordner und tippe ein
"php composer.phar install"- In deinem Code, mach ein require(_once) auf vendor/autoload.php
- Verwende einfach die Klassen, ohne weiteres require'n von irgendwelchen Dateien.
Wie verhält es sich mit meinen eigenen Klassen, die ich als Helfer-Objekte definiert habe? Aktuell inkludiere ich die brav der Reihe nach. Eine Funktion filtert den Dateibaum nach "*.lib.php", um diese Dateien per "include" einzubinden. In jeder dieser "*.lib.php" wird jeweils eine Klasse definiert, die für sich alleine stehen kann. Untereinander gibt es keine Abhängigkeiten.
Von __autoload habe ich schon gelesen... mehr aber auch nicht. Warum sollte das für mein Projekt sinnvoll sein? Ich habe eine Methode "load_libraries" in meiner Singleton-Klasse (index.php), die oben genanntes Vorgehen umsetzt. Sollte ich das durch einen composer ersetzen? Wieviele MB an Script-Dateien soll mein Projekt denn am Ende groß sein? Ich hatte in meiner naiven Einfalt etwas um die 5MB erwartet...
Willst du die Abhängigkeit irgendwann mal aktualisieren, dann tippe ein "composer update".
Und ich muss mir sicher sein, dass die jeweiligen Paket-Informationen des Composers einerseits topaktuell sind, die tatsächlichen PHP-Dateien aus den originalen Quellen bezieht und dass nebenbei keine Malware mit hineininjiziert wird...?
Weiterhin solltest du composer.phar und das vendor-Verzeichnis nicht in deine Versionsverwaltung einchecken.
Klar... wenn ich mal endlich eines einsetzen würde.
Composer ist kein Hexenwerk, sondern recht einfach. In 90% der Fälle reichen dir oben genannte Befehle, und dir steht eine ganze neue Welt an Bibliotheken zur Verfügung. Kannst ja mal suchen auf https://packagist.org/.
Habe erst seit molilys Posting im Umfeld des HTML5-Projektes davon erfahren, dass es soetwas gibt. "Neue Welt" trifft es ziemlich präzise! Für mein Hobby-Projekt vielleicht totaler Overkill, vielleicht aber auch "best practice" (falls mal jemand neues übernehmen muss) - ich werde mir das einfach einmal genauer anschauen.
Liebe Grüße,
Felix Riesterer.
hi,
der composer nimmt die lediglich das loaden ab und ist updatebar. zend-framework bietet das auch, dass man erstmal die grundstruktur von einem script erstellt bekommt. das macht sinn, und nur das. es sei denn, du willst basteln und dabei lernen. "schlechter" und "älter" wird dein code dann aber immer sein ...;
mfg
tami
hi,
hi,
der composer nimmt die lediglich das loaden ab und ist updatebar. zend-framework bietet das auch, dass man erstmal die grundstruktur von einem script erstellt bekommt.
"Use Composer or Pyrus
Starting with Zend Framework 2, Zend Framework or any of its individual components may be installed via either Composer or Pyrus"
http://framework.zend.com/downloads
mfg
tami
Hi Felix,
Composer [...] generiert dir einen Autoloader.
Und was ist mit meinen eigenen Klassen?
Molily hat dir bereits einen Link gegeben zu PSR-0 bzw. dessen Nachfolger PSR-4. Lass dich von der Sprache nicht abschrecken, das Prinzip ist auch hier recht einfach.
PSR-0 (und PSR-4) gehen davon aus, dass es eine Übereinstimmung gibt zwischen Klassennamen (inkl. Namespace) und dem physischen Ort der Klasse. Wichtig: eine Klasse pro Datei.
Nehmen wir mal an, deine PHP-Dateien liegen alle unterhalb von src, einem gängigen Standard (davon ausgenommen natürlich dein Front-Controller, aber der wird ja auch nicht autoloaded).
Hast du bspw. eine Klasse Felix\DeinProjekt\MegaKlasse, dann sollte diese in der Datei src/Felix/DeinProjekt/MegaKlasse.php zu finden sein.
Solltest du keine Namespaces nutzen, sondern _ als Quasi-Namespaces nutzen (pre-5.3-style), dann kannst du das auch tun. Felix_DeinProjekt_MegaKlasse sollte dann ebenfalls am genannten Ort sein. Allerdings ist das nur PSR-0 - IMHO erlaubt PSR-4 diesen Stil nicht mehr. Im unten genannten Composer-Eintrag ist es mit PSR-0 aufgeführt.
Füge in die composer.json noch folgenden Eintrag ein:
"autoload": { "psr-0": { "": "src/" } }
Danach rufst du composer nochmal auf mit composer install (dadurch werden neue Packages installiert, falls du welche in require definiert hast, und der Autoloader wird neu geschrieben; wichtig: es werden keine Pakete aktualisiert).
Der Eintrag bewirkt, dass der Autoloader Klassen, deren Namespace mit "" beginnt, auch unterhalb von src sucht. Falls deine PHP-Dateien anderswo liegen, dann passt du das natürlich an.
Die vendor/autoload.php ist ja hoffentlich durch deine index.php eingebunden. Du kannst dann jederzeit auf jede beliebige Klasse zugreifen. Der Autoloader findet sie aufgrund der Konvention "Klassenname <-> physischer Ort der Datei" und bindet sie automatisch ein. Und das gilt eben auch für deinen Code. Das (entschuldige den Ausdruck) Geraffel mit dem Zusammenscannen des Projektbaums kannst du dir dann sparen.
Wie verhält es sich mit meinen eigenen Klassen, die ich als Helfer-Objekte definiert habe? Aktuell inkludiere ich die brav der Reihe nach. Eine Funktion filtert den Dateibaum nach "*.lib.php", um diese Dateien per "include" einzubinden. In jeder dieser "*.lib.php" wird jeweils eine Klasse definiert, die für sich alleine stehen kann. Untereinander gibt es keine Abhängigkeiten.
Das geht IMHO nicht mit PSR-0/4 zusammen. So flexibel ist PSR-0/4 nicht, dass dies erlaubt wäre - es ist auch gar nicht erwünscht, dass das geht. Man hat halt oben genannte Konvention festgelegt, und eigentlich halten sich die meisten halt daran. Vielleicht solltest du da auch irgendwann umsteigen?
Von __autoload habe ich schon gelesen... mehr aber auch nicht. Warum sollte das für mein Projekt sinnvoll sein? Ich habe eine Methode "load_libraries" in meiner Singleton-Klasse (index.php), die oben genanntes Vorgehen umsetzt. Sollte ich das durch einen composer ersetzen? Wieviele MB an Script-Dateien soll mein Projekt denn am Ende groß sein? Ich hatte in meiner naiven Einfalt etwas um die 5MB erwartet...
Die Nutzung von composer und einem Autoloader sind zwei verschiedene Dinge. Composer selber ist erstmal nur der Dependency/Package Manager und liefert einen Autoloader mit. Nutzen musst du diesen nicht.
__autoload solltest du dir wieder aus dem Kopf schlagen, das ist schon wieder veraltet. Das Problem mit __autoload war, dass man nur einen autoloader definieren durfte. Der Nachfolger ist spl_autoload_register. Das tolle ist nun, dass du mehrere definieren kannst - für Fremdbibliotheken den composer-Autoloader und zusätzlich deinen eigenen.
Willst du die Abhängigkeit irgendwann mal aktualisieren, dann tippe ein "composer update".
Und ich muss mir sicher sein, dass die jeweiligen Paket-Informationen des Composers einerseits topaktuell sind, die tatsächlichen PHP-Dateien aus den originalen Quellen bezieht und dass nebenbei keine Malware mit hineininjiziert wird...?
composer-update holt sich jeweils die aktuellen Versionen der Bibliotheken von packagist (oder einem anderen Paketserver - du kannst auch eigene definieren). Für das zweite gibt es keine fertige Lösung. IMHO gibt es noch keinen Signatur-Mechanismus auf packagist. Da hilft es dir nur, in die Quellen hineinzuschauen.
Für mein Hobby-Projekt vielleicht totaler Overkill, vielleicht aber auch "best practice" (falls mal jemand neues übernehmen muss) - ich werde mir das einfach einmal genauer anschauen.
Die Einstiegshürde ist recht niedrig. Einfach die composer.json anlegen, composer herunterladen und schon kannst du die einzelnen Komponenten nutzen. Und es beisst sich auch nichts, wenn du deinen Code anders strukturierst - du kannst halt nur den composer-autoloader nicht für deinen Nicht-PSR-0-Code nutzen.
Im Netz gibt es unzählige Blogeinträge zum Thema PSR-0/4 und composer. Schau dich da mal um. Die Erklärungen sind sicherlich besser, als jede, die ich beim ESC schauen auf der Couch abgeben könnte. :)
Bis die Tage,
Matti
Lieber molily,
Besser einen vollwertigen HTML5-Parser verwenden, wenn möglich:
http://masterminds.github.io/html5-php/
mit viel Mühe habe ich das Teil ohne Composer nun in mein Projekt integriert. Die Klasse wird korrekt inkludiert. Das war ein Stück Arbeit!
Nun konnte ich mit diesem Parser etwas experimentieren... und stelle fest, er erstellt ein hundsgewöhnliches DOMDocument. Inwiefern bin ich nun besser dran? Dahingehend, dass das DOM nach dem Parsen "garantiert" im Sinne des Browsers erstellt wurde und eben nicht nach den Regeln in libxml2? Hmm. War das die Arbeit wert?
Meine Lösung ohne jedwelchen Composer oder so:
// load HTML5 Parser (my dir: ./base/html5.lib)
$files = array(
// diese Einträge werden eigentlich dynamisch generiert
'./base/html5.lib/HTML5/Parser/CharacterReference.php',
'./base/html5.lib/HTML5/Parser/DOMTreeBuilder.php',
'./base/html5.lib/HTML5/Parser/EventHandler.php',
'./base/html5.lib/HTML5/Parser/FileInputStream.php',
'./base/html5.lib/HTML5/Parser/InputStream.php',
'./base/html5.lib/HTML5/Parser/ParseError.php',
'./base/html5.lib/HTML5/Parser/Scanner.php',
'./base/html5.lib/HTML5/Parser/StringInputStream.php',
'./base/html5.lib/HTML5/Parser/Tokenizer.php',
'./base/html5.lib/HTML5/Parser/TreeBuildingRules.php',
'./base/html5.lib/HTML5/Parser/UTF8Utils.php',
'./base/html5.lib/HTML5/Serializer/HTML5Entities.php',
'./base/html5.lib/HTML5/Serializer/OutputRules.php',
'./base/html5.lib/HTML5/Serializer/RulesInterface.php',
'./base/html5.lib/HTML5/Serializer/Traverser.php',
'./base/html5.lib/HTML5/Elements.php',
'./base/html5.lib/HTML5/Entities.php',
'./base/html5.lib/HTML5/Exception.php',
'./base/html5.lib/HTML5/InstructionProcessor.php'
);
// find out order for loading class files
$load_last = array('./base/html5.lib/HTML5.php');
foreach (file($load_last[0]) as $i => $line) {
// we need 'use HTML5\Some\Part\Foo\Bar\Baz ;'
if (substr_count($line, 'use HTML5')) {
$line = trim(preg_replace(
'~.*use (HTML5[^;]*);.*~',
'$1',
$line
));
$line = sprintf(
'./base/html5.lib/%s.php',
str_replace('\\', '/', $line)
);
if (!in_array($line, $load_last)) {
$load_last[] = $line;
}
}
}
foreach ($files as $f) {
if (!in_array($f, $load_last)) {
include $f;
}
}
foreach ($load_last as $f) {
include $f;
}
Dieser Code war notwendig, um die PHP-Dateien des HTML5-Parser-Projektes so zu inkludieren, dass keine Fehlermeldungen entstehen und die Klasse vollständig nutzbar ist.
Damit kann ich nun von meinen RegExen auf DOM-Operationen umrüsten. Cool! Man sollte wissen, dass ein DOMDocument eine DOMNode eines fremden DOMDocuments importieren kann. Damit ist es möglich, eine beliebige Node aus einem beliebigen anderen Dokument an beliebiger Stelle wieder einzupflanzen. Ganz wichtig! Hat ne gute Weile gedauert, bis ich das aus der PHP-Dokumentation heraus hatte! Nun kann ich meine HTML-Ausgabe an den Browser dieser DOM-Bibliothek überlassen, oder eben dem HTML5-Parser.
Liebe Grüße,
Felix Riesterer.
hi,
Lieber molily,
Besser einen vollwertigen HTML5-Parser verwenden, wenn möglich:
http://masterminds.github.io/html5-php/mit viel Mühe habe ich das Teil ohne Composer nun in mein Projekt integriert. Die Klasse wird korrekt inkludiert. Das war ein Stück Arbeit!
Nun konnte ich mit diesem Parser etwas experimentieren... und stelle fest, er erstellt ein hundsgewöhnliches DOMDocument. Inwiefern bin ich nun besser dran? Dahingehend, dass das DOM nach dem Parsen "garantiert" im Sinne des Browsers erstellt wurde und eben nicht nach den Regeln in libxml2? Hmm. War das die Arbeit wert?
Meine Lösung ohne jedwelchen Composer oder so:
// load HTML5 Parser (my dir: ./base/html5.lib)
$files = array(
// diese Einträge werden eigentlich dynamisch generiert
'./base/html5.lib/HTML5/Parser/CharacterReference.php',
'./base/html5.lib/HTML5/Parser/DOMTreeBuilder.php',
'./base/html5.lib/HTML5/Parser/EventHandler.php',
'./base/html5.lib/HTML5/Parser/FileInputStream.php',
'./base/html5.lib/HTML5/Parser/InputStream.php',
'./base/html5.lib/HTML5/Parser/ParseError.php',
'./base/html5.lib/HTML5/Parser/Scanner.php',
'./base/html5.lib/HTML5/Parser/StringInputStream.php',
'./base/html5.lib/HTML5/Parser/Tokenizer.php',
'./base/html5.lib/HTML5/Parser/TreeBuildingRules.php',
'./base/html5.lib/HTML5/Parser/UTF8Utils.php',
'./base/html5.lib/HTML5/Serializer/HTML5Entities.php',
'./base/html5.lib/HTML5/Serializer/OutputRules.php',
'./base/html5.lib/HTML5/Serializer/RulesInterface.php',
'./base/html5.lib/HTML5/Serializer/Traverser.php',
'./base/html5.lib/HTML5/Elements.php',
'./base/html5.lib/HTML5/Entities.php',
'./base/html5.lib/HTML5/Exception.php',
'./base/html5.lib/HTML5/InstructionProcessor.php'
);// find out order for loading class files
$load_last = array('./base/html5.lib/HTML5.php');foreach (file($load_last[0]) as $i => $line) {
// we need 'use HTML5\Some\Part\Foo\Bar\Baz ;'
if (substr_count($line, 'use HTML5')) {
$line = trim(preg_replace(
'~.use (HTML5[^;]);.*~',
'$1',
$line
));$line = sprintf(
'./base/html5.lib/%s.php',
str_replace('\', '/', $line)
);if (!in_array($line, $load_last)) {
$load_last[] = $line;
}
}
}foreach ($files as $f) {
if (!in_array($f, $load_last)) {
include $f;
}
}foreach ($load_last as $f) {
include $f;
}
>
> Dieser Code war notwendig, um die PHP-Dateien des HTML5-Parser-Projektes so zu inkludieren, dass keine Fehlermeldungen entstehen und die Klasse vollständig nutzbar ist.
Das sieht so kompliziert aus. Aus welcher Quelle hast Du die Dateien?
>
> Damit kann ich nun von meinen RegExen auf DOM-Operationen umrüsten. Cool! Man sollte wissen, dass ein DOMDocument eine [DOMNode eines fremden DOMDocuments importieren](http://de1.php.net/manual/en/domdocument.importnode.php) kann. Damit ist es möglich, eine beliebige Node aus einem beliebigen anderen Dokument an beliebiger Stelle wieder einzupflanzen. Ganz wichtig! Hat ne gute Weile gedauert, bis ich das aus der PHP-Dokumentation heraus hatte! Nun kann ich meine HTML-Ausgabe an den Browser dieser DOM-Bibliothek überlassen, oder eben dem HTML5-Parser.
Naja, Du kannst auch Knoten erzeugen und sie einhängen. Es ist doch egal, wo sie her kommen, wenn du einen hast, kannst du ihn irgendwo "montieren", oder?
Was mir immer noch nicht klar ist, aus welcher Quelle kommt Dein ursprünglicher HTML-Quelltext und warum funktioniert das nur mit einem speziellen Parser und nicht mit dem DOM-Funktionen von PHP allein? Oder habe ich das was übersehen?
mfg
tami
Lieber tami,
warum zitierst Du mein komplettes Posting...?
Das sieht so kompliziert aus. Aus welcher Quelle hast Du die Dateien?
Ich habe mir eine ZIP-Datei von der Github-Seite gezogen.
Was mir immer noch nicht klar ist, aus welcher Quelle kommt Dein ursprünglicher HTML-Quelltext
Ich verwende HTML-Dateien unterschiedlichster Bauart und Doctypes. Diese werden per Parser eingelesen und zu einem neuen HTML5-Dokument zusammengebaut. Es ist die Aufgabe des PHP-Scripts, validen und wohlgeformten HTML-Code zu erzeugen.
Damit nun alle HTML5-Elemente korrekt geparst werden, wollte ich einen leistungsfähigen Parser, der mir keine Fehler wirft, wenn ich Elemente wie <main>, <nav> und <section> verwende. Deshalb diese HTML5-Parser-Geschichte.
und warum funktioniert das nur mit einem speziellen Parser und nicht mit dem DOM-Funktionen von PHP allein?
Die werfen Fehler. Das kann nur bedeuten, dass der PHP-eigene Parser (molily verweist auf libxml2) ungenügend für die Aufgabe ist.
Oder habe ich das was übersehen?
Vielleicht molilys Posting?
Liebe Grüße,
Felix Riesterer.
hi,
Lieber tami,
warum zitierst Du mein komplettes Posting...?
Shit happens ;-). Außerdem dachte ich, da stünde noch was wichtiges drin für den Zusammenhang ...;
Oder habe ich das was übersehen?
Vielleicht molilys Posting?
Ja, das fiel mir dann auch ein.
Ich fragte mich vermutlich eher, ob diese Inkludiererei nicht einfacher geht.
mfg
tami
Hallo,
Ich fragte mich vermutlich eher, ob diese Inkludiererei nicht einfacher geht.
Natürlich geht das einfacher, nämlich mit Class-Autoloading. Dafür bringt der Composer eine Lösung mit:
https://getcomposer.org/doc/01-basic-usage.md#autoloading
Implementiert diese Spezifikation:
http://www.php-fig.org/psr/psr-4/
Alle ernstzunehmenden PHP-Projekte arbeiten meines Wissens so, oder mit einer anderen Dependency-Lösung, die Dependencies inkludiert. Ich würde es wenn möglich nutzen, denn das scheint Best Practice zu sein.
Mathias
hi,
Liebe Mitlesende,
heute wollte ich folgenden HTML-Code in ein DOMDocument laden:
Warum? ;-)
mfg
tami
Lieber tami,
heute wollte ich folgenden HTML-Code in ein DOMDocument laden:
Warum? ;-)
:)
Das ist das Grundgerüst-Skelett eines Webprojektes, welches in ein DOM umgewandelt werden soll, um es mit PHP zu "befüllen". Wenn ich auf diese Weise mein Dokument erstelle, verspreche ich mir davon, auf HTMLTidy verzichten zu können und trotzdem garantiert validen und wohlgeformten Code auszuliefern.
Liebe Grüße,
Felix Riesterer.
hi,
Lieber tami,
heute wollte ich folgenden HTML-Code in ein DOMDocument laden:
Warum? ;-)
:)
Das ist das Grundgerüst-Skelett eines Webprojektes, welches in ein DOM umgewandelt werden soll, um es mit PHP zu "befüllen". Wenn ich auf diese Weise mein Dokument erstelle, verspreche ich mir davon, auf HTMLTidy verzichten zu können und trotzdem garantiert validen und wohlgeformten Code auszuliefern.
Ok, dann aber hast Du die Erstellung des DOM ja in der Hand. Machst Du das zB. gleich mit PHP, hast Du zwangsläufg valides XML/HTML. Machst Du das mit Javascript, ebenfalls.
mfg
tami