¿Cómo se analiza y procesa HTML / XML en PHP?


¿Cómo se puede analizar HTML / XML y extraer información de él?




Answers


Extensiones XML nativas

Prefiero usar una de las extensiones XML nativas ya que vienen con PHP, generalmente son más rápidas que todas las librerías de terceros y me dan todo el control que necesito sobre el marcado.

DOM

La extensión DOM le permite operar en documentos XML a través de la API DOM con PHP 5. Es una implementación del Modelo de Objeto de Documento 3 del Núcleo Core del W3C, una interfaz neutral de plataforma y plataforma que permite que programas y scripts accedan y actualicen dinámicamente el contenido, la estructura y el estilo de los documentos.

DOM es capaz de analizar y modificar HTML del mundo real (roto) y puede hacer consultas XPath . Está basado en libxml .

Lleva un tiempo llegar a ser productivo con DOM, pero ese momento bien lo vale IMO. Dado que DOM es una interfaz independiente del idioma, encontrará implementaciones en muchos idiomas, por lo que si necesita cambiar su lenguaje de programación, es probable que ya sepa cómo usar la API DOM de ese idioma.

Se puede encontrar un ejemplo de uso básico en Asir el atributo href de un elemento A y se puede encontrar una descripción conceptual general en DOMDocument en php

La forma de usar la extensión DOM se ha cubierto ampliamente en , por lo que si decide usarla, puede estar seguro de que la mayoría de los problemas que encuentre se pueden resolver buscando / navegando en .

XMLReader

La extensión XMLReader es un analizador de extracción de XML. El lector actúa como un cursor hacia adelante en la secuencia de documentos y deteniéndose en cada nodo en el camino.

XMLReader, como DOM, se basa en libxml. No estoy al tanto de cómo desencadenar el módulo de analizador HTML, por lo que es probable que utilizar XMLReader para analizar HTML roto sea menos sólido que usar DOM, donde explícitamente puede indicarle que use el módulo de analizador HTML de libxml.

Se puede encontrar un ejemplo de uso básico al obtener todos los valores de las etiquetas h1 usando php

Analizador XML

Esta extensión le permite crear analizadores XML y luego definir manejadores para diferentes eventos XML. Cada analizador XML también tiene algunos parámetros que puede ajustar.

La biblioteca XML Parser también se basa en libxml e implementa un analizador sintáctico XML de estilo SAX . Puede ser una opción mejor para la administración de memoria que DOM o SimpleXML, pero será más difícil trabajar con ella que con el analizador de extracción implementado por XMLReader.

SimpleXml

La extensión SimpleXML proporciona un conjunto de herramientas muy simple y fácil de usar para convertir XML a un objeto que puede procesarse con selectores de propiedades e iteradores de matrices normales.

SimpleXML es una opción cuando sabes que el HTML es XHTML válido. Si necesita analizar HTML roto, ni siquiera considere SimpleXml porque se ahogará.

Se puede encontrar un ejemplo de uso básico en Un programa simple para nodo CRUD y valores de nodo de archivo xml y hay muchos ejemplos adicionales en el Manual de PHP .

Bibliotecas de terceros (basadas en libxml)

Si prefiere usar una lib de terceros, sugeriría usar una lib que realmente use DOM / libxml debajo en lugar de analizar cadenas.

FluentDom

FluentDOM proporciona una interfaz XML fluida similar a jQuery para DOMDocument en PHP. Los selectores se escriben en XPath o CSS (usando un convertidor de CSS a XPath). Las versiones actuales amplían las interfaces estándar de implementación de DOM y agregan características del estándar DOM Living. FluentDOM puede cargar formatos como JSON, CSV, JsonML, RabbitFish y otros. Se puede instalar a través de Composer.

HtmlPageDom

