recorrer - Error tolerante HTML/XML/SGML análisis en PHP
recorrer xml php (6)
Tengo un montón de documentos heredados que son similares a HTML. Al igual que en, se ven como HTML, pero tienen etiquetas adicionales compuestas que no son parte de HTML
<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>
Necesito analizar estos archivos. PHP es la única herramienta disponible. Los documentos no se acercan a XML bien formado.
Mi idea original era usar los métodos loadHTML en PHPs DOMDocument. Sin embargo, estos métodos se ahogan en las etiquetas HTML de creación y se rehusarán a analizar la cadena / archivo.
$oDom = new DomDocument();
$oDom->loadHTML("<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>");
//gives us
DOMDocument::loadHTML() [function.loadHTML]: Tag pseud-template invalid in Entity, line: 1 occured in ....
La única solución que he podido encontrar es preprocesar los archivos con funciones de reemplazo de cadenas que eliminarán las etiquetas no válidas y las reemplazarán con una etiqueta HTML válida (tal vez un lapso con una identificación del nombre de la etiqueta).
¿Hay una solución más elegante? ¿Una forma de informar a DOMDocument sobre las etiquetas adicionales que se consideran válidas? ¿Existe una clase / objeto de análisis de HTML robusto y diferente para PHP?
(Si no es obvio, no considero que las expresiones regulares sean una solución válida aquí)
Actualización : la información en las etiquetas falsas es parte del objetivo aquí, por lo que algo como Tidy no es una opción. Además, estoy buscando algo que haga cierto nivel, si no todo, de limpieza de buena formación para mí, que es la razón por la que estaba buscando el método loadHTML de DomDocument en primer lugar.
@Twan No necesita una DTD para DOMDocument para analizar XML personalizado. Simplemente use DOMDocument->load()
, y mientras el XML esté bien formado, puede leerlo.
Una vez que los archivos estén bien formados, es cuando puede comenzar a analizar los analizadores XML, antes de que sea SOL Lok, Alejo dijo, podría ver HTML TIDY , pero parece que eso es específico de HTML, y yo no No sé cómo funcionaría con sus elementos personalizados.
No considero que las expresiones regulares sean una solución válida aquí
Hasta que tenga buena formación, esa podría ser su única opción. Una vez que llevas los documentos a esa etapa, entonces estás limpio con las funciones DOM.
Eche un vistazo al analizador en el puerto PHP Fit. El código está limpio y fue diseñado originalmente para cargar el sucio HTML guardado por Word. Está configurado para extraer tablas, pero se puede adaptar fácilmente.
Puedes ver la fuente aquí: http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/Parser.phps
La prueba unitaria le mostrará cómo usarlo: http://gerd.exit0.net/pat/PHPFIT/PHPFIT-0.1.0/test/parser.phps
Me pregunto si pasar el HTML "malo" a través de HTML Tidy podría ayudar como primer paso. Puede valer la pena mirar, si puede conseguir que el documento esté bien formado, tal vez podría cargarlo como un archivo XML normal con DomDocument.
Mi solución rápida y sucia a este problema fue ejecutar un bucle que coincida con mi lista de etiquetas personalizadas con una expresión regular. La expresión regular no detecta las etiquetas que tienen otra etiqueta personalizada interna dentro de ellas.
Cuando hay una coincidencia, se llama a una función para procesar esa etiqueta y devuelve el "HTML procesado". Si esa etiqueta personalizada estaba dentro de otra etiqueta personalizada, el padre no tiene hijos por el hecho de que se insertó HTML real en lugar del elemento secundario, y la expresión regular corresponderá y se procesará en la siguiente iteración del ciclo.
El ciclo finaliza cuando no hay etiquetas personalizadas sin hijos para que coincidan. En general, es iterativo (un ciclo while) y no recursivo.
@Alan Storm
Tu comentario sobre mi otra respuesta me hizo pensar:
Cuando carga un archivo HTML con DOMDocument, parece que hace un cierto nivel de limpieza: bien formado, PERO requiere que todas sus etiquetas sean legítimas etiquetas HTML. Estoy buscando algo que haga lo primero, pero no lo último. (Alan Storm)
Ejecute una expresión regular (¡lo siento!) Sobre las etiquetas, y cuando encuentre una que no sea un elemento HTML válido, reemplácela con un elemento válido que sepa que no existe en ninguno de los documentos (le viene a la mente un blink
. .), y darle un valor de atributo con el nombre del elemento ilegal, para que pueda volver a cambiarlo después. p.ej:
$code = str_replace("<pseudo-tag>", "<blink rel=/"pseudo-tag/">", $code);
// and then back again...
$code = preg_replace(''<blink rel="(.*?)">'', ''</1>'', $code);
obviamente ese código no funcionará, ¿pero entiendes la idea general?
Puede suprimir las advertencias con libxml_use_internal_errors
, mientras carga el documento. P.ej.:
libxml_use_internal_errors(true);
$doc = new DomDocument();
$doc->loadHTML("<strong>This is an example of a <pseud-template>fake tag</pseud-template></strong>");
libxml_use_internal_errors(false);
Si, por algún motivo, necesita acceder a las advertencias, use libxml_get_errors