Obtener elementos DOM por nombre de clase
Estoy usando PHP DOM y estoy tratando de obtener un elemento dentro de un nodo DOM que tenga un nombre de clase dado. ¿Cuál es la mejor manera de obtener ese subelemento?
Update: Terminé usando Mechanize
para PHP que era mucho más fácil de trabajar.
5 answers
Actualización: Versión Xpath de *[@class~='my-class']
selector css
Así que después de mi comentario a continuación en respuesta al comentario de hakre, tuve curiosidad y miré el código detrás de Zend_Dom_Query
. Parece que el selector anterior está compilado con el siguiente xpath (no probado):
[contains(concat(' ', normalize-space(@class), ' '), ' my-class ')]
Así que el php sería:
$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
Básicamente, todo lo que hacemos aquí es normalizar el atributo class
para que incluso una sola clase esté limitada por espacios, y la lista completa de clases esté limitada en espacio. A continuación, añadir la clase que estamos buscando con un espacio. De esta manera estamos efectivamente buscando y encontramos solo instancias de my-class
.
¿Usar un selector xpath?
$dom = new DomDocument();
$dom->load($filePath);
$finder = new DomXPath($dom);
$classname="my-class";
$nodes = $finder->query("//*[contains(@class, '$classname')]");
Si solo hay un tipo de elemento, puede reemplazar el *
con el tagname particular.
Si necesita hacer mucho de esto con un selector muy complejo, lo recomendaría Zend_Dom_Query
que soporta sintaxis de selector CSS (a la jQuery):
$finder = new Zend_Dom_Query($html);
$classname = 'my-class';
$nodes = $finder->query("*[class~=\"$classname\"]");
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-30 15:57:55
Si desea obtener el innerhtml de la clase sin el zend, puede usar esto:
$dom = new DomDocument();
$dom->load($filePath);
$classname = 'main-article';
$finder = new DomXPath($dom);
$nodes = $finder->query("//*[contains(concat(' ', normalize-space(@class), ' '), ' $classname ')]");
$tmp_dom = new DOMDocument();
foreach ($nodes as $node)
{
$tmp_dom->appendChild($tmp_dom->importNode($node,true));
}
$innerHTML.=trim($tmp_dom->saveHTML());
echo $innerHTML;
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-26 07:12:36
Creo que el camino aceptado es mejor, pero supongo que esto podría funcionar también
function getElementByClass(&$parentNode, $tagName, $className, $offset = 0) {
$response = false;
$childNodeList = $parentNode->getElementsByTagName($tagName);
$tagCount = 0;
for ($i = 0; $i < $childNodeList->length; $i++) {
$temp = $childNodeList->item($i);
if (stripos($temp->getAttribute('class'), $className) !== false) {
if ($tagCount == $offset) {
$response = $temp;
break;
}
$tagCount++;
}
}
return $response;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-17 16:57:33
También hay otro enfoque sin el uso de DomXPath
o Zend_Dom_Query
.
Basado en la función original de dav, escribí la siguiente función que devuelve todos los hijos del nodo padre cuya etiqueta y clase coinciden con los parámetros.
function getElementsByClass(&$parentNode, $tagName, $className) {
$nodes=array();
$childNodeList = $parentNode->getElementsByTagName($tagName);
for ($i = 0; $i < $childNodeList->length; $i++) {
$temp = $childNodeList->item($i);
if (stripos($temp->getAttribute('class'), $className) !== false) {
$nodes[]=$temp;
}
}
return $nodes;
}
Supongamos que tiene una variable $html
el siguiente HTML:
<html>
<body>
<div id="content_node">
<p class="a">I am in the content node.</p>
<p class="a">I am in the content node.</p>
<p class="a">I am in the content node.</p>
</div>
<div id="footer_node">
<p class="a">I am in the footer node.</p>
</div>
</body>
</html>
El uso de getElementsByClass
es tan simple como:
$dom = new DOMDocument('1.0', 'utf-8');
$dom->loadHTML($html);
$content_node=$dom->getElementById("content_node");
$div_a_class_nodes=getElementsByClass($content_node, 'div', 'a');//will contain the three nodes under "content_node".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-24 17:54:10
DOMDocument es lento para escribir y phpQuery tiene problemas de pérdida de memoria. Terminé usando:
Https://github.com/wasinger/htmlpagedom
Para seleccionar una clase:
include 'includes/simple_html_dom.php';
$doc = str_get_html($html);
$href = $doc->find('.lastPage')[0]->href;
Espero que esto ayude a alguien más también
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-05 23:23:26