Wa72 \ HtmlPageDom` es una biblioteca PHP para facilitar la manipulación de documentos HTML usando Requiere que DomCrawler de los componentes Symfony2 atraviese el árbol DOM y lo amplía agregando métodos para manipular el árbol DOM de documentos HTML.

phpQuery (no actualizado por años)

phpQuery es una API del Modelo de Objetos de Documentos (DOM) accionada por el selector de CSS3 del lado del servidor, basada en la Biblioteca de JavaScript de jQuery, escrita en PHP5 y que proporciona una Interfaz de Línea de Comandos (CLI) adicional.

También vea: https://github.com/electrolinux/phpquery

Zend_Dom

Zend_Dom proporciona herramientas para trabajar con documentos DOM y estructuras. Actualmente, ofrecemos Zend_Dom_Query, que proporciona una interfaz unificada para consultar documentos DOM utilizando los selectores XPath y CSS.

QueryPath

QueryPath es una biblioteca PHP para manipular XML y HTML. Está diseñado para funcionar no solo con archivos locales, sino también con servicios web y recursos de bases de datos. Implementa gran parte de la interfaz jQuery (incluidos los selectores estilo CSS), pero está muy optimizada para el uso del lado del servidor. Se puede instalar a través de Composer.

fDOMDocument

fDOMDocument amplía el DOM estándar para usar excepciones en todas las ocasiones de errores en lugar de advertencias o avisos de PHP. También agregan varios métodos personalizados y accesos directos para mayor comodidad y para simplificar el uso de DOM.

sable / xml

sabre / xml es una biblioteca que envuelve y amplía las clases XMLReader y XMLWriter para crear un sistema de mapeo y patrón de diseño "xml to object / array" simple. Escribir y leer XML es de un solo paso y, por lo tanto, puede ser rápido y requerir poca memoria en archivos xml grandes.

FluidXML

FluidXML es una biblioteca PHP para manipular XML con una API concisa y fluida. Aprovecha XPath y el patrón de programación fluido para ser divertido y efectivo.

De terceros (no basado en libxml)

La ventaja de utilizar DOM / libxml es que obtiene un buen rendimiento de fábrica porque está basado en una extensión nativa. Sin embargo, no todas las libs de terceros siguen esta ruta. Algunos de ellos se enumeran a continuación

PHP Simple HTML DOM Parser

  • ¡Un analizador HTML DOM escrito en PHP5 + le permite manipular HTML de una manera muy fácil!
  • Requiere PHP 5+.
  • Admite HTML no válido.
  • Encuentra etiquetas en una página HTML con selectores al igual que jQuery.
  • Extrae contenido de HTML en una sola línea.

Generalmente no recomiendo este analizador. La base de código es horrible y el analizador en sí mismo es bastante lento y tiene mucha memoria. No todos los selectores de jQuery (como los selectores de niños ) son posibles. Cualquiera de las bibliotecas basadas en libxml debe superar esto fácilmente.

Analizador PHP Html

PHPHtmlParser es un analizador html simple y flexible que le permite seleccionar etiquetas usando cualquier selector css, como jQuery. El objetivo es ayudar en el desarrollo de herramientas que requieren una manera rápida y fácil de eliminar html, ¡ya sea válido o no! Este proyecto fue originalmente compatible con sunra / php-simple-html-dom-parser, pero el soporte parece haberse detenido, por lo que este proyecto es mi adaptación de su trabajo anterior.

De nuevo, no recomendaría este analizador. Es bastante lento con un alto uso de la CPU. Tampoco hay una función para borrar la memoria de los objetos DOM creados. Estos problemas se escalan particularmente con bucles anidados. La documentación en sí es incorrecta y está mal escrita, sin respuestas a las correcciones desde el 14 de abril de 16.

Ganon

  • Un tokenizador universal y un analizador de DOM HTML / XML / RSS
    • Capacidad de manipular elementos y sus atributos
    • Admite HTML no válido y UTF8
  • Puede realizar consultas avanzadas similares a CSS3 en elementos (como jQuery - espacios de nombres compatibles)
  • Un embellecedor de HTML (como HTML Tidy)
    • Minificar CSS y Javascript
    • Clasificar atributos, cambiar carácteres, corregir sangrías, etc.
  • Extensible
    • Analizar documentos utilizando devoluciones de llamada en función del carácter / ficha actual
    • Operaciones separadas en funciones más pequeñas para anularlas fácilmente
  • Rapido y facil

Nunca lo usé No puedo decir si es bueno.

HTML 5

Puede usar lo anterior para analizar HTML5, pero puede haber peculiaridades debido al marcado que HTML5 permite. Entonces, para HTML5, debe considerar el uso de un analizador dedicado, como

html5lib

Implementaciones de Python y PHP de un analizador HTML basado en la especificación WHATWG HTML5 para una máxima compatibilidad con los principales navegadores web de escritorio.

Es posible que veamos más analizadores dedicados una vez que finalice HTML5. También hay una entrada de blog de W3's titulada How-To para html 5 que merece la pena consultar.

Servicios web

Si no desea programar PHP, también puede usar servicios web. En general, encontré muy poca utilidad para estos, pero así soy yo y mis casos de uso.

YQL

El servicio web YQL permite a las aplicaciones consultar, filtrar y combinar datos de diferentes fuentes en Internet. Las sentencias YQL tienen una sintaxis similar a SQL, familiar para cualquier desarrollador con experiencia en bases de datos.

ScraperWiki .

La interfaz externa de ScraperWiki le permite extraer datos en la forma que desea para usar en la web o en sus propias aplicaciones. También puede extraer información sobre el estado de cualquier raspador.

Expresiones regulares

Por último y menos recomendado , puede extraer datos de HTML con expresiones regulares . En general, se desaconseja usar expresiones regulares en HTML.

La mayoría de los fragmentos que encontrará en la web para hacer coincidir el marcado son frágiles. En la mayoría de los casos, solo están trabajando para una pieza de HTML muy particular. Los cambios minúsculos de marcado, como agregar espacio en blanco en alguna parte, o agregar o cambiar atributos en una etiqueta, pueden hacer que la expresión regular falle cuando no está escrita correctamente. Debe saber lo que está haciendo antes de usar regex en HTML.

Los analizadores de HTML ya conocen las reglas sintácticas de HTML. Las expresiones regulares deben enseñarse para cada nueva expresión regular que escriba. Regex está bien en algunos casos, pero realmente depende de su caso de uso.

Puede escribir analizadores más confiables , pero escribir un analizador personalizado completo y confiable con expresiones regulares es una pérdida de tiempo cuando las bibliotecas mencionadas anteriormente ya existen y hace un trabajo mucho mejor en esto.

También vea Parsing Html The Cthulhu Way

Libros

Si quieres gastar algo de dinero, echa un vistazo a

No estoy afiliado con PHP Architect o los autores.




Pruebe Simple HTML DOM Parser

  • ¡Un analizador HTML DOM escrito en PHP 5+ que te permite manipular HTML de una manera muy fácil!
  • Requiere PHP 5+.
  • Admite HTML no válido.
  • Encuentra etiquetas en una página HTML con selectores al igual que jQuery.
  • Extrae contenido de HTML en una sola línea.
  • Descargar


Ejemplos:

Cómo obtener elementos HTML:

// Create DOM from URL or file
$html = file_get_html('http://www.example.com/');

// Find all images
foreach($html->find('img') as $element)
       echo $element->src . '<br>';

// Find all links
foreach($html->find('a') as $element)
       echo $element->href . '<br>';


Cómo modificar elementos HTML:

// Create DOM from string
$html = str_get_html('<div id="hello">Hello</div><div id="world">World</div>');

$html->find('div', 1)->class = 'bar';

$html->find('div[id=hello]', 0)->innertext = 'foo';

echo $html;


Extrae contenido de HTML:

// Dump contents (without tags) from HTML
echo file_get_html('http://www.google.com/')->plaintext;


Scraping Slashdot:

// Create DOM from URL
$html = file_get_html('http://slashdot.org/');

// Find all article blocks
foreach($html->find('div.article') as $article) {
    $item['title']     = $article->find('div.title', 0)->plaintext;
    $item['intro']    = $article->find('div.intro', 0)->plaintext;
    $item['details'] = $article->find('div.details', 0)->plaintext;
    $articles[] = $item;
}

print_r($articles);



Simplemente use DOMDocument-> loadHTML () y termine con esto. El algoritmo de análisis HTML de libxml es bastante bueno y rápido, y, contrariamente a la creencia popular, no se atraganta con HTML mal formado.




¿Por qué no deberías y cuándo deberías usar expresiones regulares?

En primer lugar, un nombre incorrecto común: Regexps no son para " analizar " HTML. Regexes sin embargo puede " extraer " datos. La extracción es para lo que están hechos. La principal desventaja de la extracción de HTML regex sobre los juegos de herramientas SGML adecuados o los analizadores sintácticos de línea de base es su esfuerzo sintáctico y fiabilidad variable.

Considere la posibilidad de hacer una expresión regular de extracción de HTML bastante fiable:

<a\s+class="?playbutton\d?[^>]+id="(\d+)".+?    <a\s+class="[\w\s]*title
[\w\s]*"[^>]+href="(http://[^">]+)"[^>]*>([^<>]+)</a>.+?

es mucho menos legible que un simple equivalente phpQuery o QueryPath:

$div->find(".stationcool a")->attr("title");

Sin embargo, hay casos de uso específicos donde pueden ayudar.

  • Muchas interfaces frontales de DOM no revelan comentarios de HTML <!-- , que sin embargo son a veces los anclajes más útiles para la extracción. En particular, las variaciones pseudo-HTML <$var> o los residuos SGML son fáciles de dominar con expresiones regulares.
  • A menudo, las expresiones regulares pueden guardar el procesamiento posterior. Sin embargo, las entidades HTML a menudo requieren cuidado manual.
  • Y, por último, para tareas extremadamente simples como extraer <img src = urls, de hecho son una herramienta probable. La ventaja de la velocidad con respecto a los analizadores SGML / XML principalmente viene a jugar para estos procedimientos de extracción muy básicos.

A veces, incluso es aconsejable /<!--CONTENT-->(.+?)<!--END-->/ un fragmento de HTML con las expresiones regulares /<!--CONTENT-->(.+?)<!--END-->/ y procesar el resto utilizando las /<!--CONTENT-->(.+?)<!--END-->/ más sencillas del analizador de HTML.

Nota: De hecho, tengo esta aplicación , donde empleo el análisis XML y las expresiones regulares de forma alternativa. La semana pasada, el análisis de PyQuery se rompió y la expresión regular aún funcionaba. Sí raro, y no puedo explicarlo yo mismo. Pero así sucedió.
Así que, por favor, no voten por consideraciones del mundo real, simplemente porque no coinciden con el regex = evil meme. Pero tampoco votemos esto demasiado. Es solo una nota al margen de este tema.




phpQuery y QueryPath son muy similares en la replicación de la API jQuery. Es también por eso que son dos de los enfoques más fáciles para analizar correctamente HTML en PHP.

Ejemplos de QueryPath

Básicamente, primero crea un árbol DOM cuestionable a partir de una cadena HTML:

 $qp = qp("<html><body><h1>title</h1>..."); // or give filename or URL

El objeto resultante contiene una representación de árbol completa del documento HTML. Se puede atravesar usando los métodos DOM. Pero el enfoque común es usar selectores de CSS como en jQuery:

 $qp->find("div.classname")->children()->...;

 foreach ($qp->find("p img") as $img) {
     print qp($img)->attr("src");
 }

En su mayoría, desea utilizar selectores de etiquetas simples #id y .class o DIV para ->find() . Pero también puede usar declaraciones XPath , que a veces son más rápidas. También los métodos típicos de jQuery como ->children() y ->text() y particularmente ->attr() simplifican la extracción de los fragmentos de código HTML correctos. (Y ya tienen sus entidades SGML decodificadas).

 $qp->xpath("//div/p[1]");  // get first paragraph in a div

QueryPath también permite inyectar nuevas etiquetas en la secuencia ( ->append ), y luego generar y embellecer un documento actualizado ( ->writeHTML ). No solo puede analizar HTML malformado, sino también varios dialectos XML (con espacios de nombres), e incluso extraer datos de microformatos HTML (XFN, vCard).

 $qp->find("a[target=_blank]")->toggleClass("usability-blunder");

.

phpQuery o QueryPath?

En general, QueryPath es más adecuado para la manipulación de documentos. Mientras que phpQuery también implementa algunos métodos pseudo AJAX (solo solicitudes HTTP) para parecerse más a jQuery. Se dice que phpQuery suele ser más rápido que QueryPath (debido a las pocas características generales).

Para obtener más información sobre las diferencias, consulte esta comparación en la máquina de retorno de tagbyte.org . (La fuente original desapareció, por lo que aquí hay un enlace de archivo de Internet. Sí, aún puede localizar páginas faltantes, personas).

Y aquí hay una introducción completa de QueryPath .

Ventajas

  • Simplicidad y Confiabilidad
  • Alternativas fáciles de usar ->find("a img, a object, div a")
  • Separación adecuada de datos (en comparación con la eliminación de expresiones regulares)



Simple HTML DOM es un gran analizador de código abierto:

simplehtmldom.sourceforge

Trata los elementos DOM de forma orientada a objetos, y la nueva iteración tiene una gran cobertura para el código no conforme. También hay algunas funciones geniales como las que vería en JavaScript, como la función "buscar", que devolverá todas las instancias de los elementos de ese nombre de etiqueta.

Lo he usado en varias herramientas, probándolo en muchos tipos diferentes de páginas web, y creo que funciona muy bien.




Un enfoque general que no he visto mencionar aquí es ejecutar HTML a través de Tidy , que se puede configurar para escupir XHTML garantizado válido. Luego puede usar cualquier biblioteca XML antigua en él.

Pero para su problema específico, debería echarle un vistazo a este proyecto: http://fivefilters.org/content-only/ - es una versión modificada del algoritmo de legibilidad , que está diseñado para extraer solo el contenido textual (no los encabezados) y pies de página) de una página.




Para 1a y 2: votaría por la nueva clase Symfony Componet DOMCrawler ( DomCrawler ). Esta clase permite consultas similares a los selectores de CSS. Echa un vistazo a esta presentación para ver ejemplos del mundo real: news-of-the-symfony2-world .

El componente está diseñado para funcionar de forma independiente y se puede usar sin Symfony.

El único inconveniente es que solo funcionará con PHP 5.3 o posterior.




Esto se conoce comúnmente como raspado de pantalla , por cierto. La biblioteca que he usado para esto es Simple HTML Dom Parser .




Hemos creado bastantes rastreadores para nuestras necesidades antes. Al final del día, usualmente son simples expresiones regulares las que hacen mejor las cosas. Si bien las bibliotecas enumeradas arriba son buenas por la razón por la que se crearon, si usted sabe lo que está buscando, las expresiones regulares son una forma más segura de hacerlo, ya que también puede manejar estructuras HTML / XHTML no válidas, que fallarían, si se cargaran a través de la mayoría de los analizadores.




Recomiendo PHP Simple HTML DOM Parser .

Realmente tiene buenas características, como:

foreach($html->find('img') as $element)
       echo $element->src . '<br>';



Esto suena como una buena descripción de la tarea de la tecnología W3C XPath . Es fácil expresar consultas como "devolver todos los atributos href en etiquetas img que están anidadas en elementos <foo><bar><baz> elements ". Como no soy un experto en PHP, no puedo decirte en qué forma puede estar disponible XPath. Si puede llamar a un programa externo para procesar el archivo HTML, debería poder usar una versión de línea de comando de XPath. Para una introducción rápida, vea http://en.wikipedia.org/wiki/XPath .







Sí, puedes usar simple_html_dom para este propósito. Sin embargo, he trabajado bastante con el simple_html_dom, particularmente para el web scrapping y he descubierto que es demasiado vulnerable. Hace el trabajo básico pero no lo recomendaré de todos modos.

Nunca utilicé curl para este propósito, pero lo que aprendí es que curl puede hacer el trabajo mucho más eficientemente y es mucho más sólido.

Por favor revisa este enlace: scraping-websites-with-curl




QueryPath es bueno, pero ten cuidado con el "estado de seguimiento" porque si no te das cuenta de lo que significa, puede significar que pierdes mucho tiempo de depuración tratando de averiguar qué sucedió y por qué el código no funciona.

Lo que significa es que cada llamada en el conjunto de resultados modifica el conjunto de resultados en el objeto, no se puede encadenar como en jquery donde cada enlace es un nuevo conjunto, usted tiene un conjunto único que es el resultado de su consulta y cada llamada de función modifica ese único conjunto.

para obtener un comportamiento parecido a un jquery, debe ramificarse antes de hacer una operación de filtro / modificación similar, lo que significa que reflejará lo que sucede en jquery mucho más de cerca.

$results = qp("div p");
$forename = $results->find("input[name='forename']");

$results ahora contiene el conjunto de resultados para la input[name='forename'] NO la consulta original "div p" esto me disparó mucho, lo que encontré fue que QueryPath rastrea los filtros y los hallazgos y todo lo que modifica tus resultados y almacena ellos en el objeto. necesitas hacer esto en cambio

$forename = $results->branch()->find("input[name='forname']")

entonces $results no serán modificados y usted puede reutilizar el conjunto de resultados una y otra vez, tal vez alguien con mucho más conocimiento puede aclarar esto un poco, pero es básicamente así por lo que he encontrado.




He escrito un analizador XML de propósito general que puede manejar fácilmente archivos GB. Está basado en XMLReader y es muy fácil de usar:

$source = new XmlExtractor("path/to/tag", "/path/to/file.xml");
foreach ($source as $tag) {
    echo $tag->field1;
    echo $tag->field2->subfield1;
}

Aquí está el repositorio github : XmlExtractor




Para HTML5 , html5 lib ha sido abandonado durante años. La única biblioteca HTML5 que puedo encontrar con una actualización reciente y registros de mantenimiento es html5-php, que acaba de llegar a beta 1.0 hace poco más de una semana.




Podría intentar usar algo como HTML Tidy para limpiar cualquier HTML "roto" y convertir el HTML a XHTML, que luego puede analizar con un analizador XML.




Creé una biblioteca llamada PHPPowertools / DOM-Query , que le permite rastrear documentos HTML5 y XML tal como lo hace con jQuery.

Debajo del capó, usa Symfony / DomCrawler para la conversión de selectores de CSS a selectores de XPath . Siempre usa el mismo DomDocument, incluso cuando pasa un objeto a otro, para garantizar un rendimiento decente.

Ejemplo de uso:

namespace PowerTools;

// Get file content
$htmlcode = file_get_contents('https://github.com');

// Define your DOMCrawler based on file string
$H = new DOM_Query($htmlcode);

// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query($H->select('body'));

// Passing a string (CSS selector)
$s = $H->select('div.foo');

// Passing an element object (DOM Element)
$s = $H->select($documentBody);

// Passing a DOM Query object
$s = $H->select( $H->select('p + p'));

// Select the body tag
$body = $H->select('body');

// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');

// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');

// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) {
    return $i . " - " . $val->attr('class');
});

// Append the following HTML to all site blocks
$siteblocks->append('<div class="site-center"></div>');

// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));

// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) {
    return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
});

// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();

// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');

// Wrap the site's footer within two nex selectors
$sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');

[...]

Métodos compatibles:

  1. Renombrado 'seleccionar', por razones obvias
  2. Se renombró 'void', ya que 'empty' es una palabra reservada en PHP

NOTA :

La biblioteca también incluye su propio autocargador de configuración cero para bibliotecas compatibles con PSR-0. El ejemplo incluido debería funcionar sin la configuración adicional. Alternativamente, puedes usarlo con compositor.




Otra opción que puedes probar es QueryPath . Está inspirado en jQuery, pero en el servidor en PHP y se usa en Drupal .




Hay muchas maneras de procesar DOM HTML / XML de las cuales la mayoría ya se han mencionado. Por lo tanto, no haré ningún intento de enumerarlos yo mismo.

Simplemente quiero agregar que personalmente prefiero usar la extensión DOM y por qué:

  • iit hace un uso óptimo de la ventaja de rendimiento del código C subyacente
  • es OO PHP (y me permite subclasificarlo)
  • es bastante bajo nivel (lo que me permite usarlo como una base no hinchada para un comportamiento más avanzado)
  • proporciona acceso a cada parte del DOM (a diferencia de, por ejemplo, SimpleXml, que ignora algunas de las características XML menos conocidas)
  • tiene una sintaxis utilizada para el rastreo DOM que es similar a la sintaxis utilizada en JavaScript nativo.

Y aunque echo de menos la posibilidad de usar selectores de CSS para DOMDocument , hay una manera bastante simple y conveniente de agregar esta característica: subclasificar el DOMDocument y agregar los métodos querySelectorAll y querySelector a su subclase.

Para analizar los selectores, recomiendo usar el componente minimalista CssSelector del framework Symfony . Este componente solo traduce los selectores de CSS a los selectores de XPath, que luego se pueden alimentar a un DOMXpath para recuperar la Nodelist correspondiente.

A continuación, puede utilizar esta subclase (aún de muy bajo nivel) como base para más clases de alto nivel, con la intención de, por ejemplo. analizar tipos muy específicos de XML o agregar más comportamiento similar a jQuery.

El siguiente código viene directamente de mi biblioteca DOM-Query y usa la técnica que describí.

Para el análisis de HTML:

namespace PowerTools;

use \Symfony\Component\CssSelector\CssSelector as CssSelector;

class DOM_Document extends \DOMDocument {
    public function __construct($data = false, $doctype = 'html', $encoding = 'UTF-8', $version = '1.0') {
        parent::__construct($version, $encoding);
        if ($doctype && $doctype === 'html') {
            @$this->loadHTML($data);
        } else {
            @$this->loadXML($data);
        }
    }

    public function querySelectorAll($selector, $contextnode = null) {
        if (isset($this->doctype->name) && $this->doctype->name == 'html') {
            CssSelector::enableHtmlExtension();
        } else {
            CssSelector::disableHtmlExtension();
        }
        $xpath = new \DOMXpath($this);
        return $xpath->query(CssSelector::toXPath($selector, 'descendant::'), $contextnode);
    }

    [...]

    public function loadHTMLFile($filename, $options = 0) {
        $this->loadHTML(file_get_contents($filename), $options);
    }

    public function loadHTML($source, $options = 0) {
        if ($source && $source != '') {
            $data = trim($source);
            $html5 = new HTML5(array('targetDocument' => $this, 'disableHtmlNsInDom' => true));
            $data_start = mb_substr($data, 0, 10);
            if (strpos($data_start, '<!DOCTYPE ') === 0 || strpos($data_start, '<html>') === 0) {
                $html5->loadHTML($data);
            } else {
                @$this->loadHTML('<!DOCTYPE html><html><head><meta charset="' . $encoding . '" /></head><body></body></html>');
                $t = $html5->loadHTMLFragment($data);
                $docbody = $this->getElementsByTagName('body')->item(0);
                while ($t->hasChildNodes()) {
                    $docbody->appendChild($t->firstChild);
                }
            }
        }
    }

    [...]
}

Consulte también Análisis de documentos XML con selectores de CSS por el creador de Symfony, Fabien Potencier, sobre su decisión de crear el componente CssSelector para Symfony y cómo usarlo.




XML_HTMLSax es bastante estable, incluso si ya no se mantiene. Otra opción podría ser canalizar HTML a través de Html Tidy y luego analizarlo con herramientas XML estándar.




El marco Symfony tiene paquetes que pueden analizar el HTML, y puede usar el estilo CSS para seleccionar los DOM en lugar de usar XPath .




Advanced Html Dom es una simple sustitución HTML DOM que ofrece la misma interfaz, pero está basada en DOM, lo que significa que no se producen ninguno de los problemas de memoria asociados.

También tiene soporte completo de CSS, incluidas las extensiones de jQuery .




Con FluidXML puede consultar e iterar XML usando XPath y selectores de CSS .

$doc = fluidxml('<html>...</html>');

$title = $doc->query('//head/title')[0]->nodeValue;

$doc->query('//body/p', 'div.active', '#bgId')
        ->each(function($i, $node) {
            // $node is a DOMNode.
            $tag   = $node->nodeName;
            $text  = $node->nodeValue;
            $class = $node->getAttribute('class');
        });

https://github.com/servo-php/fluidxml




Hay varias razones para no analizar HTML por expresiones regulares. Pero, si tiene control total de qué HTML se generará, entonces puede hacerlo con expresiones regulares simples.

Arriba, es una función que analiza HTML por expresión regular. Tenga en cuenta que esta función es muy sensible y exige que el HTML obedezca ciertas reglas, pero funciona muy bien en muchos escenarios. Si desea un analizador simple y no desea instalar bibliotecas, pruebe esto:

function array_combine_($keys, $values) {
    $result = array();
    foreach ($keys as $i => $k) {
        $result[$k][] = $values[$i];
    }
    array_walk($result, create_function('&$v', '$v = (count($v) == 1)? array_pop($v): $v;'));

    return $result;
}

function extract_data($str) {
    return (is_array($str))
        ? array_map('extract_data', $str)
        : ((!preg_match_all('#<([A-Za-z0-9_]*)[^>]*>(.*?)</\1>#s', $str, $matches))
            ? $str
            : array_map(('extract_data'), array_combine_($matches[1], $matches[2])));
}

print_r(extract_data(file_get_contents("http://www.google.com/")));



JSON y matriz de XML en tres líneas:

$xml = simplexml_load_string($xml_string);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

Ta da!