diff --git a/external/njs_xml_module.c b/external/njs_xml_module.c index 95e5024a0..f1d275aa3 100644 --- a/external/njs_xml_module.c +++ b/external/njs_xml_module.c @@ -96,11 +96,11 @@ static njs_int_t njs_xml_node_ext_text(njs_vm_t *vm, njs_object_prop_t *prop, static njs_int_t njs_xml_node_attr_handler(njs_vm_t *vm, xmlNode *current, njs_str_t *name, njs_value_t *setval, njs_value_t *retval); -static njs_int_t njs_xml_node_tag_remove(njs_vm_t *vm, xmlNode *current, +static njs_int_t njs_xml_node_tag_remove(njs_vm_t *vm, njs_value_t *value, njs_str_t *name); -static njs_int_t njs_xml_node_tag_handler(njs_vm_t *vm, xmlNode *current, +static njs_int_t njs_xml_node_tag_handler(njs_vm_t *vm, njs_value_t *value, njs_str_t *name, njs_value_t *setval, njs_value_t *retval); -static njs_int_t njs_xml_node_tags_handler(njs_vm_t *vm, xmlNode *current, +static njs_int_t njs_xml_node_tags_handler(njs_vm_t *vm, njs_value_t *value, njs_str_t *name, njs_value_t *setval, njs_value_t *retval); static xmlNode *njs_xml_external_node(njs_vm_t *vm, njs_value_t *value); @@ -110,7 +110,7 @@ static const u_char *njs_xml_value_to_c_string(njs_vm_t *vm, njs_value_t *value, u_char *dst, size_t size); static njs_int_t njs_xml_encode_special_chars(njs_vm_t *vm, njs_str_t *src, njs_str_t *out); -static njs_int_t njs_xml_replace_node(njs_vm_t *vm, xmlNode *old, +static njs_int_t njs_xml_replace_node(njs_vm_t *vm, njs_value_t *value, xmlNode *current); static void njs_xml_node_cleanup(void *data); static void njs_xml_doc_cleanup(void *data); @@ -706,7 +706,7 @@ njs_xml_node_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, name.length -= njs_length("$tag$"); name.start += njs_length("$tag$"); - return njs_xml_node_tag_handler(vm, current, &name, setval, retval); + return njs_xml_node_tag_handler(vm, value, &name, setval, retval); } if (name.length >= njs_length("$tags$") @@ -715,12 +715,11 @@ njs_xml_node_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, name.length -= njs_length("$tags$"); name.start += njs_length("$tags$"); - return njs_xml_node_tags_handler(vm, current, &name, setval, - retval); + return njs_xml_node_tags_handler(vm, value, &name, setval, retval); } } - return njs_xml_node_tag_handler(vm, current, &name, setval, retval); + return njs_xml_node_tag_handler(vm, value, &name, setval, retval); } @@ -770,7 +769,7 @@ njs_xml_node_ext_add_child(njs_vm_t *vm, njs_value_t *args, njs_value_undefined_set(retval); - return njs_xml_replace_node(vm, current, copy); + return njs_xml_replace_node(vm, njs_argument(args, 0), copy); error: @@ -792,8 +791,8 @@ njs_xml_node_ext_attrs(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, return NJS_DECLINED; } - return njs_vm_external_create(vm, retval, njs_xml_attr_proto_id, - current->properties, 0); + return njs_vm_external_create(vm, retval, njs_xml_attr_proto_id, current, + 0); } @@ -909,7 +908,7 @@ njs_xml_node_ext_remove_children(njs_vm_t *vm, njs_value_t *args, njs_value_string_get(vm, selector, &name); - return njs_xml_node_tag_remove(vm, current, &name); + return njs_xml_node_tag_remove(vm, njs_argument(args, 0), &name); } /* all. */ @@ -925,7 +924,7 @@ njs_xml_node_ext_remove_children(njs_vm_t *vm, njs_value_t *args, copy->children = NULL; } - return njs_xml_replace_node(vm, current, copy); + return njs_xml_replace_node(vm, njs_argument(args, 0), copy); } @@ -990,7 +989,7 @@ njs_xml_node_ext_tags(njs_vm_t *vm, njs_object_prop_t *prop, uint32_t unused, name.start = NULL; name.length = 0; - return njs_xml_node_tags_handler(vm, current, &name, setval, retval); + return njs_xml_node_tags_handler(vm, value, &name, setval, retval); } @@ -1051,7 +1050,7 @@ njs_xml_node_ext_text(njs_vm_t *vm, njs_object_prop_t *unused, uint32_t unused1, njs_value_undefined_set(retval); } - return njs_xml_replace_node(vm, current, copy); + return njs_xml_replace_node(vm, value, copy); } @@ -1143,11 +1142,12 @@ njs_xml_node_attr_handler(njs_vm_t *vm, xmlNode *current, njs_str_t *name, static njs_int_t -njs_xml_node_tag_remove(njs_vm_t *vm, xmlNode *current, njs_str_t *name) +njs_xml_node_tag_remove(njs_vm_t *vm, njs_value_t *value, njs_str_t *name) { size_t size; - xmlNode *node, *next, *copy; - njs_int_t ret; + xmlNode *current, *node, *next, *copy; + + current = njs_vm_external(vm, njs_xml_node_proto_id, value); copy = xmlDocCopyNode(current, current->doc, 1); if (njs_slow_path(copy == NULL)) { @@ -1170,23 +1170,22 @@ njs_xml_node_tag_remove(njs_vm_t *vm, xmlNode *current, njs_str_t *name) continue; } - ret = njs_xml_replace_node(vm, node, NULL); - if (njs_slow_path(ret != NJS_OK)) { - xmlFreeNode(copy); - return NJS_ERROR; - } + xmlUnlinkNode(node); + xmlFreeNode(node); } - return njs_xml_replace_node(vm, current, copy); + return njs_xml_replace_node(vm, value, copy); } static njs_int_t -njs_xml_node_tag_handler(njs_vm_t *vm, xmlNode *current, njs_str_t *name, +njs_xml_node_tag_handler(njs_vm_t *vm, njs_value_t *value, njs_str_t *name, njs_value_t *setval, njs_value_t *retval) { size_t size; - xmlNode *node; + xmlNode *current, *node; + + current = njs_vm_external(vm, njs_xml_node_proto_id, value); if (retval != NULL && setval == NULL) { @@ -1223,21 +1222,23 @@ njs_xml_node_tag_handler(njs_vm_t *vm, xmlNode *current, njs_str_t *name, /* delete. */ - return njs_xml_node_tag_remove(vm, current, name); + return njs_xml_node_tag_remove(vm, value, name); } static njs_int_t -njs_xml_node_tags_handler(njs_vm_t *vm, xmlNode *current, njs_str_t *name, +njs_xml_node_tags_handler(njs_vm_t *vm, njs_value_t *value, njs_str_t *name, njs_value_t *setval, njs_value_t *retval) { size_t size; int64_t i, length; - xmlNode *node, *rnode, *copy; + xmlNode *current, *node, *rnode, *copy; njs_int_t ret; njs_value_t *push; njs_opaque_value_t *start; + current = njs_vm_external(vm, njs_xml_node_proto_id, value); + if (retval != NULL && setval == NULL) { /* get. */ @@ -1294,7 +1295,7 @@ njs_xml_node_tags_handler(njs_vm_t *vm, xmlNode *current, njs_str_t *name, if (retval == NULL) { /* delete. */ - return njs_xml_replace_node(vm, current, copy); + return njs_xml_replace_node(vm, value, copy); } if (!njs_value_is_array(setval)) { @@ -1338,7 +1339,7 @@ njs_xml_node_tags_handler(njs_vm_t *vm, xmlNode *current, njs_str_t *name, njs_value_undefined_set(retval); - return njs_xml_replace_node(vm, current, copy); + return njs_xml_replace_node(vm, value, copy); error: @@ -1512,9 +1513,12 @@ njs_xml_encode_special_chars(njs_vm_t *vm, njs_str_t *src, njs_str_t *out) static njs_int_t -njs_xml_replace_node(njs_vm_t *vm, xmlNode *old, xmlNode *current) +njs_xml_replace_node(njs_vm_t *vm, njs_value_t *value, xmlNode *current) { - njs_mp_cleanup_t *cln; + xmlNode *old; + njs_mp_cleanup_t *cln; + + old = njs_vm_external(vm, njs_xml_node_proto_id, value); if (current != NULL) { old = xmlReplaceNode(old, current); @@ -1523,6 +1527,8 @@ njs_xml_replace_node(njs_vm_t *vm, xmlNode *old, xmlNode *current) xmlUnlinkNode(old); } + njs_value_external_set(value, current); + cln = njs_mp_cleanup_add(njs_vm_memory_pool(vm), 0); if (njs_slow_path(cln == NULL)) { njs_vm_memory_error(vm); @@ -1846,7 +1852,8 @@ njs_xml_ext_canonicalization(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs, static njs_int_t njs_xml_attr_ext_prop_keys(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys) { - xmlAttr *node, *current; + xmlAttr *node; + xmlNode *current; njs_int_t ret; njs_value_t *push; @@ -1861,7 +1868,7 @@ njs_xml_attr_ext_prop_keys(njs_vm_t *vm, njs_value_t *value, njs_value_t *keys) return NJS_ERROR; } - for (node = current; node != NULL; node = node->next) { + for (node = current->properties; node != NULL; node = node->next) { if (node->type != XML_ATTRIBUTE_NODE) { continue; } @@ -1888,7 +1895,8 @@ njs_xml_attr_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, njs_value_t *retval) { size_t size; - xmlAttr *node, *current; + xmlAttr *node; + xmlNode *current; njs_int_t ret; njs_str_t name; @@ -1904,7 +1912,7 @@ njs_xml_attr_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, return NJS_DECLINED; } - for (node = current; node != NULL; node = node->next) { + for (node = current->properties; node != NULL; node = node->next) { if (node->type != XML_ATTRIBUTE_NODE) { continue; } @@ -1921,6 +1929,8 @@ njs_xml_attr_ext_prop_handler(njs_vm_t *vm, njs_object_prop_t *prop, njs_strlen(node->children->content)); } + njs_value_undefined_set(retval); + return NJS_OK; } diff --git a/external/qjs_xml_module.c b/external/qjs_xml_module.c index 8f90ee5cd..af297e5be 100644 --- a/external/qjs_xml_module.c +++ b/external/qjs_xml_module.c @@ -27,7 +27,7 @@ typedef struct { typedef struct { - xmlAttr *attr; + xmlNode *node; qjs_xml_doc_t *doc; } qjs_xml_attr_t; @@ -93,7 +93,7 @@ static void qjs_xml_node_finalizer(JSRuntime *rt, JSValue val); static xmlNode *qjs_xml_node(JSContext *cx, JSValueConst val, xmlDoc **doc); static JSValue qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, - xmlAttr *attr); + xmlNode *node); static int qjs_xml_attr_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, JSValueConst obj, JSAtom prop); static int qjs_xml_attr_get_own_property_names(JSContext *cx, @@ -955,8 +955,7 @@ qjs_xml_node_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, pdesc->flags = JS_PROP_ENUMERABLE; pdesc->getter = JS_UNDEFINED; pdesc->setter = JS_UNDEFINED; - pdesc->value = qjs_xml_attr_make(cx, current->doc, - node->properties); + pdesc->value = qjs_xml_attr_make(cx, current->doc, node); if (JS_IsException(pdesc->value)) { return -1; } @@ -1573,7 +1572,7 @@ qjs_xml_node(JSContext *cx, JSValueConst val, xmlDoc **doc) static JSValue -qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, xmlAttr *attr) +qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, xmlNode *node) { JSValue ret; qjs_xml_attr_t *current; @@ -1584,7 +1583,7 @@ qjs_xml_attr_make(JSContext *cx, qjs_xml_doc_t *doc, xmlAttr *attr) return JS_EXCEPTION; } - current->attr = attr; + current->node = node; current->doc = doc; doc->ref_count++; @@ -1623,7 +1622,7 @@ qjs_xml_attr_get_own_property(JSContext *cx, JSPropertyDescriptor *pdesc, name.length = njs_strlen(name.start); - for (attr = current->attr; attr != NULL; attr = attr->next) { + for (attr = current->node->properties; attr != NULL; attr = attr->next) { if (attr->type != XML_ATTRIBUTE_NODE) { continue; } @@ -1685,7 +1684,7 @@ qjs_xml_attr_get_own_property_names(JSContext *cx, JSPropertyEnum **ptab, return -1; } - for (attr = current->attr; attr != NULL; attr = attr->next) { + for (attr = current->node->properties; attr != NULL; attr = attr->next) { if (attr->type != XML_ATTRIBUTE_NODE) { continue; } @@ -2033,6 +2032,8 @@ qjs_xml_replace_node(JSContext *cx, qjs_xml_node_t *node, xmlNode *current) xmlUnlinkNode(old); } + node->node = current; + old->next = node->doc->free; node->doc->free = old; } diff --git a/test/xml/xml.t.mjs b/test/xml/xml.t.mjs index 29e2fb412..4533c8ada 100644 --- a/test/xml/xml.t.mjs +++ b/test/xml/xml.t.mjs @@ -165,6 +165,25 @@ let modify_tsuite = { return doc.note.$text; }, expected: 'WAKA' }, + { get: (doc) => { + doc.note.setText('WAKA'); + doc.note.setText('OVERWRITE'); + return doc.note.$text; + }, + expected: 'OVERWRITE' }, + { get: (doc) => { + let note = doc.note; + note.setText('WAKA'); + note.setText('OVERWRITE'); + return note.$text; + }, + expected: 'OVERWRITE' }, + { get: (doc) => { + let note = doc.note; + note.setText('WAKA'); + return doc.note.$text; + }, + expected: 'WAKA' }, { get: (doc) => { doc.note.setText('WAKA'); return xml.serializeToString(doc); @@ -275,6 +294,19 @@ let modify_tsuite = { return xml.serializeToString(doc.note.to); }, expected: `Tove` }, + { get: (doc) => { + let attrs = doc.note.to.$attrs; + doc.note.to.removeAllAttributes(); + return attrs.a; + }, + expected: undefined }, + { get: (doc) => { + let to = doc.note.to; + let attrs = doc.note.to.$attrs; + to.removeAllAttributes(); + return attrs.a; + }, + expected: undefined }, { get: (doc) => { delete doc.note.to.$attr$a; return xml.serializeToString(doc.note.to); @@ -308,6 +340,12 @@ let modify_tsuite = { return xml.serializeToString(doc); }, expected: `Jani` }, + { get: (doc) => { + let note = doc.note; + note.removeChildren('to'); + return xml.serializeToString(doc); + }, + expected: `Jani` }, { get: (doc) => { delete doc.note.$tag$to; return xml.serializeToString(doc);