diff --git a/ext/dom/html_collection.c b/ext/dom/html_collection.c index ce56b77ecd9..a4e2d6ad6fb 100644 --- a/ext/dom/html_collection.c +++ b/ext/dom/html_collection.c @@ -46,47 +46,35 @@ static dom_named_item dom_html_collection_named_item(zend_string *key, zend_obje /* 2. Return the first element in the collection for which at least one of the following is true: */ xmlNodePtr basep = dom_object_get_node(objmap->baseobj); - if (basep != NULL) { - zend_long cur = 0; - zend_long next = cur; /* not +1, otherwise we skip the first candidate */ - xmlNodePtr candidate = basep->children; - bool iterate_tag_name = objmap->handler == &php_dom_obj_map_by_tag_name; - while (candidate != NULL) { - if (iterate_tag_name) { - candidate = dom_get_elements_by_tag_name_ns_raw(basep, candidate, objmap->ns, objmap->local, objmap->local_lower, &cur, next); - if (candidate == NULL) { - break; - } - next = cur + 1; - } else { - if (candidate->type != XML_ELEMENT_NODE) { - candidate = candidate->next; - continue; - } + if (basep != NULL && basep->children != NULL) { + php_dom_obj_map_collection_iter iter = {0}; + iter.candidate = basep->children; + iter.basep = basep; + + while (true) { + objmap->handler->collection_named_item_iter(objmap, &iter); + if (iter.candidate == NULL) { + break; } - ZEND_ASSERT(candidate->type == XML_ELEMENT_NODE); + ZEND_ASSERT(iter.candidate->type == XML_ELEMENT_NODE); xmlAttrPtr attr; /* it has an ID which is key; */ - if ((attr = xmlHasNsProp(candidate, BAD_CAST "id", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { + if ((attr = xmlHasNsProp(iter.candidate, BAD_CAST "id", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { ret.context_intern = objmap->baseobj; - ret.node = candidate; + ret.node = iter.candidate; return ret; } /* it is in the HTML namespace and has a name attribute whose value is key; */ - else if (php_dom_ns_is_fast(candidate, php_dom_ns_is_html_magic_token)) { - if ((attr = xmlHasNsProp(candidate, BAD_CAST "name", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { + else if (php_dom_ns_is_fast(iter.candidate, php_dom_ns_is_html_magic_token)) { + if ((attr = xmlHasNsProp(iter.candidate, BAD_CAST "name", NULL)) != NULL && dom_compare_value(attr, BAD_CAST ZSTR_VAL(key))) { ret.context_intern = objmap->baseobj; - ret.node = candidate; + ret.node = iter.candidate; return ret; } } - - if (!iterate_tag_name) { - candidate = candidate->next; - } } } diff --git a/ext/dom/obj_map.c b/ext/dom/obj_map.c index 08788a24a71..64e4cff7b6f 100644 --- a/ext/dom/obj_map.c +++ b/ext/dom/obj_map.c @@ -266,6 +266,16 @@ static void dom_map_get_elements_item(dom_nnodemap_object *map, zend_long index, } } +static void dom_map_collection_named_item_elements_iter(dom_nnodemap_object *map, php_dom_obj_map_collection_iter *iter) +{ + if (iter->candidate != iter->basep->children) { + iter->candidate = iter->candidate->next; + } + while (iter->candidate && iter->candidate->type != XML_ELEMENT_NODE) { + iter->candidate = iter->candidate->next; + } +} + static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { xmlNodePtr nodep = dom_object_get_node(map->baseobj); @@ -282,6 +292,12 @@ static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long ind } } +static void dom_map_collection_named_item_by_tag_name_iter(dom_nnodemap_object *map, php_dom_obj_map_collection_iter *iter) +{ + 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); + iter->next = iter->cur + 1; +} + static void dom_map_get_null_item(dom_nnodemap_object *map, zend_long index, zval *return_value) { RETURN_NULL(); @@ -447,6 +463,7 @@ const php_dom_obj_map_handler php_dom_obj_map_attributes = { .get_item = dom_map_get_attributes_item, .get_ns_named_item = dom_map_get_ns_named_item_prop, .has_ns_named_item = dom_map_has_ns_named_item_prop, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = false, }; @@ -456,6 +473,7 @@ const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = { .get_item = dom_map_get_by_tag_name_item, .get_ns_named_item = dom_map_get_ns_named_item_null, .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = dom_map_collection_named_item_by_tag_name_iter, .use_cache = true, .nameless = true, }; @@ -465,6 +483,7 @@ const php_dom_obj_map_handler php_dom_obj_map_child_nodes = { .get_item = dom_map_get_nodes_item, .get_ns_named_item = dom_map_get_ns_named_item_null, .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = NULL, .use_cache = true, .nameless = true, }; @@ -474,6 +493,7 @@ const php_dom_obj_map_handler php_dom_obj_map_nodeset = { .get_item = dom_map_get_nodeset_item, .get_ns_named_item = dom_map_get_ns_named_item_null, .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = true, }; @@ -483,6 +503,7 @@ const php_dom_obj_map_handler php_dom_obj_map_entities = { .get_item = dom_map_get_entity_item, .get_ns_named_item = dom_map_get_ns_named_item_entity, .has_ns_named_item = dom_map_has_ns_named_item_xmlht, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = false, }; @@ -492,6 +513,7 @@ const php_dom_obj_map_handler php_dom_obj_map_notations = { .get_item = dom_map_get_notation_item, .get_ns_named_item = dom_map_get_ns_named_item_notation, .has_ns_named_item = dom_map_has_ns_named_item_xmlht, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = false, }; @@ -501,6 +523,7 @@ const php_dom_obj_map_handler php_dom_obj_map_child_elements = { .get_item = dom_map_get_elements_item, .get_ns_named_item = dom_map_get_ns_named_item_null, .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = dom_map_collection_named_item_elements_iter, .use_cache = true, .nameless = true, }; @@ -510,6 +533,7 @@ const php_dom_obj_map_handler php_dom_obj_map_noop = { .get_item = dom_map_get_null_item, .get_ns_named_item = dom_map_get_ns_named_item_null, .has_ns_named_item = dom_map_has_ns_named_item_null, + .collection_named_item_iter = NULL, .use_cache = false, .nameless = true, }; diff --git a/ext/dom/obj_map.h b/ext/dom/obj_map.h index 78f66decb96..97ec43f0011 100644 --- a/ext/dom/obj_map.h +++ b/ext/dom/obj_map.h @@ -19,11 +19,17 @@ typedef struct dom_nnodemap_object dom_nnodemap_object; +typedef struct php_dom_obj_map_collection_iter { + zend_long cur, next; + xmlNodePtr candidate, basep; +} php_dom_obj_map_collection_iter; + typedef struct php_dom_obj_map_handler { zend_long (*length)(dom_nnodemap_object *); void (*get_item)(dom_nnodemap_object *, zend_long, zval *); xmlNodePtr (*get_ns_named_item)(dom_nnodemap_object *, const zend_string *, const char *); bool (*has_ns_named_item)(dom_nnodemap_object *, const zend_string *, const char *); + void (*collection_named_item_iter)(dom_nnodemap_object *, php_dom_obj_map_collection_iter *); bool use_cache; bool nameless; } php_dom_obj_map_handler;