2424#if defined(HAVE_LIBXML ) && defined(HAVE_DOM )
2525#include "php_dom.h"
2626#include "obj_map.h"
27+ #include "token_list.h"
2728
2829static zend_always_inline void objmap_cache_release_cached_obj (dom_nnodemap_object * objmap )
2930{
@@ -40,6 +41,30 @@ static zend_always_inline void reset_objmap_cache(dom_nnodemap_object *objmap)
4041 objmap -> cached_length = -1 ;
4142}
4243
44+ static bool dom_matches_class_name (const dom_nnodemap_object * map , const xmlNode * nodep )
45+ {
46+ bool ret = false;
47+
48+ if (nodep -> type == XML_ELEMENT_NODE ) {
49+ xmlAttrPtr classes = xmlHasNsProp (nodep , BAD_CAST "class" , NULL );
50+ if (classes != NULL ) {
51+ bool should_free ;
52+ xmlChar * value = php_libxml_attr_value (classes , & should_free );
53+
54+ bool quirks = map -> baseobj -> document -> quirks_mode == PHP_LIBXML_QUIRKS ;
55+ if (dom_ordered_set_all_contained (map -> array , (const char * ) value , quirks )) {
56+ ret = true;
57+ }
58+
59+ if (should_free ) {
60+ xmlFree (value );
61+ }
62+ }
63+ }
64+
65+ return ret ;
66+ }
67+
4368/**************************
4469 * === Length methods === *
4570 **************************/
@@ -106,6 +131,24 @@ static zend_long dom_map_get_by_tag_name_length(dom_nnodemap_object *map)
106131 return count ;
107132}
108133
134+ static zend_long dom_map_get_by_class_name_length (dom_nnodemap_object * map )
135+ {
136+ xmlNodePtr nodep = dom_object_get_node (map -> baseobj );
137+ zend_long count = 0 ;
138+ if (nodep ) {
139+ xmlNodePtr basep = nodep ;
140+ nodep = php_dom_first_child_of_container_node (basep );
141+
142+ while (nodep != NULL ) {
143+ if (dom_matches_class_name (map , nodep )) {
144+ count ++ ;
145+ }
146+ nodep = php_dom_next_in_tree_order (nodep , basep );
147+ }
148+ }
149+ return count ;
150+ }
151+
109152static zend_long dom_map_get_zero_length (dom_nnodemap_object * map )
110153{
111154 return 0 ;
@@ -292,6 +335,32 @@ static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long ind
292335 }
293336}
294337
338+ static void dom_map_get_by_class_name_item (dom_nnodemap_object * map , zend_long index , zval * return_value )
339+ {
340+ xmlNodePtr nodep = dom_object_get_node (map -> baseobj );
341+ xmlNodePtr itemnode = NULL ;
342+ if (nodep && index >= 0 ) {
343+ xmlNodePtr basep = nodep ;
344+ dom_node_idx_pair start_point = dom_obj_map_get_start_point (map , nodep , index );
345+ if (start_point .node ) {
346+ itemnode = php_dom_next_in_tree_order (start_point .node , basep );
347+ } else {
348+ itemnode = php_dom_first_child_of_container_node (nodep );
349+ }
350+
351+ do {
352+ -- start_point .index ;
353+ while (itemnode != NULL && !dom_matches_class_name (map , itemnode )) {
354+ itemnode = php_dom_next_in_tree_order (itemnode , basep );
355+ }
356+ } while (start_point .index > 0 && itemnode );
357+ }
358+ dom_ret_node_to_zobj (map , itemnode , return_value );
359+ if (itemnode ) {
360+ dom_map_cache_obj (map , itemnode , index , return_value );
361+ }
362+ }
363+
295364static void dom_map_collection_named_item_by_tag_name_iter (dom_nnodemap_object * map , php_dom_obj_map_collection_iter * iter )
296365{
297366 iter -> candidate = dom_get_elements_by_tag_name_ns_raw (iter -> basep , iter -> candidate , map -> ns , map -> local , map -> local_lower , & iter -> cur , iter -> next );
@@ -478,6 +547,16 @@ const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = {
478547 .nameless = true,
479548};
480549
550+ const php_dom_obj_map_handler php_dom_obj_map_by_class_name = {
551+ .length = dom_map_get_by_class_name_length ,
552+ .get_item = dom_map_get_by_class_name_item ,
553+ .get_ns_named_item = dom_map_get_ns_named_item_null ,
554+ .has_ns_named_item = dom_map_has_ns_named_item_null ,
555+ .collection_named_item_iter = NULL , // TODO ???
556+ .use_cache = true,
557+ .nameless = true,
558+ };
559+
481560const php_dom_obj_map_handler php_dom_obj_map_child_nodes = {
482561 .length = dom_map_get_nodes_length ,
483562 .get_item = dom_map_get_nodes_item ,
@@ -533,7 +612,7 @@ const php_dom_obj_map_handler php_dom_obj_map_noop = {
533612 .get_item = dom_map_get_null_item ,
534613 .get_ns_named_item = dom_map_get_ns_named_item_null ,
535614 .has_ns_named_item = dom_map_has_ns_named_item_null ,
536- .collection_named_item_iter = NULL ,
615+ .collection_named_item_iter = NULL , // TODO
537616 .use_cache = false,
538617 .nameless = true,
539618};
0 commit comments