|
28 | 28 | static zend_always_inline void objmap_cache_release_cached_obj(dom_nnodemap_object *objmap) |
29 | 29 | { |
30 | 30 | if (objmap->cached_obj) { |
31 | | - /* Since the DOM is a tree there can be no cycles. */ |
32 | | - if (GC_DELREF(&objmap->cached_obj->std) == 0) { |
33 | | - zend_objects_store_del(&objmap->cached_obj->std); |
34 | | - } |
| 31 | + OBJ_RELEASE(&objmap->cached_obj->std); |
35 | 32 | objmap->cached_obj = NULL; |
36 | 33 | objmap->cached_obj_index = 0; |
37 | 34 | } |
@@ -82,6 +79,20 @@ static zend_long dom_map_get_nodes_length(dom_nnodemap_object *map) |
82 | 79 | return count; |
83 | 80 | } |
84 | 81 |
|
| 82 | +static zend_long dom_map_get_elements_length(dom_nnodemap_object *map) |
| 83 | +{ |
| 84 | + zend_long count = 0; |
| 85 | + xmlNodePtr nodep = dom_object_get_node(map->baseobj); |
| 86 | + if (nodep) { |
| 87 | + for (xmlNodePtr curnode = dom_nodelist_iter_start_first_child(nodep); curnode; curnode = curnode->next) { |
| 88 | + if (curnode->type == XML_ELEMENT_NODE) { |
| 89 | + count++; |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + return count; |
| 94 | +} |
| 95 | + |
85 | 96 | static zend_long dom_map_get_by_tag_name_length(dom_nnodemap_object *map) |
86 | 97 | { |
87 | 98 | xmlNodePtr nodep = dom_object_get_node(map->baseobj); |
@@ -223,6 +234,38 @@ static void dom_map_get_nodes_item(dom_nnodemap_object *map, zend_long index, zv |
223 | 234 | } |
224 | 235 | } |
225 | 236 |
|
| 237 | +static void dom_map_get_elements_item(dom_nnodemap_object *map, zend_long index, zval *return_value) |
| 238 | +{ |
| 239 | + xmlNodePtr nodep = dom_object_get_node(map->baseobj); |
| 240 | + xmlNodePtr itemnode = NULL; |
| 241 | + if (nodep && index >= 0) { |
| 242 | + dom_node_idx_pair start_point = dom_obj_map_get_start_point(map, nodep, index); |
| 243 | + if (start_point.node) { |
| 244 | + /* Guaranteed to be an element */ |
| 245 | + itemnode = start_point.node; |
| 246 | + } else { |
| 247 | + /* Fetch first element child */ |
| 248 | + itemnode = nodep->children; |
| 249 | + while (itemnode && itemnode->type != XML_ELEMENT_NODE) { |
| 250 | + itemnode = itemnode->next; |
| 251 | + } |
| 252 | + } |
| 253 | + |
| 254 | + for (; start_point.index > 0 && itemnode; --start_point.index) { |
| 255 | + do { |
| 256 | + itemnode = itemnode->next; |
| 257 | + } while (itemnode && itemnode->type != XML_ELEMENT_NODE); |
| 258 | + } |
| 259 | + if (itemnode && itemnode->type != XML_ELEMENT_NODE) { |
| 260 | + itemnode = NULL; |
| 261 | + } |
| 262 | + } |
| 263 | + dom_ret_node_to_zobj(map, itemnode, return_value); |
| 264 | + if (itemnode) { |
| 265 | + dom_map_cache_obj(map, itemnode, index, return_value); |
| 266 | + } |
| 267 | +} |
| 268 | + |
226 | 269 | static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long index, zval *return_value) |
227 | 270 | { |
228 | 271 | xmlNodePtr nodep = dom_object_get_node(map->baseobj); |
@@ -456,6 +499,15 @@ const php_dom_obj_map_handler php_dom_obj_map_notations = { |
456 | 499 | .nameless = false, |
457 | 500 | }; |
458 | 501 |
|
| 502 | +const php_dom_obj_map_handler php_dom_obj_map_child_elements = { |
| 503 | + .length = dom_map_get_elements_length, |
| 504 | + .get_item = dom_map_get_elements_item, |
| 505 | + .get_named_item = dom_map_get_named_item_null, |
| 506 | + .has_named_item = dom_map_has_named_item_null, |
| 507 | + .use_cache = true, |
| 508 | + .nameless = true, |
| 509 | +}; |
| 510 | + |
459 | 511 | const php_dom_obj_map_handler php_dom_obj_map_noop = { |
460 | 512 | .length = dom_map_get_zero_length, |
461 | 513 | .get_item = dom_map_get_null_item, |
|
0 commit comments