2012-05-23 22 views
16

Estoy intentando analizar el código HTML con DOMDocument, hacer cosas como cambios en él, luego volver a montarlo en una cadena que envíe a la salida.¿Cómo hacer que HTML5 funcione con DOMDocument?

Pero hay algunos problemas en relación con el análisis, lo que significa que lo que envío a DOMDocument no siempre viene de vuelta en la misma forma :)

He aquí una lista:

  1. usando ->loadHTML:

    • formatea mi documento independientemente de las configuraciones preserveWhitespace y formatOutput (perdiendo espacios en blanco en el texto preformateado)
    • me da errores cuando tengo etiquetas html5 como <header>, <footer> etc. Pero pueden suprimirse, así que puedo vivir con esto.
    • produce marcado inconsistente - por ejemplo, si agrego un elemento <link ... /> (con una etiqueta de cierre automático), después de análisis sintáctico/saveHTML la salida será <link .. >
  2. usando ->loadXML:

    • codifica entidades como > desde <style> o <script> etiquetas: body > div se convierte en body &gt; div
    • todas las etiquetas se cierran de la misma manera, por ejemplo <meta ... /> se convierte en <meta...></meta>; pero esto se puede arreglar con una expresión regular.

no lo probé HTML5lib pero preferiría DOMDocument en lugar de un analizador personalizado por razones de rendimiento


Actualización:

Así como el Honeymonster menciona el uso de correcciones CDATA el problema principal con loadXML.

¿Hay alguna manera de evitar el cierre automático de todas las etiquetas HTML vacías además de un cierto conjunto, sin usar expresiones regulares?

Ahora mismo tengo:

$html = $dom->saveXML($node); 

$html = preg_replace_callback('#<(\w+)([^>]*)\s*/>#s', function($matches){ 

     // ignore only these tags 
     $xhtml_tags = array('br', 'hr', 'input', 'frame', 'img', 'area', 'link', 'col', 'base', 'basefont', 'param' ,'meta'); 

     // if a element that is not in the above list is empty, 
     // it should close like `<element></element>` (for eg. empty `<title>`) 
     return in_array($matches[1], $xhtml_tags) ? "<{$matches[1]}{$matches[2]} />" : "<{$matches[1]}{$matches[2]}></{$matches[1]}>"; 
}, $html); 

que trabaja pero también hará las sustituciones en el contenido CDATA, que no quiero ...

+3

¿Tiene un fragmento de prueba con el que podamos jugar? –

+0

¿Cómo sabes que html5lib es más lento que DOMDocument si ni siquiera lo intentaste? – Brad

+3

Supongo que porque está escrito en PHP ... DOMDocument es una extensión de PHP escrita en C – Alex

Respuesta

7

Desafortunadamente, o, posiblemente, afortunadamente, DOMDocument está diseñado para no tratar de conservar el formato del documento original. Esto es para facilitar el manejo del estado interno del analizador manteniendo todos los elementos del mismo estilo. La mayoría de los analizadores de Afaik crearán una representación en árbol en la memoria y no se preocuparán por el formato textual hasta que el usuario lo solicite.Esta es la razón por la cual las etiquetas auto cerradas se envían con etiquetas de cierre separadas. La buena noticia es que no importa.

En cuanto a las etiquetas de estilo y las etiquetas de secuencia de comandos que consiguen <> convertidos a &lt;&gt;, puede ser capaz de evitar la conversión rodeando el contenido del elemento en cuestión con las etiquetas CDATA recomendados de esta manera:

<style> 
    /*<![CDATA[*/ 
    body > div { 
     width: 50%; 
    } 
    /*]]>*/ 
</style> 

La comentario /* */ alrededor de las declaraciones cdata son para permitir a los clientes rotos que no conocen las secciones de cdata y en su lugar tratan las declaraciones como código CSS. Si solo está utilizando el documento internamente, puede omitir el entorno de comentarios /* */ y tener solo la declaración cdata. Puede encontrar problemas con los clientes rotos mencionados anteriormente si manipula el documento y luego lo envía al navegador sin verificar que se guarden los comentarios /* */; No estoy seguro si domdocument retendrá estos o no.

+1

wow no puedo creer que no haya pensado en usar CDATA :) gracias, eso resuelve muchos problemas con el analizador xml, que quería usar;) – Alex

12

Uso html5lib. Puede analizar html5 y producir un DOMDocument. Ejemplo:

require_once '/path/to/HTML5/Parser.php'; 
$dom = HTML5_Parser::parse('<html><body>...'); 

Documentation

+2

¿Pero html5lib puede guardar los documentos y devolver una cadena con el bonito formato? No vi eso en el código fuente. – Wiliam

-4

Cuando la inicialización DomDocument, haga lo siguiente:

$dom = new DOMDocument(5, 'UTF-8'); 
+1

Desafortunadamente, el parámetro de versión no hace referencia a la versión HTML. – nibra

4

Si quieres apoyar HTML5, no toque DOMDocument en absoluto.

actualmente la mejor opción parece ser https://github.com/Masterminds/html5-php

Anteriormente la mejor opción era https://github.com/html5lib/html5lib-php sino como la descripción dice, es "actualmente no mantenido". Y esto ha sido estado desde octubre de 2011, así que no estoy conteniendo la respiración.

No he usado html5-php en producción, así que no puedo proporcionar ninguna experiencia real sobre eso. He usado html5lib-php en producción y diría que está analizando correctamente los documentos bien formados, pero tiene errores inesperados con algunos errores de sintaxis simples. Por otro lado, parece implementar el algoritmo de agencia de adopción y algunos otros casos de esquina raros correctamente. Si todavía se mantuviera html5lib-php, aún así lo preferiría. Sin embargo, tal como están las cosas actualmente, preferiría usar html5-php y posiblemente ayudar a solucionar los errores restantes allí.

Cuestiones relacionadas