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 ;
@@ -276,6 +319,10 @@ static void dom_map_collection_named_item_elements_iter(dom_nnodemap_object *map
276319 }
277320}
278321
322+ static void dom_map_collection_named_item_null (dom_nnodemap_object * map , php_dom_obj_map_collection_iter * iter )
323+ {
324+ }
325+
279326static void dom_map_get_by_tag_name_item (dom_nnodemap_object * map , zend_long index , zval * return_value )
280327{
281328 xmlNodePtr nodep = dom_object_get_node (map -> baseobj );
@@ -292,12 +339,50 @@ static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long ind
292339 }
293340}
294341
342+ static void dom_map_get_by_class_name_item (dom_nnodemap_object * map , zend_long index , zval * return_value )
343+ {
344+ xmlNodePtr nodep = dom_object_get_node (map -> baseobj );
345+ xmlNodePtr itemnode = NULL ;
346+ if (nodep && index >= 0 ) {
347+ xmlNodePtr basep = nodep ;
348+ dom_node_idx_pair start_point = dom_obj_map_get_start_point (map , nodep , index );
349+ if (start_point .node ) {
350+ itemnode = php_dom_next_in_tree_order (start_point .node , basep );
351+ } else {
352+ itemnode = php_dom_first_child_of_container_node (nodep );
353+ }
354+
355+ do {
356+ -- start_point .index ;
357+ while (itemnode != NULL && !dom_matches_class_name (map , itemnode )) {
358+ itemnode = php_dom_next_in_tree_order (itemnode , basep );
359+ }
360+ } while (start_point .index > 0 && itemnode );
361+ }
362+ dom_ret_node_to_zobj (map , itemnode , return_value );
363+ if (itemnode ) {
364+ dom_map_cache_obj (map , itemnode , index , return_value );
365+ }
366+ }
367+
295368static void dom_map_collection_named_item_by_tag_name_iter (dom_nnodemap_object * map , php_dom_obj_map_collection_iter * iter )
296369{
297370 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 );
298371 iter -> next = iter -> cur + 1 ;
299372}
300373
374+ static void dom_map_collection_named_item_by_class_name_iter (dom_nnodemap_object * map , php_dom_obj_map_collection_iter * iter )
375+ {
376+ xmlNodePtr basep = iter -> basep ;
377+ xmlNodePtr nodep = iter -> candidate ? php_dom_next_in_tree_order (iter -> candidate , basep ) : php_dom_first_child_of_container_node (basep );
378+
379+ while (nodep != NULL && !dom_matches_class_name (map , nodep )) {
380+ nodep = php_dom_next_in_tree_order (nodep , basep );
381+ }
382+
383+ iter -> candidate = nodep ;
384+ }
385+
301386static void dom_map_get_null_item (dom_nnodemap_object * map , zend_long index , zval * return_value )
302387{
303388 RETURN_NULL ();
@@ -478,6 +563,16 @@ const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = {
478563 .nameless = true,
479564};
480565
566+ const php_dom_obj_map_handler php_dom_obj_map_by_class_name = {
567+ .length = dom_map_get_by_class_name_length ,
568+ .get_item = dom_map_get_by_class_name_item ,
569+ .get_ns_named_item = dom_map_get_ns_named_item_null ,
570+ .has_ns_named_item = dom_map_has_ns_named_item_null ,
571+ .collection_named_item_iter = dom_map_collection_named_item_by_class_name_iter ,
572+ .use_cache = true,
573+ .nameless = true,
574+ };
575+
481576const php_dom_obj_map_handler php_dom_obj_map_child_nodes = {
482577 .length = dom_map_get_nodes_length ,
483578 .get_item = dom_map_get_nodes_item ,
@@ -533,7 +628,7 @@ const php_dom_obj_map_handler php_dom_obj_map_noop = {
533628 .get_item = dom_map_get_null_item ,
534629 .get_ns_named_item = dom_map_get_ns_named_item_null ,
535630 .has_ns_named_item = dom_map_has_ns_named_item_null ,
536- .collection_named_item_iter = NULL ,
631+ .collection_named_item_iter = dom_map_collection_named_item_null ,
537632 .use_cache = false,
538633 .nameless = true,
539634};
0 commit comments