plugins ext FEATURE initial schema-mount support
Only for XML data for now. Includes lots of other
changes needed to support this extension.
diff --git a/src/parser_xml.c b/src/parser_xml.c
index fcfc8f9..e874231 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -48,12 +48,12 @@
* @brief Parse and create XML metadata.
*
* @param[in] lydctx XML data parser context.
- * @param[in] parent_exts Extension instances of the parent node.
+ * @param[in] sparent Schema node of the parent.
* @param[out] meta List of created metadata instances.
* @return LY_ERR value.
*/
static LY_ERR
-lydxml_metadata(struct lyd_xml_ctx *lydctx, struct lysc_ext_instance *parent_exts, struct lyd_meta **meta)
+lydxml_metadata(struct lyd_xml_ctx *lydctx, const struct lysc_node *sparent, struct lyd_meta **meta)
{
LY_ERR ret = LY_SUCCESS;
const struct lyxml_ns *ns;
@@ -67,9 +67,9 @@
*meta = NULL;
/* check for NETCONF filter unqualified attributes */
- LY_ARRAY_FOR(parent_exts, u) {
- if (!strcmp(parent_exts[u].def->name, "get-filter-element-attributes") &&
- !strcmp(parent_exts[u].def->module->name, "ietf-netconf")) {
+ LY_ARRAY_FOR(sparent->exts, u) {
+ if (!strcmp(sparent->exts[u].def->name, "get-filter-element-attributes") &&
+ !strcmp(sparent->exts[u].def->module->name, "ietf-netconf")) {
filter_attrs = 1;
break;
}
@@ -141,7 +141,7 @@
/* create metadata */
ret = lyd_parser_create_meta((struct lyd_ctx *)lydctx, NULL, meta, mod, name, name_len, xmlctx->value,
- xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
+ xmlctx->value_len, &xmlctx->dynamic, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA, sparent);
LY_CHECK_GOTO(ret, cleanup);
/* next attribute */
@@ -407,6 +407,77 @@
}
/**
+ * @brief Try to parse data with a parent based on an extension instance.
+ *
+ * @param[in] lydctx XML data parser context.
+ * @param[in,out] parent Parent node where the children are inserted.
+ * @return LY_SUCCESS on success;
+ * @return LY_ENOT if no extension instance parsed the data;
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lydxml_nested_ext(struct lyd_xml_ctx *lydctx, struct lyd_node *parent)
+{
+ LY_ERR r;
+ struct ly_in in_bck, in_start, in_ext;
+ LY_ARRAY_COUNT_TYPE u;
+ struct lysc_ext_instance *nested_exts = NULL;
+ lyplg_ext_data_parse_clb ext_parse_cb;
+ struct lyd_ctx_ext_val *ext_val;
+
+ /* backup current input */
+ in_bck = *lydctx->xmlctx->in;
+
+ /* go back in the input for extension parsing */
+ in_start = *lydctx->xmlctx->in;
+ if (lydctx->xmlctx->status != LYXML_ELEM_CONTENT) {
+ assert((lydctx->xmlctx->status == LYXML_ELEMENT) || (lydctx->xmlctx->status == LYXML_ATTRIBUTE));
+ in_start.current = lydctx->xmlctx->prefix ? lydctx->xmlctx->prefix : lydctx->xmlctx->name;
+ }
+ do {
+ --in_start.current;
+ } while (in_start.current[0] != '<');
+
+ /* check if there are any nested extension instances */
+ if (parent && parent->schema) {
+ nested_exts = parent->schema->exts;
+ }
+ LY_ARRAY_FOR(nested_exts, u) {
+ /* prepare the input and try to parse this extension data */
+ in_ext = in_start;
+ ext_parse_cb = nested_exts[u].def->plugin->parse;
+ r = ext_parse_cb(&in_ext, LYD_XML, &nested_exts[u], parent, lydctx->parse_opts | LYD_PARSE_ONLY);
+ if (!r) {
+ /* data successfully parsed, remember for validation */
+ if (!(lydctx->parse_opts & LYD_PARSE_ONLY)) {
+ ext_val = malloc(sizeof *ext_val);
+ LY_CHECK_ERR_RET(!ext_val, LOGMEM(lydctx->xmlctx->ctx), LY_EMEM);
+ ext_val->ext = &nested_exts[u];
+ ext_val->sibling = lyd_child(parent);
+ LY_CHECK_RET(ly_set_add(&lydctx->ext_val, ext_val, 1, NULL));
+ }
+
+ /* adjust the xmlctx accordingly */
+ *lydctx->xmlctx->in = in_ext;
+ lydctx->xmlctx->status = LYXML_ELEM_CONTENT;
+ lydctx->xmlctx->dynamic = 0;
+ ly_set_rm_index(&lydctx->xmlctx->elements, lydctx->xmlctx->elements.count - 1, free);
+ lyxml_ns_rm(lydctx->xmlctx);
+ LY_CHECK_RET(lyxml_ctx_next(lydctx->xmlctx));
+ return LY_SUCCESS;
+ } else if (r != LY_ENOT) {
+ /* fatal error */
+ return r;
+ }
+ /* data was not from this module, continue */
+ }
+
+ /* no extensions or none matched, restore input */
+ *lydctx->xmlctx->in = in_bck;
+ return LY_ENOT;
+}
+
+/**
* @brief Parse XML subtree.
*
* @param[in] lydctx XML YANG data parser context.
@@ -420,9 +491,6 @@
lydxml_subtree_r(struct lyd_xml_ctx *lydctx, struct lyd_node *parent, struct lyd_node **first_p, struct ly_set *parsed)
{
LY_ERR ret = LY_SUCCESS, r;
- LY_ARRAY_COUNT_TYPE u;
-
- lyplg_ext_data_parse_clb ext_parse;
const char *prefix, *name, *val;
size_t prefix_len, name_len;
struct lyxml_ctx *xmlctx;
@@ -435,9 +503,9 @@
uint32_t prev_parse_opts, prev_int_opts;
struct lyd_node *node = NULL, *anchor;
void *val_prefix_data = NULL;
- struct lysc_ext_instance *exts = NULL;
LY_VALUE_FORMAT format;
uint32_t getnext_opts;
+ ly_bool parse_subtree;
assert(parent || first_p);
@@ -445,6 +513,10 @@
ctx = xmlctx->ctx;
getnext_opts = lydctx->int_opts & LYD_INTOPT_REPLY ? LYS_GETNEXT_OUTPUT : 0;
+ parse_subtree = lydctx->parse_opts & LYD_PARSE_SUBTREE ? 1 : 0;
+ /* all descendants should be parsed */
+ lydctx->parse_opts &= ~LYD_PARSE_SUBTREE;
+
assert(xmlctx->status == LYXML_ELEMENT);
/* remember element prefix and name */
@@ -462,6 +534,18 @@
}
mod = ly_ctx_get_module_implemented_ns(ctx, ns->uri);
if (!mod) {
+ /* check for extension data */
+ r = lydxml_nested_ext(lydctx, parent);
+ if (!r) {
+ /* successfully parsed */
+ return r;
+ } else if (r != LY_ENOT) {
+ /* error */
+ ret = r;
+ goto error;
+ }
+
+ /* unknown module */
if (lydctx->parse_opts & LYD_PARSE_STRICT) {
LOGVAL(ctx, LYVE_REFERENCE, "No module with namespace \"%s\" in the context.", ns->uri);
ret = LY_EVALID;
@@ -486,22 +570,18 @@
snode = lys_find_child(parent ? parent->schema : NULL, mod, name, name_len, 0, getnext_opts);
}
if (!snode) {
- /* Check if data of an extension */
- if (parent && parent->schema) {
- exts = parent->schema->exts;
+ /* check for extension data */
+ r = lydxml_nested_ext(lydctx, parent);
+ if (!r) {
+ /* successfully parsed */
+ return r;
+ } else if (r != LY_ENOT) {
+ /* error */
+ ret = r;
+ goto error;
}
- LY_ARRAY_FOR(exts, u) {
- ext_parse = exts[u].def->plugin->parse;
- r = ext_parse(xmlctx->in, LYD_XML, &exts[u], parent, lydctx->parse_opts,
- lydctx->val_opts);
- if (r == LY_SUCCESS) {
- /* Data was from this module*/
- return LY_SUCCESS;
- } else if (r != LY_ENOT) {
- /* Error while parsing */
- }
- /* Data was not from this module */
- }
+
+ /* unknown data node */
if (lydctx->parse_opts & LYD_PARSE_STRICT) {
if (parent) {
LOGVAL(ctx, LYVE_REFERENCE, "Node \"%.*s\" not found as a child of \"%s\" node.",
@@ -537,7 +617,7 @@
/* create metadata/attributes */
if (xmlctx->status == LYXML_ATTRIBUTE) {
if (snode) {
- ret = lydxml_metadata(lydctx, snode->exts, &meta);
+ ret = lydxml_metadata(lydctx, snode, &meta);
LY_CHECK_GOTO(ret, error);
} else {
assert(lydctx->parse_opts & LYD_PARSE_OPAQ);
@@ -648,8 +728,8 @@
LY_CHECK_GOTO(ret, error);
/* add any missing default children */
- ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_exts,
- &lydctx->node_types, (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
+ ret = lyd_new_implicit_r(node, lyd_node_child_p(node), NULL, NULL, &lydctx->node_when, &lydctx->node_types,
+ (lydctx->val_opts & LYD_VALIDATE_NO_STATE) ? LYD_IMPLICIT_NO_STATE : 0, NULL);
LY_CHECK_GOTO(ret, error);
}
@@ -711,12 +791,14 @@
/* add/correct flags */
if (snode) {
- lyd_parse_set_data_flags(node, &lydctx->node_when, &lydctx->node_exts, &meta, lydctx->parse_opts);
+ lyd_parse_set_data_flags(node, &lydctx->node_when, &meta, lydctx->parse_opts);
}
/* parser next */
assert(xmlctx->status == LYXML_ELEM_CLOSE);
- LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+ if (!parse_subtree) {
+ LY_CHECK_GOTO(ret = lyxml_ctx_next(xmlctx), error);
+ }
/* add metadata/attributes */
if (snode) {
@@ -1398,12 +1480,13 @@
LY_ERR
lyd_parse_xml(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, struct lyd_node *parent,
struct lyd_node **first_p, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts, enum lyd_type data_type,
- struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
+ struct lyd_node **envp, struct ly_set *parsed, ly_bool *subtree_sibling, struct lyd_ctx **lydctx_p)
{
LY_ERR rc = LY_SUCCESS;
struct lyd_xml_ctx *lydctx;
uint32_t i, int_opts = 0, close_elem = 0;
ly_bool parsed_data_nodes = 0;
+ enum LYXML_PARSER_STATUS status;
assert(ctx && in && lydctx_p);
assert(!(parse_opts & ~LYD_PARSE_OPTS_MASK));
@@ -1420,7 +1503,9 @@
switch (data_type) {
case LYD_TYPE_DATA_YANG:
- int_opts = LYD_INTOPT_WITH_SIBLINGS;
+ if (!(parse_opts & LYD_PARSE_SUBTREE)) {
+ int_opts = LYD_INTOPT_WITH_SIBLINGS;
+ }
break;
case LYD_TYPE_RPC_YANG:
int_opts = LYD_INTOPT_RPC | LYD_INTOPT_ACTION | LYD_INTOPT_NO_SIBLINGS;
@@ -1489,10 +1574,20 @@
lydctx->op_node = NULL;
}
+ if (parse_opts & LYD_PARSE_SUBTREE) {
+ /* check for a sibling element */
+ assert(subtree_sibling);
+ if (!lyxml_ctx_peek(lydctx->xmlctx, &status) && (status == LYXML_ELEMENT)) {
+ *subtree_sibling = 1;
+ } else {
+ *subtree_sibling = 0;
+ }
+ }
+
cleanup:
/* there should be no unres stored if validation should be skipped */
assert(!(parse_opts & LYD_PARSE_ONLY) || (!lydctx->node_types.count && !lydctx->meta_types.count &&
- !lydctx->node_when.count && !lydctx->node_exts.count));
+ !lydctx->node_when.count));
if (rc) {
lyd_xml_ctx_free((struct lyd_ctx *)lydctx);