data tree FEATURE support for anydata
Defined and supported in XML parser.
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 75e3c55..a6193c0 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -275,12 +275,47 @@
goto cleanup;
}
}
+ /* process children */
if (ctx->status == LYXML_ELEMENT && parents_count != ctx->elements.count) {
ret = lydxml_nodes(ctx, (struct lyd_node_inner*)cur, data, lyd_node_children_p(cur));
LY_CHECK_GOTO(ret, cleanup);
}
+ } else if (snode->nodetype & LYD_NODE_ANY) {
+ unsigned int cur_element_index = ctx->elements.count;
+ const char *start = *data, *stop;
+ const char *p, *n;
+ size_t p_len, n_len;
+
+ /* skip children data and store them as a string */
+ while (cur_element_index <= ctx->elements.count) {
+ switch (ctx->status) {
+ case LYXML_ELEMENT:
+ ret = lyxml_get_element((struct lyxml_context *)ctx, data, &p, &p_len, &n, &n_len);
+ break;
+ case LYXML_ATTRIBUTE:
+ lyxml_get_attribute((struct lyxml_context*)ctx, data, &p, &p_len, &n, &n_len);
+ break;
+ case LYXML_ELEM_CONTENT:
+ case LYXML_ATTR_CONTENT:
+ ret = lyxml_get_string((struct lyxml_context *)ctx, data, NULL, NULL, NULL, NULL, NULL);
+ if (ret == LY_EINVAL) {
+ /* not an error, just incorrect XML parser status */
+ ret = LY_SUCCESS;
+ }
+ break;
+ case LYXML_END:
+ /* unexpected end of data */
+ LOGINT(ctx->ctx);
+ goto cleanup;
+ }
+ LY_CHECK_GOTO(ret, cleanup);
+ }
+ /* data now points after the anydata's closing element tag, we need just end of its content */
+ for (stop = *data - 1; *stop != '<'; --stop);
+
+ ((struct lyd_node_any*)cur)->value_type = LYD_ANYDATA_XML;
+ ((struct lyd_node_any*)cur)->value.xml = lydict_insert(ctx->ctx, start, stop - start);
}
- /* TODO anyxml/anydata */
}
cleanup:
diff --git a/src/tree_data.h b/src/tree_data.h
index 1cf0e8f..12e2859 100644
--- a/src/tree_data.h
+++ b/src/tree_data.h
@@ -121,44 +121,15 @@
* @brief List of possible value types stored in ::lyd_node_anydata.
*/
typedef enum {
- LYD_ANYDATA_CONSTSTRING = 0x00, /**< value is constant string (const char *) which is internally duplicated for
- storing in the anydata structure; XML sensitive characters (such as & or \>)
- are automatically escaped when the anydata is printed in XML format. */
- LYD_ANYDATA_STRING = 0x01, /**< value is dynamically allocated string (char*), so the data are used directly
- without duplication and caller is supposed to not manipulate with the data
- after a successful call (including calling free() on the provided data); XML
- sensitive characters (such as & or \>) are automatically escaped when the
- anydata is printed in XML format */
- LYD_ANYDATA_JSON = 0x02, /**< value is string containing the data modeled by YANG and encoded as I-JSON. The
- string is handled as constant string. In case of using the value as input
- parameter, the #LYD_ANYDATA_JSOND can be used for dynamically allocated
- string. */
- LYD_ANYDATA_JSOND = 0x03, /**< In case of using value as input parameter, this enumeration is supposed to be
- used for dynamically allocated strings (it is actually combination of
- #LYD_ANYDATA_JSON and #LYD_ANYDATA_STRING (and it can be also specified as
- ORed value of the mentioned values. */
- LYD_ANYDATA_SXML = 0x04, /**< value is string containing the serialized XML data. The string is handled as
- constant string. In case of using the value as input parameter, the
- #LYD_ANYDATA_SXMLD can be used for dynamically allocated string. */
- LYD_ANYDATA_SXMLD = 0x05, /**< In case of using serialized XML value as input parameter, this enumeration is
- supposed to be used for dynamically allocated strings (it is actually
- combination of #LYD_ANYDATA_SXML and #LYD_ANYDATA_STRING (and it can be also
- specified as ORed value of the mentioned values). */
- LYD_ANYDATA_XML = 0x08, /**< value is struct lyxml_elem*, the structure is directly connected into the
- anydata node without duplication, caller is supposed to not manipulate with the
- data after a successful call (including calling lyxml_free() on the provided
- data) */
- LYD_ANYDATA_DATATREE = 0x10, /**< value is struct lyd_node* (first sibling), the structure is directly connected
- into the anydata node without duplication, caller is supposed to not manipulate
- with the data after a successful call (including calling lyd_free() on the
- provided data) */
- LYD_ANYDATA_LYB = 0x20, /**< value is a memory with serialized data tree in LYB format. The data are handled
- as a constant string. In case of using the value as input parameter,
- the #LYD_ANYDATA_LYBD can be used for dynamically allocated string. */
- LYD_ANYDATA_LYBD = 0x21, /**< In case of using LYB value as input parameter, this enumeration is
- supposed to be used for dynamically allocated strings (it is actually
- combination of #LYD_ANYDATA_LYB and #LYD_ANYDATA_STRING (and it can be also
- specified as ORed value of the mentioned values). */
+ LYD_ANYDATA_DATATREE = 0x01, /**< Value is a pointer to lyd_node structure (first sibling). When provided as input parameter, the pointer
+ is directly connected into the anydata node without duplication, caller is supposed to not manipulate
+ with the data after a successful call (including calling lyd_free() on the provided data) */
+ LYD_ANYDATA_STRING = 0x02, /**< Value is a generic string without any knowledge about its format (e.g. anyxml value in JSON encoded
+ as string). XML sensitive characters (such as & or \>) are automatically escaped when the anydata
+ is printed in XML format. */
+ LYD_ANYDATA_XML = 0x04, /**< Value is a string containing the serialized XML data. */
+ LYD_ANYDATA_JSON = 0x08, /**< Value is a string containing the data modeled by YANG and encoded as I-JSON. */
+ LYD_ANYDATA_LYB = 0x10, /**< Value is a memory chunk with the serialized data tree in LYB format. */
} LYD_ANYDATA_VALUETYPE;
/** @} */
@@ -332,7 +303,14 @@
void *priv; /**< private user data, not used by libyang */
#endif
- /* TODO - anydata representation */
+ union {
+ struct lyd_node *tree; /**< data tree */
+ const char *str; /**< Generic string data */
+ const char *xml; /**< Serialized XML data */
+ const char *json; /**< I-JSON encoded string */
+ char *mem; /**< LYD_ANYDATA_LYB memory chunk */
+ } value; /**< pointer to the stored value representation of the anydata/anyxml node */
+ LYD_ANYDATA_VALUETYPE value_type;/**< type of the data stored as lyd_node_any::value */
};
/**
diff --git a/src/tree_data_free.c b/src/tree_data_free.c
index 80653d8..42797b2 100644
--- a/src/tree_data_free.c
+++ b/src/tree_data_free.c
@@ -158,32 +158,19 @@
lyd_free_subtree(ctx, iter, 0);
}
} else if (node->schema->nodetype & LYD_NODE_ANY) {
- /* TODO anydata */
-#if 0
- switch (((struct lyd_node_anydata *)node)->value_type) {
- case LYD_ANYDATA_CONSTSTRING:
- case LYD_ANYDATA_SXML:
- case LYD_ANYDATA_JSON:
- FREE_STRING(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.str);
- break;
+ switch (((struct lyd_node_any*)node)->value_type) {
case LYD_ANYDATA_DATATREE:
- lyd_free_withsiblings(((struct lyd_node_anydata *)node)->value.tree);
- break;
- case LYD_ANYDATA_XML:
- lyxml_free_withsiblings(node->schema->module->ctx, ((struct lyd_node_anydata *)node)->value.xml);
- break;
- case LYD_ANYDATA_LYB:
- free(((struct lyd_node_anydata *)node)->value.mem);
+ lyd_free_all(((struct lyd_node_any*)node)->value.tree);
break;
case LYD_ANYDATA_STRING:
- case LYD_ANYDATA_SXMLD:
- case LYD_ANYDATA_JSOND:
- case LYD_ANYDATA_LYBD:
- /* dynamic strings are used only as input parameters */
- assert(0);
+ case LYD_ANYDATA_XML:
+ case LYD_ANYDATA_JSON:
+ FREE_STRING(node->schema->module->ctx, ((struct lyd_node_any*)node)->value.str);
+ break;
+ case LYD_ANYDATA_LYB:
+ free(((struct lyd_node_any*)node)->value.mem);
break;
}
-#endif
} else if (node->schema->nodetype & LYD_NODE_TERM) {
((struct lysc_node_leaf*)node->schema)->type->plugin->free(ctx, &((struct lyd_node_term*)node)->value);
}
diff --git a/src/xml.c b/src/xml.c
index 95b0e64..8a70445 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -562,40 +562,52 @@
/* parse */
while (in[offset]) {
if (in[offset] == '&') {
- if (!buf) {
- /* it is necessary to modify the input, so we will need a dynamically allocated buffer */
- goto getbuffer;
- }
+ if (output) {
+ if (!buf) {
+ /* it is necessary to modify the input, so we will need a dynamically allocated buffer */
+ goto getbuffer;
+ }
- if (offset) {
- /* store what we have so far */
- BUFSIZE_CHECK(ctx, buf, size, len, offset);
- memcpy(&buf[len], in, offset);
- len += offset;
- in += offset;
- offset = 0;
+ if (offset) {
+ /* store what we have so far */
+ BUFSIZE_CHECK(ctx, buf, size, len, offset);
+ memcpy(&buf[len], in, offset);
+ len += offset;
+ in += offset;
+ offset = 0;
+ }
+ /* process reference */
+ /* we will need 4 bytes at most since we support only the predefined
+ * (one-char) entities and character references */
+ BUFSIZE_CHECK(ctx, buf, size, len, 4);
}
- /* process reference */
- /* we will need 4 bytes at most since we support only the predefined
- * (one-char) entities and character references */
- BUFSIZE_CHECK(ctx, buf, size, len, 4);
++offset;
if (in[offset] != '#') {
/* entity reference - only predefined references are supported */
if (!strncmp(&in[offset], "lt;", 3)) {
- buf[len++] = '<';
+ if (output) {
+ buf[len++] = '<';
+ }
in += 4; /* < */
} else if (!strncmp(&in[offset], "gt;", 3)) {
- buf[len++] = '>';
+ if (output) {
+ buf[len++] = '>';
+ }
in += 4; /* > */
} else if (!strncmp(&in[offset], "amp;", 4)) {
- buf[len++] = '&';
+ if (output) {
+ buf[len++] = '&';
+ }
in += 5; /* & */
} else if (!strncmp(&in[offset], "apos;", 5)) {
- buf[len++] = '\'';
+ if (output) {
+ buf[len++] = '\'';
+ }
in += 6; /* ' */
} else if (!strncmp(&in[offset], "quot;", 5)) {
- buf[len++] = '\"';
+ if (output) {
+ buf[len++] = '\"';
+ }
in += 6; /* " */
} else {
LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX,
@@ -632,7 +644,12 @@
LY_VCODE_INSTREXP_len(&in[offset]), &in[offset], ";"),
error);
++offset;
- rc = lyxml_pututf8(&buf[len], n, &u);
+ if (output) {
+ rc = lyxml_pututf8(&buf[len], n, &u);
+ } else {
+ char utf8[4];
+ rc = lyxml_pututf8(&utf8[0], n, &u);
+ }
LY_CHECK_ERR_GOTO(rc, LOGVAL(ctx, LY_VLOG_LINE, &context->line, LYVE_SYNTAX,
"Invalid character reference \"%.*s\" (0x%08x).", 12, p, n),
error);
@@ -758,11 +775,12 @@
(*buffer_size) = size;
(*output) = buf;
(*dynamic) = 1;
- } else {
+ (*length) = len;
+ } else if (output) {
(*output) = (char*)start;
(*dynamic) = 0;
+ (*length) = len;
}
- (*length) = len;
if (context->status == LYXML_ATTRIBUTE) {
/* skip whitespaces after the value */
diff --git a/src/xml.h b/src/xml.h
index b5e40a3..2795d62 100644
--- a/src/xml.h
+++ b/src/xml.h
@@ -146,6 +146,9 @@
* reference which modify the input data. These constructs are replaced by their real value, so in case the output
* string will be again printed as an XML data, it may be necessary to correctly encode such characters.
*
+ * Optionally, the buffer, buffer_size, output, length and dynamic arguments (altogether) can be NULL.
+ * In such a case, the XML text in @p input is just checked, the @p input pointer is moved after the XML text, but nothing is stored.
+ *
* @param[in] context XML context to track lines or store errors into libyang context.
* @param[in,out] input Input string to process, updated according to the processed/read data.
* @param[in, out] buffer Storage for the output string. If the parameter points to NULL, the buffer is allocated if needed.