Skip to content

Refactor dom_html_collection_named_item() #19090

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 15 additions & 27 deletions ext/dom/html_collection.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
}

Expand Down
4 changes: 2 additions & 2 deletions ext/dom/namednodemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down Expand Up @@ -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 */
Expand Down
78 changes: 51 additions & 27 deletions ext/dom/obj_map.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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();
Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand All @@ -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) {
Expand All @@ -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;
}
Expand All @@ -448,71 +464,79 @@ 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,
};

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,
};

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,
};

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,
};

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,
};

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,
};

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,
};

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,
};
Expand Down
12 changes: 9 additions & 3 deletions ext/dom/obj_map.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
8 changes: 4 additions & 4 deletions ext/dom/php_dom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -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));
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading