Skip to content

Commit c7c6a79

Browse files
authored
Add support for ParentNode::$children (#18908)
ParentNode::$children returns a HTMLCollection of all directly descendant child elements of a container. I had to move around some properties such that the ParentNode property offsets are always at a fixed offset, to simplify the code. This also adds the necessary code to deal with GC cycles in HTMLCollections. Furthermore, we also disable cloning a HTMLCollection as that never worked and furthermore it also conflicts with the [[SameObject]] WebIDL requirement of $children.
1 parent 1b7f456 commit c7c6a79

24 files changed

+372
-129
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ PHP NEWS
7474
- DOM:
7575
. Added Dom\Element::$outerHTML. (nielsdos)
7676
. Added Dom\Element::insertAdjacentHTML(). (nielsdos)
77+
. Added $children property to ParentNode implementations. (nielsdos)
7778

7879
- Enchant:
7980
. Added enchant_dict_remove_from_session(). (nielsdos)

UPGRADING

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ PHP 8.5 UPGRADE NOTES
185185

186186
- DOM:
187187
. Added Dom\Element::$outerHTML.
188+
. Added $children property to Dom\ParentNode implementations.
188189

189190
- EXIF:
190191
. Add OffsetTime* Exif tags.

ext/dom/dom_properties.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ zend_result dom_entity_reference_child_nodes_read(dom_object *obj, zval *retval)
109109
zend_result dom_namednodemap_length_read(dom_object *obj, zval *retval);
110110

111111
/* parent node properties */
112+
zend_result dom_parent_node_children_read(dom_object *obj, zval *retval);
112113
zend_result dom_parent_node_first_element_child_read(dom_object *obj, zval *retval);
113114
zend_result dom_parent_node_last_element_child_read(dom_object *obj, zval *retval);
114115
zend_result dom_parent_node_child_element_count(dom_object *obj, zval *retval);

ext/dom/element.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,18 +177,21 @@ zend_result dom_element_class_name_write(dom_object *obj, zval *newval)
177177
}
178178
/* }}} */
179179

180-
zval *dom_element_class_list_zval(dom_object *obj)
180+
zval *dom_get_prop_checked_offset(dom_object *obj, uint32_t offset, const char *name)
181181
{
182-
const uint32_t PROP_INDEX = 0;
183-
184182
#if ZEND_DEBUG
185-
zend_string *class_list_str = ZSTR_INIT_LITERAL("classList", false);
186-
const zend_property_info *prop_info = zend_get_property_info(dom_modern_element_class_entry, class_list_str, 0);
187-
zend_string_release_ex(class_list_str, false);
188-
ZEND_ASSERT(OBJ_PROP_TO_NUM(prop_info->offset) == PROP_INDEX);
183+
zend_string *name_zstr = ZSTR_INIT_LITERAL(name, false);
184+
const zend_property_info *prop_info = zend_get_property_info(obj->std.ce, name_zstr, 0);
185+
zend_string_release_ex(name_zstr, false);
186+
ZEND_ASSERT(OBJ_PROP_TO_NUM(prop_info->offset) == offset);
189187
#endif
190188

191-
return OBJ_PROP_NUM(&obj->std, PROP_INDEX);
189+
return OBJ_PROP_NUM(&obj->std, offset);
190+
}
191+
192+
zval *dom_element_class_list_zval(dom_object *obj)
193+
{
194+
return dom_get_prop_checked_offset(obj, 1, "classList");
192195
}
193196

194197
/* {{{ classList TokenList

ext/dom/html_collection.c

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,23 @@ static dom_named_item dom_html_collection_named_item(zend_string *key, zend_obje
5050
zend_long cur = 0;
5151
zend_long next = cur; /* not +1, otherwise we skip the first candidate */
5252
xmlNodePtr candidate = basep->children;
53+
bool iterate_tag_name = objmap->handler == &php_dom_obj_map_by_tag_name;
5354
while (candidate != NULL) {
54-
candidate = dom_get_elements_by_tag_name_ns_raw(basep, candidate, objmap->ns, objmap->local, objmap->local_lower, &cur, next);
55-
if (candidate == NULL) {
56-
break;
55+
if (iterate_tag_name) {
56+
candidate = dom_get_elements_by_tag_name_ns_raw(basep, candidate, objmap->ns, objmap->local, objmap->local_lower, &cur, next);
57+
if (candidate == NULL) {
58+
break;
59+
}
60+
next = cur + 1;
61+
} else {
62+
if (candidate->type != XML_ELEMENT_NODE) {
63+
candidate = candidate->next;
64+
continue;
65+
}
5766
}
5867

68+
ZEND_ASSERT(candidate->type == XML_ELEMENT_NODE);
69+
5970
xmlAttrPtr attr;
6071

6172
/* it has an ID which is key; */
@@ -73,7 +84,9 @@ static dom_named_item dom_html_collection_named_item(zend_string *key, zend_obje
7384
}
7485
}
7586

76-
next = cur + 1;
87+
if (!iterate_tag_name) {
88+
candidate = candidate->next;
89+
}
7790
}
7891
}
7992

@@ -141,4 +154,23 @@ int dom_html_collection_has_dimension(zend_object *object, zval *member, int che
141154
}
142155
}
143156

157+
HashTable *dom_html_collection_get_gc(zend_object *object, zval **table, int *n)
158+
{
159+
dom_nnodemap_object *objmap = php_dom_obj_from_obj(object)->ptr;
160+
161+
if (objmap->baseobj) {
162+
zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create();
163+
zend_get_gc_buffer_add_obj(gc_buffer, &objmap->baseobj->std);
164+
zend_get_gc_buffer_use(gc_buffer, table, n);
165+
166+
if (object->properties == NULL && object->ce->default_properties_count == 0) {
167+
return NULL;
168+
} else {
169+
return zend_std_get_properties(object);
170+
}
171+
} else {
172+
return zend_std_get_gc(object, table, n);
173+
}
174+
}
175+
144176
#endif

ext/dom/html_collection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@
1919

2020
zval *dom_html_collection_read_dimension(zend_object *object, zval *offset, int type, zval *rv);
2121
int dom_html_collection_has_dimension(zend_object *object, zval *member, int check_empty);
22+
HashTable *dom_html_collection_get_gc(zend_object *object, zval **table, int *n);
2223

2324
#endif

