parser xml UPDATE opaq node values
Forbid mixed nodes for opaque nodes but
store even WS-only value for nodes without
descendants.
Fixes #2081
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 225fe15..b24e9fa 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -634,7 +634,10 @@
{
LY_ERR rc = LY_SUCCESS;
struct lyxml_ctx *xmlctx = lydctx->xmlctx;
- const char *ns_uri;
+ struct lyd_node_opaq *opaq;
+ const char *ns_uri, *value = NULL;
+ size_t value_len;
+ ly_bool ws_only, dynamic = 0;
const struct lyxml_ns *ns;
uint32_t hints;
void *val_prefix_data = NULL;
@@ -644,19 +647,17 @@
*node = NULL;
- if (xmlctx->ws_only) {
- /* ignore WS-only value */
- if (xmlctx->dynamic) {
- free((char *)xmlctx->value);
- }
+ /* remember the value */
+ value = xmlctx->value;
+ value_len = xmlctx->value_len;
+ ws_only = xmlctx->ws_only;
+ dynamic = xmlctx->dynamic;
+ if (dynamic) {
xmlctx->dynamic = 0;
- xmlctx->value = "";
- xmlctx->value_len = 0;
}
/* get value prefixes, if any */
- rc = ly_store_prefix_data(xmlctx->ctx, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns, &format,
- &val_prefix_data);
+ rc = ly_store_prefix_data(xmlctx->ctx, value, value_len, LY_VALUE_XML, &xmlctx->ns, &format, &val_prefix_data);
LY_CHECK_GOTO(rc, cleanup);
/* get NS again, it may have been backed up and restored */
@@ -666,11 +667,10 @@
/* get best-effort node hints */
lydxml_get_hints_opaq(name, name_len, xmlctx->value, xmlctx->value_len, sibling, ns_uri, &hints, insert_anchor);
- /* create node */
- rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns_uri, ns_uri ? strlen(ns_uri) : 0,
- xmlctx->value, xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, hints, node);
+ /* create the node without value */
+ rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns_uri, ns_uri ? strlen(ns_uri) : 0, NULL, 0,
+ NULL, format, NULL, hints, node);
LY_CHECK_GOTO(rc, cleanup);
- val_prefix_data = NULL;
/* parser next */
rc = lyxml_ctx_next(xmlctx);
@@ -682,8 +682,34 @@
LY_CHECK_GOTO(rc, cleanup);
}
+ /* update the value */
+ opaq = (struct lyd_node_opaq *)*node;
+ if (opaq->child) {
+ if (!ws_only) {
+ LOGVAL(xmlctx->ctx, LYVE_SYNTAX_XML, "Mixed XML content node \"%s\" found, not supported.", LYD_NAME(opaq));
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ } else if (value_len) {
+ lydict_remove(xmlctx->ctx, opaq->value);
+ if (dynamic) {
+ LY_CHECK_GOTO(rc = lydict_insert_zc(xmlctx->ctx, (char *)value, &opaq->value), cleanup);
+ dynamic = 0;
+ } else {
+ LY_CHECK_GOTO(rc = lydict_insert(xmlctx->ctx, value, value_len, &opaq->value), cleanup);
+ }
+ }
+
+ /* always store val_prefix_data because the format requires them */
+ assert(!opaq->val_prefix_data);
+ opaq->val_prefix_data = val_prefix_data;
+ val_prefix_data = NULL;
+
cleanup:
ly_free_prefix_data(format, val_prefix_data);
+ if (dynamic) {
+ free((char *)value);
+ }
if (rc) {
lyd_free_tree(*node);
*node = NULL;
@@ -1386,9 +1412,11 @@
LY_ERR rc = LY_SUCCESS;
const struct lyxml_ns *ns;
struct lyd_attr *attr = NULL;
- struct lyd_node *child = NULL;
- const char *name, *prefix;
- size_t name_len, prefix_len;
+ struct lyd_node *node = NULL;
+ struct lyd_node_opaq *opaq;
+ const char *name, *prefix, *value = NULL;
+ size_t name_len, prefix_len, value_len;
+ ly_bool ws_only, dynamic = 0;
assert(xmlctx->status == LYXML_ELEMENT);
@@ -1409,14 +1437,23 @@
LY_CHECK_RET(lydxml_attrs(xmlctx, &attr));
}
- /* create node */
+ /* remember the value */
assert(xmlctx->status == LYXML_ELEM_CONTENT);
- rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
- xmlctx->ws_only ? 0 : xmlctx->value_len, NULL, LY_VALUE_XML, NULL, 0, &child);
+ value = xmlctx->value;
+ value_len = xmlctx->value_len;
+ ws_only = xmlctx->ws_only;
+ dynamic = xmlctx->dynamic;
+ if (dynamic) {
+ xmlctx->dynamic = 0;
+ }
+
+ /* create the node without value */
+ rc = lyd_create_opaq(xmlctx->ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), NULL, 0, NULL,
+ LY_VALUE_XML, NULL, 0, &node);
LY_CHECK_GOTO(rc, cleanup);
/* assign atributes */
- ((struct lyd_node_opaq *)child)->attr = attr;
+ ((struct lyd_node_opaq *)node)->attr = attr;
attr = NULL;
/* parser next element */
@@ -1424,17 +1461,38 @@
/* parse all the descendants */
while (xmlctx->status == LYXML_ELEMENT) {
- rc = lydxml_opaq_r(xmlctx, child);
+ rc = lydxml_opaq_r(xmlctx, node);
LY_CHECK_GOTO(rc, cleanup);
}
/* insert */
- lyd_insert_node(parent, NULL, child, 1);
+ lyd_insert_node(parent, NULL, node, 1);
+
+ /* update the value */
+ opaq = (struct lyd_node_opaq *)node;
+ if (opaq->child) {
+ if (!ws_only) {
+ LOGVAL(xmlctx->ctx, LYVE_SYNTAX_XML, "Mixed XML content node \"%s\" found, not supported.", LYD_NAME(node));
+ rc = LY_EVALID;
+ goto cleanup;
+ }
+ } else if (value_len) {
+ lydict_remove(xmlctx->ctx, opaq->value);
+ if (dynamic) {
+ LY_CHECK_GOTO(rc = lydict_insert_zc(xmlctx->ctx, (char *)value, &opaq->value), cleanup);
+ dynamic = 0;
+ } else {
+ LY_CHECK_GOTO(rc = lydict_insert(xmlctx->ctx, value, value_len, &opaq->value), cleanup);
+ }
+ }
cleanup:
lyd_free_attr_siblings(xmlctx->ctx, attr);
+ if (dynamic) {
+ free((char *)value);
+ }
if (rc) {
- lyd_free_tree(child);
+ lyd_free_tree(node);
}
return rc;
}
diff --git a/tests/utests/data/test_printer_xml.c b/tests/utests/data/test_printer_xml.c
index d533c41..6213a37 100644
--- a/tests/utests/data/test_printer_xml.c
+++ b/tests/utests/data/test_printer_xml.c
@@ -145,7 +145,8 @@
" <cont>\n"
" <elem1 xmlns=\"urn:tests:defs\">\n"
" <elem2 xmlns=\"urn:tests:types\" xmlns:defs=\"urn:tests:defs\" xmlns:defaults=\"urn:defaults\" "
- "defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\"/>\n"
+ "defs:attr1=\"defaults:val\" attr2=\"/defaults:node/defs:node2\">\n"
+ " </elem2>\n"
" </elem1>\n"
" </cont>\n"
"</any>\n";