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);