diff --git a/ext/dom/html_collection.c b/ext/dom/html_collection.c
index ce56b77ecd958..a4e2d6ad6fbed 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/namednodemap.c b/ext/dom/namednodemap.c
index 953731ad84487..dbfd8b8c9f2ca 100644
--- a/ext/dom/namednodemap.c
+++ b/ext/dom/namednodemap.c
@@ -67,7 +67,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItem)
}
dom_nnodemap_object *objmap = Z_DOMOBJ_P(ZEND_THIS)->ptr;
- php_dom_obj_map_get_named_item_into_zval(objmap, named, NULL, return_value);
+ php_dom_obj_map_get_ns_named_item_into_zval(objmap, named, NULL, return_value);
}
/* }}} end dom_namednodemap_get_named_item */
@@ -112,7 +112,7 @@ PHP_METHOD(DOMNamedNodeMap, getNamedItemNS)
objmap = (dom_nnodemap_object *)intern->ptr;
if (objmap != NULL) {
- php_dom_obj_map_get_named_item_into_zval(objmap, named, uri, return_value);
+ php_dom_obj_map_get_ns_named_item_into_zval(objmap, named, uri, return_value);
}
}
/* }}} end dom_namednodemap_get_named_item_ns */
diff --git a/ext/dom/obj_map.c b/ext/dom/obj_map.c
index 367171c43007e..9d54cb70d34ba 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();
@@ -376,9 +392,9 @@ void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long i
}
}
-void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value)
+void php_dom_obj_map_get_ns_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value)
{
- xmlNodePtr itemnode = objmap->handler->get_named_item(objmap, named, ns);
+ xmlNodePtr itemnode = objmap->handler->get_ns_named_item(objmap, named, ns);
if (itemnode) {
DOM_RET_OBJ(itemnode, objmap->baseobj);
} else {
@@ -390,17 +406,17 @@ void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const
* === Named item === *
**********************/
-static xmlNodePtr dom_map_get_named_item_entity(dom_nnodemap_object *map, const zend_string *named, const char *ns)
+static xmlNodePtr dom_map_get_ns_named_item_entity(dom_nnodemap_object *map, const zend_string *named, const char *ns)
{
return xmlHashLookup(map->ht, BAD_CAST ZSTR_VAL(named));
}
-static bool dom_map_has_named_item_xmlht(dom_nnodemap_object *map, const zend_string *named, const char *ns)
+static bool dom_map_has_ns_named_item_xmlht(dom_nnodemap_object *map, const zend_string *named, const char *ns)
{
- return dom_map_get_named_item_entity(map, named, ns) != NULL;
+ return dom_map_get_ns_named_item_entity(map, named, ns) != NULL;
}
-static xmlNodePtr dom_map_get_named_item_notation(dom_nnodemap_object *map, const zend_string *named, const char *ns)
+static xmlNodePtr dom_map_get_ns_named_item_notation(dom_nnodemap_object *map, const zend_string *named, const char *ns)
{
xmlNotationPtr notation = xmlHashLookup(map->ht, BAD_CAST ZSTR_VAL(named));
if (notation) {
@@ -409,7 +425,7 @@ static xmlNodePtr dom_map_get_named_item_notation(dom_nnodemap_object *map, cons
return NULL;
}
-static xmlNodePtr dom_map_get_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns)
+static xmlNodePtr dom_map_get_ns_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns)
{
xmlNodePtr nodep = dom_object_get_node(map->baseobj);
if (nodep) {
@@ -426,17 +442,17 @@ static xmlNodePtr dom_map_get_named_item_prop(dom_nnodemap_object *map, const ze
return NULL;
}
-static bool dom_map_has_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns)
+static bool dom_map_has_ns_named_item_prop(dom_nnodemap_object *map, const zend_string *named, const char *ns)
{
- return dom_map_get_named_item_prop(map, named, ns) != NULL;
+ return dom_map_get_ns_named_item_prop(map, named, ns) != NULL;
}
-static xmlNodePtr dom_map_get_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns)
+static xmlNodePtr dom_map_get_ns_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns)
{
return NULL;
}
-static bool dom_map_has_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns)
+static bool dom_map_has_ns_named_item_null(dom_nnodemap_object *map, const zend_string *named, const char *ns)
{
return false;
}
@@ -448,8 +464,9 @@ static bool dom_map_has_named_item_null(dom_nnodemap_object *map, const zend_str
const php_dom_obj_map_handler php_dom_obj_map_attributes = {
.length = dom_map_get_prop_length,
.get_item = dom_map_get_attributes_item,
- .get_named_item = dom_map_get_named_item_prop,
- .has_named_item = dom_map_has_named_item_prop,
+ .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,
};
@@ -457,8 +474,9 @@ const php_dom_obj_map_handler php_dom_obj_map_attributes = {
const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = {
.length = dom_map_get_by_tag_name_length,
.get_item = dom_map_get_by_tag_name_item,
- .get_named_item = dom_map_get_named_item_null,
- .has_named_item = dom_map_has_named_item_null,
+ .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,
};
@@ -466,8 +484,9 @@ const php_dom_obj_map_handler php_dom_obj_map_by_tag_name = {
const php_dom_obj_map_handler php_dom_obj_map_child_nodes = {
.length = dom_map_get_nodes_length,
.get_item = dom_map_get_nodes_item,
- .get_named_item = dom_map_get_named_item_null,
- .has_named_item = dom_map_has_named_item_null,
+ .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,
};
@@ -475,8 +494,9 @@ const php_dom_obj_map_handler php_dom_obj_map_child_nodes = {
const php_dom_obj_map_handler php_dom_obj_map_nodeset = {
.length = dom_map_get_nodeset_length,
.get_item = dom_map_get_nodeset_item,
- .get_named_item = dom_map_get_named_item_null,
- .has_named_item = dom_map_has_named_item_null,
+ .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,
};
@@ -484,8 +504,9 @@ const php_dom_obj_map_handler php_dom_obj_map_nodeset = {
const php_dom_obj_map_handler php_dom_obj_map_entities = {
.length = dom_map_get_xmlht_length,
.get_item = dom_map_get_entity_item,
- .get_named_item = dom_map_get_named_item_entity,
- .has_named_item = dom_map_has_named_item_xmlht,
+ .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,
};
@@ -493,8 +514,9 @@ const php_dom_obj_map_handler php_dom_obj_map_entities = {
const php_dom_obj_map_handler php_dom_obj_map_notations = {
.length = dom_map_get_xmlht_length,
.get_item = dom_map_get_notation_item,
- .get_named_item = dom_map_get_named_item_notation,
- .has_named_item = dom_map_has_named_item_xmlht,
+ .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,
};
@@ -502,8 +524,9 @@ const php_dom_obj_map_handler php_dom_obj_map_notations = {
const php_dom_obj_map_handler php_dom_obj_map_child_elements = {
.length = dom_map_get_elements_length,
.get_item = dom_map_get_elements_item,
- .get_named_item = dom_map_get_named_item_null,
- .has_named_item = dom_map_has_named_item_null,
+ .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,
};
@@ -511,8 +534,9 @@ const php_dom_obj_map_handler php_dom_obj_map_child_elements = {
const php_dom_obj_map_handler php_dom_obj_map_noop = {
.length = dom_map_get_zero_length,
.get_item = dom_map_get_null_item,
- .get_named_item = dom_map_get_named_item_null,
- .has_named_item = dom_map_has_named_item_null,
+ .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 dc2b33bd24fec..97ec43f0011f8 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_named_item)(dom_nnodemap_object *, const zend_string *, const char *);
- bool (*has_named_item)(dom_nnodemap_object *, const zend_string *, const char *);
+ 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;
@@ -51,7 +57,7 @@ typedef struct dom_nnodemap_object {
} dom_nnodemap_object;
void php_dom_create_obj_map(dom_object *basenode, dom_object *intern, xmlHashTablePtr ht, zend_string *local, zend_string *ns, const php_dom_obj_map_handler *handler);
-void php_dom_obj_map_get_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value);
+void php_dom_obj_map_get_ns_named_item_into_zval(dom_nnodemap_object *objmap, const zend_string *named, const char *ns, zval *return_value);
void php_dom_obj_map_get_item_into_zval(dom_nnodemap_object *objmap, zend_long index, zval *return_value);
zend_long php_dom_get_nodelist_length(dom_object *obj);
diff --git a/ext/dom/php_dom.c b/ext/dom/php_dom.c
index 5df8a1cb1e1ce..9e7896b7853f3 100644
--- a/ext/dom/php_dom.c
+++ b/ext/dom/php_dom.c
@@ -2373,7 +2373,7 @@ static zval *dom_nodemap_read_dimension(zend_object *object, zval *offset, int t
zend_long lval;
if (dom_nodemap_or_nodelist_process_offset_as_named(offset, &lval)) {
/* exceptional case, switch to named lookup */
- php_dom_obj_map_get_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv);
+ php_dom_obj_map_get_ns_named_item_into_zval(php_dom_obj_from_obj(object)->ptr, Z_STR_P(offset), NULL, rv);
return rv;
}
@@ -2399,7 +2399,7 @@ static int dom_nodemap_has_dimension(zend_object *object, zval *member, int chec
if (dom_nodemap_or_nodelist_process_offset_as_named(member, &offset)) {
/* exceptional case, switch to named lookup */
dom_nnodemap_object *map = php_dom_obj_from_obj(object)->ptr;
- return map->handler->has_named_item(map, Z_STR_P(member), NULL);
+ return map->handler->has_ns_named_item(map, Z_STR_P(member), NULL);
}
return offset >= 0 && offset < php_dom_get_namednodemap_length(php_dom_obj_from_obj(object));
@@ -2420,7 +2420,7 @@ static zval *dom_modern_nodemap_read_dimension(zend_object *object, zval *offset
if (ZEND_HANDLE_NUMERIC(Z_STR_P(offset), lval)) {
map->handler->get_item(map, (zend_long) lval, rv);
} else {
- php_dom_obj_map_get_named_item_into_zval(map, Z_STR_P(offset), NULL, rv);
+ php_dom_obj_map_get_ns_named_item_into_zval(map, Z_STR_P(offset), NULL, rv);
}
} else if (Z_TYPE_P(offset) == IS_LONG) {
map->handler->get_item(map, Z_LVAL_P(offset), rv);
@@ -2448,7 +2448,7 @@ static int dom_modern_nodemap_has_dimension(zend_object *object, zval *member, i
if (ZEND_HANDLE_NUMERIC(Z_STR_P(member), lval)) {
return (zend_long) lval >= 0 && (zend_long) lval < php_dom_get_namednodemap_length(obj);
} else {
- return map->handler->has_named_item(map, Z_STR_P(member), NULL);
+ return map->handler->has_ns_named_item(map, Z_STR_P(member), NULL);
}
} else if (Z_TYPE_P(member) == IS_LONG) {
zend_long offset = Z_LVAL_P(member);