diff --git a/ext/dom/element.c b/ext/dom/element.c index 5fcffaf42055..049612ed1d75 100644 --- a/ext/dom/element.c +++ b/ext/dom/element.c @@ -2013,6 +2013,120 @@ PHP_METHOD(Dom_Element, matches) dom_element_matches(thisp, intern, return_value, selectors_str); } + +PHP_METHOD(Dom_Element, up) +{ + zend_string *selectors_str = NULL; + zend_long index = 0; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(selectors_str) + Z_PARAM_LONG(index) + ZEND_PARSE_PARAMETERS_END(); + + if (index < 0) { + zend_argument_value_error(2, "must be greater than or equal to 0"); + RETURN_THROWS(); + } + + xmlNodePtr thisp; + dom_object *intern; + zval *id; + DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, intern); + + dom_element_up(thisp, intern, return_value, selectors_str, index); +} + +PHP_METHOD(Dom_Element, down) +{ + zend_string *selectors_str = NULL; + zend_long index = 0; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(selectors_str) + Z_PARAM_LONG(index) + ZEND_PARSE_PARAMETERS_END(); + + if (index < 0) { + zend_argument_value_error(2, "must be greater than or equal to 0"); + RETURN_THROWS(); + } + + xmlNodePtr thisp; + dom_object *intern; + zval *id; + DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, intern); + + dom_element_down(thisp, intern, return_value, selectors_str, index); +} + +PHP_METHOD(Dom_Element, next) +{ + zend_string *selectors_str = NULL; + zend_long index = 0; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(selectors_str) + Z_PARAM_LONG(index) + ZEND_PARSE_PARAMETERS_END(); + + if (index < 0) { + zend_argument_value_error(2, "must be greater than or equal to 0"); + RETURN_THROWS(); + } + + xmlNodePtr thisp; + dom_object *intern; + zval *id; + DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, intern); + + dom_element_next(thisp, intern, return_value, selectors_str, index); +} + +PHP_METHOD(Dom_Element, previous) +{ + zend_string *selectors_str = NULL; + zend_long index = 0; + + ZEND_PARSE_PARAMETERS_START(0, 2) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(selectors_str) + Z_PARAM_LONG(index) + ZEND_PARSE_PARAMETERS_END(); + + if (index < 0) { + zend_argument_value_error(2, "must be greater than or equal to 0"); + RETURN_THROWS(); + } + + xmlNodePtr thisp; + dom_object *intern; + zval *id; + DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, intern); + + dom_element_previous(thisp, intern, return_value, selectors_str, index); +} + +PHP_METHOD(Dom_Element, siblings) +{ + zend_string *selectors_str = NULL; + + ZEND_PARSE_PARAMETERS_START(0, 1) + Z_PARAM_OPTIONAL + Z_PARAM_STR_OR_NULL(selectors_str) + ZEND_PARSE_PARAMETERS_END(); + + xmlNodePtr thisp; + dom_object *intern; + zval *id; + DOM_GET_THIS_OBJ(thisp, id, xmlNodePtr, intern); + + dom_element_siblings(thisp, intern, return_value, selectors_str); +} + PHP_METHOD(Dom_Element, closest) { zend_string *selectors_str; diff --git a/ext/dom/parentnode/css_selectors.c b/ext/dom/parentnode/css_selectors.c index 0fc0cc1ef0f6..77981c553236 100644 --- a/ext/dom/parentnode/css_selectors.c +++ b/ext/dom/parentnode/css_selectors.c @@ -14,6 +14,239 @@ #ifdef HAVE_CONFIG_H #include "config.h" + +/* Prototype-like DOM Traversal Methods */ + +void dom_element_up(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + const xmlNode *current = thisp->parent; + zend_long current_index = 0; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + return; + } + current_index++; + } + current = current->parent; + } + RETURN_NULL(); + } + + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + break; + } + current_index++; + } + } + current = current->parent; + } + } + + dom_selector_cleanup(&parser, &selectors, list); +} + +typedef struct { + xmlNodePtr result; + zend_long target_index; + zend_long current_index; +} dom_query_down_ctx; + +static lxb_status_t dom_query_down_callback(const xmlNode *node, lxb_css_selector_specificity_t spec, void *ctx) +{ + dom_query_down_ctx *qctx = (dom_query_down_ctx *) ctx; + if (qctx->current_index == qctx->target_index) { + qctx->result = (xmlNodePtr) node; + return LXB_STATUS_STOP; + } + qctx->current_index++; + return LXB_STATUS_OK; +} + +void dom_element_down(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + dom_query_down_ctx ctx = { NULL, index, 0 }; + + if (selectors_str == NULL) { + /* Fast path for all elements: use universal selector */ + zend_string *univ = zend_string_init("*", 1, 0); + dom_query_selector_common(thisp, intern, univ, dom_query_down_callback, &ctx, LXB_SELECTORS_OPT_DEFAULT); + zend_string_release(univ); + } else { + dom_query_selector_common(thisp, intern, selectors_str, dom_query_down_callback, &ctx, LXB_SELECTORS_OPT_DEFAULT); + } + + if (ctx.result != NULL) { + DOM_RET_OBJ(ctx.result, intern); + } else { + RETURN_NULL(); + } +} + +void dom_element_next(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + const xmlNode *current = thisp->next; + zend_long current_index = 0; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + return; + } + current_index++; + } + current = current->next; + } + RETURN_NULL(); + } + + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + break; + } + current_index++; + } + } + current = current->next; + } + } + + dom_selector_cleanup(&parser, &selectors, list); +} + +void dom_element_previous(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + const xmlNode *current = thisp->prev; + zend_long current_index = 0; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + return; + } + current_index++; + } + current = current->prev; + } + RETURN_NULL(); + } + + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + break; + } + current_index++; + } + } + current = current->prev; + } + } + + dom_selector_cleanup(&parser, &selectors, list); +} + +void dom_element_siblings(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str) +{ + HashTable *list = zend_new_array(0); + const xmlNode *parent = thisp->parent; + + if (parent != NULL) { + const xmlNode *current = parent->children; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE && current != thisp) { + zval zv; + php_dom_create_object((xmlNodePtr) current, &zv, intern); + zend_hash_next_index_insert(list, &zv); + } + current = current->next; + } + } else { + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list_lxb = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list_lxb != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE && current != thisp) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list_lxb, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + zval zv; + php_dom_create_object((xmlNodePtr) current, &zv, intern); + zend_hash_next_index_insert(list, &zv); + } + } + current = current->next; + } + } + dom_selector_cleanup(&parser, &selectors, list_lxb); + } + } + + object_init_ex(return_value, dom_modern_nodelist_class_entry); + dom_object *ret_obj = Z_DOMOBJ_P(return_value); + dom_nnodemap_object *mapptr = (dom_nnodemap_object *) ret_obj->ptr; + mapptr->array = list; + mapptr->release_array = true; + mapptr->handler = &php_dom_obj_map_nodeset; +} + #endif #include "php.h" @@ -279,4 +512,237 @@ void dom_element_closest(xmlNodePtr thisp, dom_object *intern, zval *return_valu } } + +/* Prototype-like DOM Traversal Methods */ + +void dom_element_up(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + const xmlNode *current = thisp->parent; + zend_long current_index = 0; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + return; + } + current_index++; + } + current = current->parent; + } + RETURN_NULL(); + } + + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + break; + } + current_index++; + } + } + current = current->parent; + } + } + + dom_selector_cleanup(&parser, &selectors, list); +} + +typedef struct { + xmlNodePtr result; + zend_long target_index; + zend_long current_index; +} dom_query_down_ctx; + +static lxb_status_t dom_query_down_callback(const xmlNode *node, lxb_css_selector_specificity_t spec, void *ctx) +{ + dom_query_down_ctx *qctx = (dom_query_down_ctx *) ctx; + if (qctx->current_index == qctx->target_index) { + qctx->result = (xmlNodePtr) node; + return LXB_STATUS_STOP; + } + qctx->current_index++; + return LXB_STATUS_OK; +} + +void dom_element_down(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + dom_query_down_ctx ctx = { NULL, index, 0 }; + + if (selectors_str == NULL) { + /* Fast path for all elements: use universal selector */ + zend_string *univ = zend_string_init("*", 1, 0); + dom_query_selector_common(thisp, intern, univ, dom_query_down_callback, &ctx, LXB_SELECTORS_OPT_DEFAULT); + zend_string_release(univ); + } else { + dom_query_selector_common(thisp, intern, selectors_str, dom_query_down_callback, &ctx, LXB_SELECTORS_OPT_DEFAULT); + } + + if (ctx.result != NULL) { + DOM_RET_OBJ(ctx.result, intern); + } else { + RETURN_NULL(); + } +} + +void dom_element_next(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + const xmlNode *current = thisp->next; + zend_long current_index = 0; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + return; + } + current_index++; + } + current = current->next; + } + RETURN_NULL(); + } + + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + break; + } + current_index++; + } + } + current = current->next; + } + } + + dom_selector_cleanup(&parser, &selectors, list); +} + +void dom_element_previous(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index) +{ + const xmlNode *current = thisp->prev; + zend_long current_index = 0; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + return; + } + current_index++; + } + current = current->prev; + } + RETURN_NULL(); + } + + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + if (current_index == index) { + DOM_RET_OBJ((xmlNodePtr) current, intern); + break; + } + current_index++; + } + } + current = current->prev; + } + } + + dom_selector_cleanup(&parser, &selectors, list); +} + +void dom_element_siblings(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str) +{ + HashTable *list = zend_new_array(0); + const xmlNode *parent = thisp->parent; + + if (parent != NULL) { + const xmlNode *current = parent->children; + + if (selectors_str == NULL) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE && current != thisp) { + zval zv; + php_dom_create_object((xmlNodePtr) current, &zv, intern); + zend_hash_next_index_insert(list, &zv); + } + current = current->next; + } + } else { + lxb_css_parser_t parser; + lxb_selectors_t selectors; + lxb_css_selector_list_t *list_lxb = dom_parse_selector(&parser, &selectors, selectors_str, LXB_SELECTORS_OPT_MATCH_FIRST, intern); + + if (EXPECTED(list_lxb != NULL)) { + while (current != NULL) { + if (current->type == XML_ELEMENT_NODE && current != thisp) { + dom_query_selector_matches_ctx ctx = { current, false }; + lxb_status_t status = lxb_selectors_match_node(&selectors, current, list_lxb, dom_query_selector_find_matches_callback, &ctx); + status = dom_check_css_execution_status(status); + if (UNEXPECTED(status != LXB_STATUS_OK)) { + break; + } + if (ctx.result) { + zval zv; + php_dom_create_object((xmlNodePtr) current, &zv, intern); + zend_hash_next_index_insert(list, &zv); + } + } + current = current->next; + } + } + dom_selector_cleanup(&parser, &selectors, list_lxb); + } + } + + object_init_ex(return_value, dom_modern_nodelist_class_entry); + dom_object *ret_obj = Z_DOMOBJ_P(return_value); + dom_nnodemap_object *mapptr = (dom_nnodemap_object *) ret_obj->ptr; + mapptr->array = list; + mapptr->release_array = true; + mapptr->handler = &php_dom_obj_map_nodeset; +} + #endif diff --git a/ext/dom/php_dom.h b/ext/dom/php_dom.h index 6f4b5075b659..53d3e9e08247 100644 --- a/ext/dom/php_dom.h +++ b/ext/dom/php_dom.h @@ -196,6 +196,11 @@ bool php_dom_pre_insert_is_parent_invalid(xmlNodePtr parent); void dom_parent_node_query_selector(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str); void dom_parent_node_query_selector_all(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str); void dom_element_matches(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str); +void dom_element_up(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index); +void dom_element_down(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index); +void dom_element_next(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index); +void dom_element_previous(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str, zend_long index); +void dom_element_siblings(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str); void dom_element_closest(xmlNodePtr thisp, dom_object *intern, zval *return_value, const zend_string *selectors_str); xmlNodePtr dom_parse_fragment(dom_object *obj, xmlNodePtr context_node, const zend_string *input); diff --git a/ext/dom/php_dom.stub.php b/ext/dom/php_dom.stub.php index 521e3cd99c2e..1d5deccebaaa 100644 --- a/ext/dom/php_dom.stub.php +++ b/ext/dom/php_dom.stub.php @@ -1410,6 +1410,12 @@ public function querySelectorAll(string $selectors): NodeList {} public function closest(string $selectors): ?Element {} public function matches(string $selectors): bool {} + public function up(?string $selectors = null, int $index = 0): ?Element {} + public function down(?string $selectors = null, int $index = 0): ?Element {} + public function next(?string $selectors = null, int $index = 0): ?Element {} + public function previous(?string $selectors = null, int $index = 0): ?Element {} + public function siblings(?string $selectors = null): NodeList {} + /** @virtual */ public string $innerHTML; diff --git a/ext/dom/php_dom_arginfo.h b/ext/dom/php_dom_arginfo.h index 6a15f911e610..897085e0d049 100644 --- a/ext/dom/php_dom_arginfo.h +++ b/ext/dom/php_dom_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit php_dom.stub.php instead. - * Stub hash: 8d7713834c924709155ed7acc554c9efc55e96c1 + * Stub hash: f53e8ef8b543d089b51a72828c57efa10acdc98d * Has decl header: yes */ #include "zend_attributes.h" @@ -831,6 +831,21 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Dom_Element_matches, 0, 1, ZEND_ARG_TYPE_INFO(0, selectors, IS_STRING, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Dom_Element_up, 0, 0, Dom\\Element, 1) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, selectors, IS_STRING, 1, "null") + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, index, IS_LONG, 0, "0") +ZEND_END_ARG_INFO() + +#define arginfo_class_Dom_Element_down arginfo_class_Dom_Element_up + +#define arginfo_class_Dom_Element_next arginfo_class_Dom_Element_up + +#define arginfo_class_Dom_Element_previous arginfo_class_Dom_Element_up + +ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_Dom_Element_siblings, 0, 0, Dom\\\116odeList, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, selectors, IS_STRING, 1, "null") +ZEND_END_ARG_INFO() + #define arginfo_class_Dom_Element_getInScopeNamespaces arginfo_class_DOMNode___sleep #define arginfo_class_Dom_Element_getDescendantNamespaces arginfo_class_DOMNode___sleep @@ -1288,6 +1303,11 @@ ZEND_METHOD(Dom_Element, querySelector); ZEND_METHOD(Dom_Element, querySelectorAll); ZEND_METHOD(Dom_Element, closest); ZEND_METHOD(Dom_Element, matches); +ZEND_METHOD(Dom_Element, up); +ZEND_METHOD(Dom_Element, down); +ZEND_METHOD(Dom_Element, next); +ZEND_METHOD(Dom_Element, previous); +ZEND_METHOD(Dom_Element, siblings); ZEND_METHOD(Dom_Element, getInScopeNamespaces); ZEND_METHOD(Dom_Element, getDescendantNamespaces); ZEND_METHOD(Dom_Element, rename); @@ -1671,6 +1691,11 @@ static const zend_function_entry class_Dom_Element_methods[] = { ZEND_ME(Dom_Element, querySelectorAll, arginfo_class_Dom_Element_querySelectorAll, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, closest, arginfo_class_Dom_Element_closest, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, matches, arginfo_class_Dom_Element_matches, ZEND_ACC_PUBLIC) + ZEND_ME(Dom_Element, up, arginfo_class_Dom_Element_up, ZEND_ACC_PUBLIC) + ZEND_ME(Dom_Element, down, arginfo_class_Dom_Element_down, ZEND_ACC_PUBLIC) + ZEND_ME(Dom_Element, next, arginfo_class_Dom_Element_next, ZEND_ACC_PUBLIC) + ZEND_ME(Dom_Element, previous, arginfo_class_Dom_Element_previous, ZEND_ACC_PUBLIC) + ZEND_ME(Dom_Element, siblings, arginfo_class_Dom_Element_siblings, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, getInScopeNamespaces, arginfo_class_Dom_Element_getInScopeNamespaces, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, getDescendantNamespaces, arginfo_class_Dom_Element_getDescendantNamespaces, ZEND_ACC_PUBLIC) ZEND_ME(Dom_Element, rename, arginfo_class_Dom_Element_rename, ZEND_ACC_PUBLIC) diff --git a/ext/dom/php_dom_decl.h b/ext/dom/php_dom_decl.h index e42fe5969595..94a1fc6d758e 100644 --- a/ext/dom/php_dom_decl.h +++ b/ext/dom/php_dom_decl.h @@ -1,8 +1,8 @@ /* This is a generated file, edit php_dom.stub.php instead. - * Stub hash: 8d7713834c924709155ed7acc554c9efc55e96c1 */ + * Stub hash: f53e8ef8b543d089b51a72828c57efa10acdc98d */ -#ifndef ZEND_PHP_DOM_DECL_8d7713834c924709155ed7acc554c9efc55e96c1_H -#define ZEND_PHP_DOM_DECL_8d7713834c924709155ed7acc554c9efc55e96c1_H +#ifndef ZEND_PHP_DOM_DECL_f53e8ef8b543d089b51a72828c57efa10acdc98d_H +#define ZEND_PHP_DOM_DECL_f53e8ef8b543d089b51a72828c57efa10acdc98d_H typedef enum zend_enum_Dom_AdjacentPosition { ZEND_ENUM_Dom_AdjacentPosition_BeforeBegin = 1, @@ -11,4 +11,4 @@ typedef enum zend_enum_Dom_AdjacentPosition { ZEND_ENUM_Dom_AdjacentPosition_AfterEnd = 4, } zend_enum_Dom_AdjacentPosition; -#endif /* ZEND_PHP_DOM_DECL_8d7713834c924709155ed7acc554c9efc55e96c1_H */ +#endif /* ZEND_PHP_DOM_DECL_f53e8ef8b543d089b51a72828c57efa10acdc98d_H */ diff --git a/ext/dom/tests/modern/traversal_prototype.phpt b/ext/dom/tests/modern/traversal_prototype.phpt new file mode 100644 index 000000000000..79f539c9df9b --- /dev/null +++ b/ext/dom/tests/modern/traversal_prototype.phpt @@ -0,0 +1,85 @@ +--TEST-- +DOM\Element Prototype.js like DOM-Traversal +--EXTENSIONS-- +dom +--FILE-- + + +
+