parser xml FEATURE try to guess sensible hints for opaque nodes
... instead of guessing them when printing.
Refs #1827
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 69d1b45..1f395b8 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -411,6 +411,79 @@
}
/**
+ * @brief Get sensible data hints for an opaque node.
+ *
+ * @param[in] name Node name.
+ * @param[in] name_len Length of @p name.
+ * @param[in] value Node value.
+ * @param[in] value_len Length of @p value.
+ * @param[in] first Node first sibling.
+ * @param[in] ns Node module namespace.
+ * @param[out] hints Data hints to use.
+ * @param[out] anchor Anchor to insert after in case of a list.
+ */
+static void
+lydxml_get_hints_opaq(const char *name, size_t name_len, const char *value, size_t value_len, struct lyd_node *first,
+ const char *ns, uint32_t *hints, struct lyd_node **anchor)
+{
+ struct lyd_node_opaq *opaq;
+ char *ptr;
+ long num;
+
+ *hints = 0;
+ *anchor = NULL;
+
+ if (!value_len) {
+ /* no value */
+ *hints |= LYD_VALHINT_EMPTY;
+ } else if (!strncmp(value, "true", value_len) || !strncmp(value, "false", value_len)) {
+ /* boolean value */
+ *hints |= LYD_VALHINT_BOOLEAN;
+ } else {
+ num = strtol(value, &ptr, 10);
+ if ((unsigned)(ptr - value) == value_len) {
+ /* number value */
+ *hints |= LYD_VALHINT_DECNUM;
+ if ((num < INT32_MIN) || (num > UINT32_MAX)) {
+ /* large number */
+ *hints |= LYD_VALHINT_NUM64;
+ }
+ } else {
+ /* string value */
+ *hints |= LYD_VALHINT_STRING;
+ }
+ }
+
+ if (!first) {
+ return;
+ }
+
+ /* search backwards to find the last instance */
+ do {
+ first = first->prev;
+ if (first->schema) {
+ continue;
+ }
+
+ opaq = (struct lyd_node_opaq *)first;
+ assert(opaq->format == LY_VALUE_XML);
+ if (!ly_strncmp(opaq->name.name, name, name_len) && !strcmp(opaq->name.module_ns, ns)) {
+ if (opaq->value && opaq->value[0]) {
+ /* leaf-list nodes */
+ opaq->hints |= LYD_NODEHINT_LEAFLIST;
+ *hints |= LYD_NODEHINT_LEAFLIST;
+ } else {
+ /* list nodes */
+ opaq->hints |= LYD_NODEHINT_LIST;
+ *hints |= LYD_NODEHINT_LIST;
+ }
+ *anchor = first;
+ break;
+ }
+ } while (first->prev->next);
+}
+
+/**
* @brief Get schema node for the current element.
*
* @param[in] lydctx XML data parser context.
@@ -537,8 +610,8 @@
struct lyd_attr *attr = NULL;
const struct lysc_node *snode;
struct lysc_ext_instance *ext;
- uint32_t prev_parse_opts, orig_parse_opts, prev_int_opts;
- struct lyd_node *node = NULL, *anchor;
+ uint32_t prev_parse_opts, orig_parse_opts, prev_int_opts, hints;
+ struct lyd_node *node = NULL, *anchor, *insert_anchor = NULL;
void *val_prefix_data = NULL;
LY_VALUE_FORMAT format;
ly_bool parse_subtree;
@@ -595,7 +668,7 @@
if (xmlctx->ws_only) {
/* ignore WS-only value */
if (xmlctx->dynamic) {
- free((char *) xmlctx->value);
+ free((char *)xmlctx->value);
}
xmlctx->dynamic = 0;
xmlctx->value = "";
@@ -612,9 +685,13 @@
ns = lyxml_ns_get(&xmlctx->ns, prefix, prefix_len);
assert(ns);
+ /* get best-effort node hints */
+ lydxml_get_hints_opaq(name, name_len, xmlctx->value, xmlctx->value_len, parent ? lyd_child(parent) : *first_p,
+ ns->uri, &hints, &insert_anchor);
+
/* create node */
ret = lyd_create_opaq(ctx, name, name_len, prefix, prefix_len, ns->uri, strlen(ns->uri), xmlctx->value,
- xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, LYD_HINT_DATA, &node);
+ xmlctx->value_len, &xmlctx->dynamic, format, val_prefix_data, hints, &node);
LY_CHECK_GOTO(ret, error);
/* parser next */
@@ -781,7 +858,9 @@
}
/* insert, keep first pointer correct */
- if (ext) {
+ if (insert_anchor) {
+ lyd_insert_after(insert_anchor, node);
+ } else if (ext) {
LY_CHECK_GOTO(ret = lyd_insert_ext(parent, node), error);
} else {
lyd_insert_node(parent, first_p, node, lydctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
diff --git a/src/printer_json.c b/src/printer_json.c
index 4c53f0f..a301075 100644
--- a/src/printer_json.c
+++ b/src/printer_json.c
@@ -846,34 +846,6 @@
json_print_opaq(struct jsonpr_ctx *pctx, const struct lyd_node_opaq *node)
{
ly_bool first = 1, last = 1;
- char *ptr;
- long num;
-
- if (node->hints == LYD_HINT_DATA) {
- /* basically, we do not know anything about the node so just do our best */
- LY_CHECK_RET(json_print_member2(pctx, pctx->parent, node->format, &node->name, 0));
- if (node->child) {
- LY_CHECK_RET(json_print_inner(pctx, &node->node));
- LEVEL_PRINTED;
- } else {
- if (node->value) {
- num = strtol(node->value, &ptr, 10);
- if (!ptr[0] && (ptr != node->value) &&
- (((num < 0) && (num >= INT32_MIN)) || ((num >= 0) && (num <= UINT32_MAX)))) {
- ly_print_(pctx->out, "%s", node->value);
- } else {
- ly_print_(pctx->out, "\"%s\"", node->value);
- }
- } else {
- ly_print_(pctx->out, "[null]");
- }
- LEVEL_PRINTED;
-
- /* attributes */
- json_print_attributes(pctx, (const struct lyd_node *)node, 0);
- }
- return LY_SUCCESS;
- }
if (node->hints & (LYD_NODEHINT_LIST | LYD_NODEHINT_LEAFLIST)) {
if (node->prev->next && matching_node(node->prev, &node->node)) {
@@ -902,10 +874,10 @@
} else {
if (node->hints & LYD_VALHINT_EMPTY) {
ly_print_(pctx->out, "[null]");
- } else if (node->hints & (LYD_VALHINT_BOOLEAN | LYD_VALHINT_DECNUM)) {
+ } else if ((node->hints & (LYD_VALHINT_BOOLEAN | LYD_VALHINT_DECNUM)) && !(node->hints & LYD_VALHINT_NUM64)) {
ly_print_(pctx->out, "%s", node->value);
} else {
- /* string */
+ /* string or a large number */
ly_print_(pctx->out, "\"%s\"", node->value);
}
LEVEL_PRINTED;