ext/dom/html_document.c

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,16 +84,7 @@ typedef struct dom_decoding_encoding_ctx {
8484
/* https://dom.spec.whatwg.org/#dom-document-implementation */
8585
zend_result dom_modern_document_implementation_read(dom_object *obj, zval *retval)
8686
{
87-
const uint32_t PROP_INDEX = 0;
88-
89-
#if ZEND_DEBUG
90-
zend_string *implementation_str = ZSTR_INIT_LITERAL("implementation", false);
91-
const zend_property_info *prop_info = zend_get_property_info(dom_abstract_base_document_class_entry, implementation_str, 0);
92-
zend_string_release_ex(implementation_str, false);
93-
ZEND_ASSERT(OBJ_PROP_TO_NUM(prop_info->offset) == PROP_INDEX);
94-
#endif
95-
96-
zval *cached_implementation = OBJ_PROP_NUM(&obj->std, PROP_INDEX);
87+
zval *cached_implementation = dom_get_prop_checked_offset(obj, 1, "implementation");
9788
if (Z_ISUNDEF_P(cached_implementation)) {
9889
php_dom_create_implementation(cached_implementation, true);
9990
}

ext/dom/obj_map.c

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@
2828
static zend_always_inline void objmap_cache_release_cached_obj(dom_nnodemap_object *objmap)
2929
{
3030
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);
3532
objmap->cached_obj = NULL;
3633
objmap->cached_obj_index = 0;
3734
}
@@ -82,6 +79,20 @@ static zend_long dom_map_get_nodes_length(dom_nnodemap_object *map)
8279
return count;
8380
}
8481

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+
8596
static zend_long dom_map_get_by_tag_name_length(dom_nnodemap_object *map)
8697
{
8798
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
223234
}
224235
}
225236

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+
226269
static void dom_map_get_by_tag_name_item(dom_nnodemap_object *map, zend_long index, zval *return_value)
227270
{
228271
xmlNodePtr nodep = dom_object_get_node(map->baseobj);
@@ -456,6 +499,15 @@ const php_dom_obj_map_handler php_dom_obj_map_notations = {
456499
.nameless = false,
457500
};
458501

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+
459511
const php_dom_obj_map_handler php_dom_obj_map_noop = {
460512
.length = dom_map_get_zero_length,
461513
.get_item = dom_map_get_null_item,

ext/dom/obj_map.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ zend_long php_dom_get_nodelist_length(dom_object *obj);
5757

5858
extern const php_dom_obj_map_handler php_dom_obj_map_attributes;
5959
extern const php_dom_obj_map_handler php_dom_obj_map_by_tag_name;
60+
extern const php_dom_obj_map_handler php_dom_obj_map_child_elements;
6061
extern const php_dom_obj_map_handler php_dom_obj_map_child_nodes;
6162
extern const php_dom_obj_map_handler php_dom_obj_map_nodeset;
6263
extern const php_dom_obj_map_handler php_dom_obj_map_entities;

ext/dom/parentnode/tree.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,34 @@
2222
#include "php.h"
2323
#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
2424
#include "../php_dom.h"
25+
#include "../obj_map.h"
2526
#include "../internal_helpers.h"
2627
#include "../dom_properties.h"
2728

29+
zval *dom_parent_node_children(dom_object *obj)
30+
{
31+
return dom_get_prop_checked_offset(obj, 0, "children");
32+
}
33+
34+
zend_result dom_parent_node_children_read(dom_object *obj, zval *retval)
35+
{
36+
zval *cached_children = dom_parent_node_children(obj);
37+
if (Z_ISUNDEF_P(cached_children)) {
38+
object_init_ex(cached_children, dom_html_collection_class_entry);
39+
php_dom_create_obj_map(obj, Z_DOMOBJ_P(cached_children), NULL, NULL, NULL, &php_dom_obj_map_child_elements);
40+
41+
/* Handle cycles for potential TMPVARs (could also be CV but we can't differentiate).
42+
* RC == 2 because of 1 TMPVAR and 1 in HTMLCollection. */
43+
if (GC_REFCOUNT(&obj->std) == 2) {
44+
gc_possible_root(Z_COUNTED_P(cached_children));
45+
}
46+
}
47+
48+
ZVAL_OBJ_COPY(retval, Z_OBJ_P(cached_children));
49+
50+
return SUCCESS;
51+
}
52+
2853
/* {{{ firstElementChild DomParentNode
2954
readonly=yes
3055
URL: https://www.w3.org/TR/dom/#dom-parentnode-firstelementchild

ext/dom/php_dom.c

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ PHP_DOM_EXPORT zend_class_entry *dom_namespace_info_class_entry;
9696
static zend_object_handlers dom_object_handlers;
9797
static zend_object_handlers dom_nnodemap_object_handlers;
9898
static zend_object_handlers dom_nodelist_object_handlers;
99+
static zend_object_handlers dom_unset_children_property_object_handlers;
99100
static zend_object_handlers dom_modern_nnodemap_object_handlers;
100101
static zend_object_handlers dom_modern_nodelist_object_handlers;
101102
static zend_object_handlers dom_html_collection_object_handlers;
@@ -668,14 +669,35 @@ static zend_object *dom_objects_store_clone_obj(zend_object *zobject) /* {{{ */
668669
static zend_object *dom_modern_element_clone_obj(zend_object *zobject)
669670
{
670671
zend_object *clone = dom_objects_store_clone_obj(zobject);
672+
dom_object *intern = php_dom_obj_from_obj(clone);
671673

672674
/* The $classList property is unique per element, and cached due to its [[SameObject]] requirement.
673675
* Remove it from the clone so the clone will get a fresh instance upon demand. */
674-
zval *class_list = dom_element_class_list_zval(php_dom_obj_from_obj(clone));
676+
zval *class_list = dom_element_class_list_zval(intern);
675677
if (!Z_ISUNDEF_P(class_list)) {
676678
zval_ptr_dtor(class_list);
677679
ZVAL_UNDEF(class_list);
678680
}
681+
/* Likewise for $children */
682+
zval *children = dom_parent_node_children(intern);
683+
if (!Z_ISUNDEF_P(children)) {
684+
zval_ptr_dtor(children);
685+
ZVAL_UNDEF(children);
686+
}
687+
688+
return clone;
689+
}
690+
691+
static zend_object *dom_clone_obj_unset_children_property(zend_object *zobject)
692+
{
693+
zend_object *clone = dom_objects_store_clone_obj(zobject);
694+
dom_object *intern = php_dom_obj_from_obj(clone);
695+
696+
zval *children = dom_parent_node_children(intern);
697+
if (!Z_ISUNDEF_P(children)) {
698+
zval_ptr_dtor(children);
699+
ZVAL_UNDEF(children);
700+
}
679701

680702
return clone;
681703
}
@@ -777,6 +799,9 @@ PHP_MINIT_FUNCTION(dom)
777799
memcpy(&dom_modern_element_object_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
778800
dom_modern_element_object_handlers.clone_obj = dom_modern_element_clone_obj;
779801

802+
memcpy(&dom_unset_children_property_object_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
803+
dom_unset_children_property_object_handlers.clone_obj = dom_clone_obj_unset_children_property;
804+
780805
memcpy(&dom_nnodemap_object_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
781806
dom_nnodemap_object_handlers.free_obj = dom_nnodemap_objects_free_storage;
782807
dom_nnodemap_object_handlers.read_dimension = dom_nodemap_read_dimension;
@@ -797,6 +822,8 @@ PHP_MINIT_FUNCTION(dom)
797822
memcpy(&dom_html_collection_object_handlers, &dom_modern_nodelist_object_handlers, sizeof(zend_object_handlers));
798823
dom_html_collection_object_handlers.read_dimension = dom_html_collection_read_dimension;
799824
dom_html_collection_object_handlers.has_dimension = dom_html_collection_has_dimension;
825+
dom_html_collection_object_handlers.get_gc = dom_html_collection_get_gc;
826+
dom_html_collection_object_handlers.clone_obj = NULL;
800827

801828
memcpy(&dom_object_namespace_node_handlers, &dom_object_handlers, sizeof(zend_object_handlers));
802829
dom_object_namespace_node_handlers.offset = XtOffsetOf(dom_object_namespace_node, dom.std);
@@ -911,9 +938,10 @@ PHP_MINIT_FUNCTION(dom)
911938

912939
dom_modern_documentfragment_class_entry = register_class_Dom_DocumentFragment(dom_modern_node_class_entry, dom_modern_parentnode_class_entry);
913940
dom_modern_documentfragment_class_entry->create_object = dom_objects_new;
914-
dom_modern_documentfragment_class_entry->default_object_handlers = &dom_object_handlers;
941+
dom_modern_documentfragment_class_entry->default_object_handlers = &dom_unset_children_property_object_handlers;
915942
zend_hash_init(&dom_modern_documentfragment_prop_handlers, 0, NULL, NULL, true);
916943

944+
DOM_REGISTER_PROP_HANDLER(&dom_modern_documentfragment_prop_handlers, "children", dom_parent_node_children_read, NULL);
917945
DOM_REGISTER_PROP_HANDLER(&dom_modern_documentfragment_prop_handlers, "firstElementChild", dom_parent_node_first_element_child_read, NULL);
918946
DOM_REGISTER_PROP_HANDLER(&dom_modern_documentfragment_prop_handlers, "lastElementChild", dom_parent_node_last_element_child_read, NULL);
919947
DOM_REGISTER_PROP_HANDLER(&dom_modern_documentfragment_prop_handlers, "childElementCount", dom_parent_node_child_element_count, NULL);
@@ -922,7 +950,7 @@ PHP_MINIT_FUNCTION(dom)
922950
zend_hash_add_new_ptr(&classes, dom_modern_documentfragment_class_entry->name, &dom_modern_documentfragment_prop_handlers);
923951

924952
dom_abstract_base_document_class_entry = register_class_Dom_Document(dom_modern_node_class_entry, dom_modern_parentnode_class_entry);
925-
dom_abstract_base_document_class_entry->default_object_handlers = &dom_object_handlers;
953+
dom_abstract_base_document_class_entry->default_object_handlers = &dom_unset_children_property_object_handlers;
926954
zend_hash_init(&dom_abstract_base_document_prop_handlers, 0, NULL, NULL, true);
927955
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "implementation", dom_modern_document_implementation_read, NULL);
928956
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "URL", dom_document_document_uri_read, dom_document_document_uri_write);
@@ -932,6 +960,7 @@ PHP_MINIT_FUNCTION(dom)
932960
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "inputEncoding", dom_document_encoding_read, dom_html_document_encoding_write);
933961
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "doctype", dom_document_doctype_read, NULL);
934962
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "documentElement", dom_document_document_element_read, NULL);
963+
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "children", dom_parent_node_children_read, NULL);
935964
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "firstElementChild", dom_parent_node_first_element_child_read, NULL);
936965
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "lastElementChild", dom_parent_node_last_element_child_read, NULL);
937966
DOM_REGISTER_PROP_HANDLER(&dom_abstract_base_document_prop_handlers, "childElementCount", dom_parent_node_child_element_count, NULL);
@@ -1118,6 +1147,7 @@ PHP_MINIT_FUNCTION(dom)
11181147
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "className", dom_element_class_name_read, dom_element_class_name_write);
11191148
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "classList", dom_element_class_list_read, NULL);
11201149
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "attributes", dom_node_attributes_read, NULL);
1150+
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "children", dom_parent_node_children_read, NULL);
11211151
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "firstElementChild", dom_parent_node_first_element_child_read, NULL);
11221152
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "lastElementChild", dom_parent_node_last_element_child_read, NULL);
11231153
DOM_REGISTER_PROP_HANDLER(&dom_modern_element_prop_handlers, "childElementCount", dom_parent_node_child_element_count, NULL);
@@ -1534,8 +1564,8 @@ void dom_nnodemap_objects_free_storage(zend_object *object) /* {{{ */
15341564
dom_nnodemap_object *objmap = (dom_nnodemap_object *)intern->ptr;
15351565

