24
24
#if defined(HAVE_LIBXML ) && defined(HAVE_DOM )
25
25
#include "php_dom.h"
26
26
#include "obj_map.h"
27
+ #include "token_list.h"
27
28
28
29
static zend_always_inline void objmap_cache_release_cached_obj (dom_nnodemap_object * objmap )
29
30
{
@@ -40,6 +41,30 @@ static zend_always_inline void reset_objmap_cache(dom_nnodemap_object *objmap)
40
41
objmap -> cached_length = -1 ;
41
42
}
42
43
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
+
43
68
/**************************
44
69
* === Length methods === *
45
70
**************************/
@@ -106,6 +131,24 @@ static zend_long dom_map_get_by_tag_name_length(dom_nnodemap_object *map)
106
131
return count ;
107
132
}
108
133
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
+
109
152
static zend_long dom_map_get_zero_length (dom_nnodemap_object * map )
110
153
{
111
154
return 0 ;
@@ -276,6 +319,10 @@ static void dom_map_collection_named_item_elements_iter(dom_nnodemap_object *map
276
319
}
277
320
}
278
321
322
+ static void dom_map_collection_named_item_null (dom_nnodemap_object * map , php_dom_obj_map_collection_iter * iter )
323
+ {
324
+ }
325
+
279
326
static void dom_map_get_by_tag_name_item (dom_nnodemap_object * map , zend_long index , zval * return_value )
280
327
{
281
328
xmlNodePtr nodep = dom_object_get_node (map -> baseobj );
@@ -292,12 +339,54 @@ static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long ind
292
339
}
293
340
}
294
341
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
+ dom_node_idx_pair start_point = dom_obj_map_get_start_point (map , nodep , index );
348
+ if (start_point .node ) {
349
+ if (start_point .index > 0 ) {
350
+ /* Only start iteration at next point if we actually have an index to seek to. */
351
+ itemnode = php_dom_next_in_tree_order (start_point .node , nodep );
352
+ } else {
353
+ itemnode = start_point .node ;
354
+ }
355
+ } else {
356
+ itemnode = php_dom_first_child_of_container_node (nodep );
357
+ }
358
+
359
+ do {
360
+ -- start_point .index ;
361
+ while (itemnode != NULL && !dom_matches_class_name (map , itemnode )) {
362
+ itemnode = php_dom_next_in_tree_order (itemnode , nodep );
363
+ }
364
+ } while (start_point .index > 0 && itemnode );
365
+ }
366
+ dom_ret_node_to_zobj (map , itemnode , return_value );
367
+ if (itemnode ) {
368
+ dom_map_cache_obj (map , itemnode , index , return_value );
369
+ }
370
+ }
371
+
295
372
static void dom_map_collection_named_item_by_tag_name_iter (dom_nnodemap_object * map , php_dom_obj_map_collection_iter * iter )
296
373
{
297
374
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 );
298
375
iter -> next = iter -> cur + 1 ;
299
376
}
300
377
378
+ static void dom_map_collection_named_item_by_class_name_iter (dom_nnodemap_object * map , php_dom_obj_map_collection_iter * iter )
379
+ {
380
+ xmlNodePtr basep = iter -> basep ;
381
+ xmlNodePtr nodep = iter -> candidate ? php_dom_next_in_tree_order (iter -> candidate , basep ) : php_dom_first_child_of_container_node (basep );
382
+
383
+ while (nodep != NULL && !dom_matches_class_name (map , nodep )) {
384
+ nodep = php_dom_next_in_tree_order (nodep , basep );
385
+ }
386
+
387
+ iter -> candidate = nodep ;
388
+ }
389
+
301
390
static void dom_map_get_null_item (dom_nnodemap_object * map , zend_long index , zval * return_value )
302
391
{
303
392
RETURN_NULL ();
@@ -478,6 +567,16 @@ const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = {
478
567
.nameless = true,
479
568
};
480
569
570
+ const php_dom_obj_map_handler php_dom_obj_map_by_class_name = {
571
+ .length = dom_map_get_by_class_name_length ,
572
+ .get_item = dom_map_get_by_class_name_item ,
573
+ .get_ns_named_item = dom_map_get_ns_named_item_null ,
574
+ .has_ns_named_item = dom_map_has_ns_named_item_null ,
575
+ .collection_named_item_iter = dom_map_collection_named_item_by_class_name_iter ,
576
+ .use_cache = true,
577
+ .nameless = true,
578
+ };
579
+
481
580
const php_dom_obj_map_handler php_dom_obj_map_child_nodes = {
482
581
.length = dom_map_get_nodes_length ,
483
582
.get_item = dom_map_get_nodes_item ,
@@ -533,7 +632,7 @@ const php_dom_obj_map_handler php_dom_obj_map_noop = {
533
632
.get_item = dom_map_get_null_item ,
534
633
.get_ns_named_item = dom_map_get_ns_named_item_null ,
535
634
.has_ns_named_item = dom_map_has_ns_named_item_null ,
536
- .collection_named_item_iter = NULL ,
635
+ .collection_named_item_iter = dom_map_collection_named_item_null ,
537
636
.use_cache = false,
538
637
.nameless = true,
539
638
};
0 commit comments