XML data FEATURE parse/print XML attributes mapped to Metadata annotations
diff --git a/src/log.c b/src/log.c
index 8efac1a..c3a6c13 100644
--- a/src/log.c
+++ b/src/log.c
@@ -476,12 +476,12 @@
}
ret = asprintf(&plugin_msg, "Extension plugin \"%s\": %s)", ext->def->plugin->id, format);
if (ret == -1) {
- LOGMEM(ext->def->module->ctx);
+ LOGMEM(ext->module->ctx);
return;
}
va_start(ap, format);
- log_vprintf(ext->def->module->ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0), err_no, path ? strdup(path) : NULL, plugin_msg, ap);
+ log_vprintf(ext->module->ctx, level, (level == LY_LLERR ? LY_EPLUGIN : 0), err_no, path ? strdup(path) : NULL, plugin_msg, ap);
va_end(ap);
free(plugin_msg);
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 6685e8b..d967fe9 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -67,6 +67,16 @@
return ly_ctx_get_module_implemented_ns(ctx, ns->uri);
}
+struct attr_data_s {
+ const char *prefix;
+ const char *name;
+ char *value;
+ size_t prefix_len;
+ size_t name_len;
+ size_t value_len;
+ int dynamic;
+};
+
/**
* @brief Parse XML attributes of the XML element of YANG data.
*
@@ -77,23 +87,13 @@
* @reutn LY_ERR value.
*/
static LY_ERR
-lydxml_attributes(struct lyd_xml_ctx *ctx, const char **data, struct lyd_attr **attributes)
+lydxml_attributes_parse(struct lyd_xml_ctx *ctx, const char **data, struct ly_set *attrs_data)
{
LY_ERR ret = LY_SUCCESS;
- unsigned int u, v;
+ unsigned int u;
const char *prefix, *name;
size_t prefix_len, name_len;
- struct lyd_attr *attr = NULL, *last = NULL;
- const struct lyxml_ns *ns;
- struct ly_set attr_datas = {0};
- struct attr_data_s {
- const char *prefix;
- char *value;
- size_t prefix_len;
- size_t value_len;
- int dynamic;
- } *attr_data;
- struct lys_module *mod;
+ struct attr_data_s *attr_data;
while(ctx->status == LYXML_ATTRIBUTE &&
lyxml_get_attribute((struct lyxml_context*)ctx, data, &prefix, &prefix_len, &name, &name_len) == LY_SUCCESS) {
@@ -110,60 +110,122 @@
* annotation definition for the attribute and correctly process the value */
attr_data = malloc(sizeof *attr_data);
attr_data->prefix = prefix;
+ attr_data->name = name;
attr_data->prefix_len = prefix_len;
+ attr_data->name_len = name_len;
ret = lyxml_get_string((struct lyxml_context *)ctx, data, &buffer, &buffer_size, &attr_data->value, &attr_data->value_len, &attr_data->dynamic);
- LY_CHECK_ERR_GOTO(ret, free(attr_data), cleanup);
- ly_set_add(&attr_datas, attr_data, LY_SET_OPT_USEASLIST);
+ LY_CHECK_ERR_GOTO(ret, free(attr_data), error);
+ ly_set_add(attrs_data, attr_data, LY_SET_OPT_USEASLIST);
+ }
+
+ return LY_SUCCESS;
+
+error:
+ for (u = 0; u < attrs_data->count; ++u) {
+ if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
+ free(((struct attr_data_s*)attrs_data->objs[u])->value);
+ }
+ }
+ ly_set_erase(attrs_data, free);
+ return ret;
+}
+
+static LY_ERR
+lydxml_attributes(struct lyd_xml_ctx *ctx, struct ly_set *attrs_data, struct lyd_node *parent)
+{
+ LY_ERR ret = LY_EVALID, rc;
+ struct lyd_attr *attr = NULL, *last = NULL;
+ const struct lyxml_ns *ns;
+ struct lys_module *mod;
+
+ for (unsigned int u = 0; u < attrs_data->count; ++u) {
+ unsigned int v;
+ struct lysc_ext_instance *ant = NULL;
+ struct attr_data_s *attr_data = (struct attr_data_s*)attrs_data->objs[u];
+
+ if (!attr_data->prefix_len) {
+ /* in XML, all attributes must be prefixed
+ * TODO exception for NETCONF filters which are supposed to map to the ietf-netconf without prefix */
+ if (ctx->options & LYD_OPT_STRICT) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Missing mandatory prefix for XML attribute \"%.*s\".",
+ attr_data->name_len, attr_data->name);
+ }
+skip_attr:
+ if (attr_data->dynamic) {
+ free(attr_data->value);
+ attr_data->dynamic = 0;
+ }
+ continue;
+ }
+
+ /* get namespace of the attribute to find its annotation definition */
+ ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
+ if (!ns) {
+ /* unknown namespace, ignore the attribute */
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", attr_data->prefix_len, attr_data->prefix);
+ goto cleanup;
+ }
+ mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
+ if (!mod) {
+ /* module is not implemented or not present in the schema */
+ if (ctx->options & LYD_OPT_STRICT) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE,
+ "Unknown (or not implemented) YANG module with namespace \"%s\" for attribute \"%.*s%s%.*s\".",
+ ns, attr_data->prefix_len, attr_data->prefix, attr_data->prefix_len ? ":" : "", attr_data->name_len, attr_data->name);
+ }
+ goto skip_attr;
+ }
+
+ LY_ARRAY_FOR(mod->compiled->exts, v) {
+ if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
+ !strncmp(mod->compiled->exts[v].argument, attr_data->name, attr_data->name_len) && !mod->compiled->exts[v].argument[attr_data->name_len]) {
+ /* we have the annotation definition */
+ ant = &mod->compiled->exts[v];
+ break;
+ }
+ }
+ if (!ant) {
+ /* attribute is not defined as a metadata annotation (RFC 7952) */
+ if (ctx->options & LYD_OPT_STRICT) {
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Annotation definition for attribute \"%s:%.*s\" not found.",
+ mod->name, attr_data->name_len, attr_data->name);
+ }
+ goto skip_attr;
+ }
attr = calloc(1, sizeof *attr);
LY_CHECK_ERR_GOTO(!attr, LOGMEM(ctx->ctx); ret = LY_EMEM, cleanup);
- attr->name = lydict_insert(ctx->ctx, name, name_len);
+ attr->parent = parent;
+ attr->annotation = ant;
+ rc = lyd_value_parse_attr(attr, attr_data->value, attr_data->value_len, attr_data->dynamic, 0, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
+ if (rc == LY_EINCOMPLETE) {
+ ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
+ } else if (rc) {
+ ret = rc;
+ free(attr);
+ goto cleanup;
+ }
+ attr_data->dynamic = 0; /* value eaten by lyd_value_parse_attr() */
+ attr->name = lydict_insert(ctx->ctx, attr_data->name, attr_data->name_len);
if (last) {
last->next = attr;
} else {
- (*attributes) = attr;
+ parent->attr = attr;
}
last = attr;
}
-
- /* resolve annotation pointers in all the attributes and process the attribute's values */
- for (last = *attributes, u = 0; u < attr_datas.count && last; u++, last = last->next) {
- attr_data = (struct attr_data_s*)attr_datas.objs[u];
- ns = lyxml_ns_get((struct lyxml_context *)ctx, attr_data->prefix, attr_data->prefix_len);
- mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
-
- LY_ARRAY_FOR(mod->compiled->exts, v) {
- if (mod->compiled->exts[v].def->plugin == lyext_plugins_internal[LYEXT_PLUGIN_INTERNAL_ANNOTATION].plugin &&
- !strcmp(mod->compiled->exts[v].argument, last->name)) {
- /* we have the annotation definition */
- last->annotation = &mod->compiled->exts[v];
- break;
- }
- }
-
- if (!last->annotation) {
- /* attribute is not defined as a metadata annotation (RFC 7952) */
-
- }
-
- ret = lyd_value_parse_attr(attr, attr_data->value, attr_data->value_len, attr_data->dynamic, 0, lydxml_resolve_prefix, ctx, LYD_XML, NULL);
- if (ret == LY_EINCOMPLETE) {
- ly_set_add(&ctx->incomplete_type_validation_attrs, attr, LY_SET_OPT_USEASLIST);
- } else if (ret) {
- goto cleanup;
- }
- attr_data->dynamic = 0; /* value eaten by lyd_value_parse_attr() */
- }
+ ret = LY_SUCCESS;
cleanup:
- for (u = 0; u < attr_datas.count; ++u) {
- if (((struct attr_data_s*)attr_datas.objs[u])->dynamic) {
- free(((struct attr_data_s*)attr_datas.objs[u])->value);
+ for (unsigned int u = 0; u < attrs_data->count; ++u) {
+ if (((struct attr_data_s*)attrs_data->objs[u])->dynamic) {
+ free(((struct attr_data_s*)attrs_data->objs[u])->value);
}
}
- ly_set_erase(&attr_datas, free);
+ ly_set_erase(attrs_data, free);
+
return ret;
}
@@ -182,7 +244,7 @@
LY_ERR ret = LY_SUCCESS;
const char *prefix, *name;
size_t prefix_len, name_len;
- struct lyd_attr *attributes = NULL;
+ struct ly_set attrs_data = {0};
const struct lyxml_ns *ns;
const struct lysc_node *snode;
struct lys_module *mod;
@@ -203,14 +265,13 @@
continue;
}
}
- attributes = NULL;
if (ctx->status == LYXML_ATTRIBUTE) {
- LY_CHECK_GOTO(lydxml_attributes(ctx, data, &attributes), error);
+ LY_CHECK_GOTO(lydxml_attributes_parse(ctx, data, &attrs_data), error);
}
ns = lyxml_ns_get((struct lyxml_context *)ctx, prefix, prefix_len);
if (!ns) {
- LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%*.s\".", prefix_len, prefix);
+ LOGVAL(ctx->ctx, LY_VLOG_LINE, &ctx->line, LYVE_REFERENCE, "Unknown XML prefix \"%.*s\".", prefix_len, prefix);
goto error;
}
mod = ly_ctx_get_module_implemented_ns(ctx->ctx, ns->uri);
@@ -338,8 +399,7 @@
} /* first top level node - nothing more to do */
}
prev = last;
- cur->attr = attributes;
- attributes = NULL;
+ LY_CHECK_GOTO(ret = lydxml_attributes(ctx, &attrs_data, cur), cleanup);
if (snode->nodetype & LYD_NODE_TERM) {
int dynamic = 0;
@@ -442,7 +502,12 @@
/* TODO add missing siblings default elements */
cleanup:
- lyd_free_attr(ctx->ctx, attributes, 1);
+ for (unsigned int u = 0; u < attrs_data.count; ++u) {
+ if (((struct attr_data_s*)attrs_data.objs[u])->dynamic) {
+ free(((struct attr_data_s*)attrs_data.objs[u])->value);
+ }
+ }
+ ly_set_erase(&attrs_data, free);
return ret;
error:
diff --git a/src/plugins_exts_internal.h b/src/plugins_exts_internal.h
index 9b25a27..18fb33a 100644
--- a/src/plugins_exts_internal.h
+++ b/src/plugins_exts_internal.h
@@ -23,7 +23,7 @@
/**
* @brief List of internally implemented extension plugins.
*/
-extern struct lyext_plugins_list *lyext_plugins_internal;
+extern struct lyext_plugins_list lyext_plugins_internal[];
/**
* @brief Index of Metadata's annotation extension plugin in lyext_plugins_internal
diff --git a/src/printer_xml.c b/src/printer_xml.c
index ecc6e75..4ce56b8 100644
--- a/src/printer_xml.c
+++ b/src/printer_xml.c
@@ -50,7 +50,6 @@
struct lys_module *module;
} *mlist = NULL, *mlist_new;
-#if 0
static LY_ERR
modlist_add(struct mlist **mlist, const struct lys_module *mod)
{
@@ -72,7 +71,6 @@
return LY_SUCCESS;
}
-#endif
/**
* TODO
@@ -83,11 +81,10 @@
struct lyd_node *next, *cur, *child;
struct lyd_attr *attr;
-#if 0
struct mlist *mlist = NULL, *miter;
-
+#if 0
const struct lys_module *wdmod = NULL;
-
+#endif
/* add node attribute modules */
for (attr = node->attr; attr; attr = attr->next) {
if (!strcmp(node->schema->name, "filter") &&
@@ -95,14 +92,10 @@
!strcmp(node->schema->module->name, "notifications"))) {
/* exception for NETCONF's filter attributes */
continue;
- } else {
- r = modlist_add(&mlist, lys_main_module(attr->annotation->module));
- }
- if (r) {
+ } else if (modlist_add(&mlist, attr->annotation->module)) {
goto print;
}
}
-#endif
/* add node children nodes and attribute modules */
switch (node->schema->nodetype) {
@@ -150,7 +143,7 @@
default:
break;
}
-#if 0
+
print:
/* print used namespaces */
while (mlist) {
@@ -160,7 +153,20 @@
ly_print(ctx->out, " xmlns:%s=\"%s\"", miter->module->prefix, miter->module->ns);
free(miter);
}
-#endif
+}
+
+/**
+ * @brief XML mapping of YANG modules to prefixes in values.
+ *
+ * Implementation of ly_clb_get_prefix
+ */
+static const char *
+xml_print_get_prefix(const struct lys_module *mod, void *private)
+{
+ struct ly_set *ns_list = (struct ly_set*)private;
+
+ ly_set_add(ns_list, (void*)mod, 0);
+ return mod->prefix;
}
/**
@@ -169,11 +175,8 @@
static LY_ERR
xml_print_attrs(struct xmlpr_ctx *ctx, const struct lyd_node *node)
{
- (void) ctx;
- (void) node;
-
-#if 0
struct lyd_attr *attr;
+#if 0
const char **prefs, **nss;
const char *xml_expr = NULL, *mod_name;
uint32_t ns_count, i;
@@ -181,9 +184,12 @@
const struct lys_module *wdmod = NULL;
char *p;
size_t len;
+#endif
+ struct ly_set ns_list = {0};
+ int dynamic;
+ unsigned int u;
- LY_PRINT_SET;
-
+#if 0
/* with-defaults */
if (node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
if ((node->dflt && (options & (LYP_WD_ALL_TAG | LYP_WD_IMPL_TAG))) ||
@@ -202,8 +208,18 @@
&& (!strcmp(node->schema->module->name, "ietf-netconf") || !strcmp(node->schema->module->name, "notifications"))) {
rpc_filter = 1;
}
-
+#endif
for (attr = node->attr; attr; attr = attr->next) {
+ const char *value = attr->value.realtype->plugin->print(&attr->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
+
+ /* print namespaces connected with the values's prefixes */
+ for (u = 0; u < ns_list.count; ++u) {
+ const struct lys_module *mod = (const struct lys_module*)ns_list.objs[u];
+ ly_print(ctx->out, " xmlns:%s=\"%s\"", mod->prefix, mod->ns);
+ }
+ ly_set_erase(&ns_list, NULL);
+
+#if 0
if (rpc_filter) {
/* exception for NETCONF's filter's attributes */
if (!strcmp(attr->name, "select")) {
@@ -222,81 +238,20 @@
}
ly_print(out, " %s=\"", attr->name);
} else {
- ly_print(out, " %s:%s=\"", attr->annotation->module->prefix, attr->name);
+#endif
+ ly_print(ctx->out, " %s:%s=\"", attr->annotation->module->prefix, attr->name);
+#if 0
}
+#endif
- switch (attr->value_type) {
- case LY_TYPE_BINARY:
- case LY_TYPE_STRING:
- case LY_TYPE_BITS:
- case LY_TYPE_ENUM:
- case LY_TYPE_BOOL:
- case LY_TYPE_DEC64:
- case LY_TYPE_INT8:
- case LY_TYPE_INT16:
- case LY_TYPE_INT32:
- case LY_TYPE_INT64:
- case LY_TYPE_UINT8:
- case LY_TYPE_UINT16:
- case LY_TYPE_UINT32:
- case LY_TYPE_UINT64:
- if (attr->value_str) {
- /* xml_expr can contain transformed xpath */
- lyxml_dump_text(out, xml_expr ? xml_expr : attr->value_str, LYXML_DATA_ATTR);
- }
- break;
-
- case LY_TYPE_IDENT:
- if (!attr->value_str) {
- break;
- }
- p = strchr(attr->value_str, ':');
- assert(p);
- len = p - attr->value_str;
- mod_name = attr->annotation->module->name;
- if (!strncmp(attr->value_str, mod_name, len) && !mod_name[len]) {
- lyxml_dump_text(out, ++p, LYXML_DATA_ATTR);
- } else {
- /* avoid code duplication - use instance-identifier printer which gets necessary namespaces to print */
- goto printinst;
- }
- break;
- case LY_TYPE_INST:
-printinst:
- xml_expr = transform_json2xml(node->schema->module, ((struct lyd_node_leaf_list *)node)->value_str, 1,
- &prefs, &nss, &ns_count);
- if (!xml_expr) {
- /* error */
- return EXIT_FAILURE;
- }
-
- for (i = 0; i < ns_count; ++i) {
- ly_print(out, " xmlns:%s=\"%s\"", prefs[i], nss[i]);
- }
- free(prefs);
- free(nss);
-
- lyxml_dump_text(out, xml_expr, LYXML_DATA_ATTR);
- lydict_remove(node->schema->module->ctx, xml_expr);
- break;
-
- /* LY_TYPE_LEAFREF not allowed */
- case LY_TYPE_EMPTY:
- break;
-
- default:
- /* error */
- LOGINT(node->schema->module->ctx);
- return EXIT_FAILURE;
+ if (value && value[0]) {
+ lyxml_dump_text(ctx->out, value, 1);
}
-
- ly_print(out, "\"");
-
- if (xml_expr) {
- lydict_remove(node->schema->module->ctx, xml_expr);
+ ly_print(ctx->out, "\"");
+ if (dynamic) {
+ free((void*)value);
}
}
-#endif
return LY_SUCCESS;
}
@@ -333,20 +288,6 @@
static LY_ERR xml_print_node(struct xmlpr_ctx *ctx, const struct lyd_node *node);
/**
- * @brief XML mapping of YANG modules to prefixes in values.
- *
- * Implementation of ly_clb_get_prefix
- */
-static const char *
-xml_print_get_prefix(const struct lys_module *mod, void *private)
-{
- struct ly_set *ns_list = (struct ly_set*)private;
-
- ly_set_add(ns_list, (void*)mod, 0);
- return mod->prefix;
-}
-
-/**
* @brief Print XML element representing lyd_node_term.
*
* @param[in] ctx XML printer context.
@@ -356,11 +297,13 @@
static LY_ERR
xml_print_term(struct xmlpr_ctx *ctx, const struct lyd_node_term *node)
{
- LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
struct ly_set ns_list = {0};
unsigned int u;
int dynamic;
- const char *value = node->value.realtype->plugin->print(&node->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
+ const char *value;
+
+ LY_CHECK_RET(xml_print_node_open(ctx, (struct lyd_node *)node));
+ value = node->value.realtype->plugin->print(&node->value, LYD_XML, xml_print_get_prefix, &ns_list, &dynamic);
/* print namespaces connected with the values's prefixes */
for (u = 0; u < ns_list.count; ++u) {
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index b8c5329..9ff54c4 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -128,7 +128,7 @@
iter = iter->next;
FREE_STRING(ctx, attr->name);
- /* TODO type->plugin->free(ctx, type, &attr->value); */
+ attr->value.realtype->plugin->free(ctx, &attr->value);
free(attr);
}
}
diff --git a/src/tree_schema.h b/src/tree_schema.h
index 8346592..abe4908 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1115,6 +1115,7 @@
*/
struct lysc_ext_instance {
struct lysc_ext *def; /**< pointer to the extension definition */
+ struct lys_module *module; /**< module where the extension instantiated is defined */
void *parent; /**< pointer to the parent element holding the extension instance(s), use
::lysc_ext_instance#parent_type to access the schema element */
const char *argument; /**< optional value of the extension's argument */
diff --git a/src/tree_schema_compile.c b/src/tree_schema_compile.c
index 25b16e4..25e9ffa 100644
--- a/src/tree_schema_compile.c
+++ b/src/tree_schema_compile.c
@@ -435,6 +435,7 @@
DUP_STRING(ctx->ctx, ext_p->argument, ext->argument);
ext->insubstmt = ext_p->insubstmt;
ext->insubstmt_index = ext_p->insubstmt_index;
+ ext->module = ctx->mod_def;
ext->parent = parent;
ext->parent_type = parent_type;