15361566
if (objmap) {
1537-
if (objmap->cached_obj && GC_DELREF(&objmap->cached_obj->std) == 0) {
1538-
zend_objects_store_del(&objmap->cached_obj->std);
1567+
if (objmap->cached_obj) {
1568+
OBJ_RELEASE(&objmap->cached_obj->std);
15391569
}
15401570
if (objmap->release_local) {
15411571
dom_zend_string_release_from_char_pointer(objmap->local);

ext/dom/php_dom.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,11 @@ bool php_dom_create_nullable_object(xmlNodePtr obj, zval *return_value, dom_obje
160160
xmlNodePtr dom_clone_node(php_dom_libxml_ns_mapper *ns_mapper, xmlNodePtr node, xmlDocPtr doc, bool recursive);
161161
void dom_set_document_ref_pointers(xmlNodePtr node, php_libxml_ref_obj *document);
162162
void dom_set_document_ref_pointers_attr(xmlAttrPtr attr, php_libxml_ref_obj *document);
163+
164+
/* Prop getters by offset */
165+
zval *dom_get_prop_checked_offset(dom_object *obj, uint32_t offset, const char *name);
163166
zval *dom_element_class_list_zval(dom_object *obj);
167+
zval *dom_parent_node_children(dom_object *obj);
164168

165169
typedef enum {
166170
DOM_LOAD_STRING = 0,

0 commit comments

Comments
 (0)