tree data FEATURE compare on opaque nodes
diff --git a/src/tree_data.c b/src/tree_data.c
index 8704a96..7ab2607 100644
--- a/src/tree_data.c
+++ b/src/tree_data.c
@@ -1166,6 +1166,82 @@
}
/**
+ * @brief Compare 2 nodes values including opaque node values.
+ *
+ * @param[in] node1 First node to compare.
+ * @param[in] node2 Second node to compare.
+ * @return LY_SUCCESS if equal.
+ * @return LY_ENOT if not equal.
+ * @return LY_ERR on error.
+ */
+static LY_ERR
+lyd_compare_single_value(const struct lyd_node *node1, const struct lyd_node *node2)
+{
+ const struct lyd_node_opaq *opaq1 = NULL, *opaq2 = NULL;
+ const char *val1, *val2, *col;
+ const struct lys_module *mod;
+ char *val_dyn = NULL;
+ LY_ERR rc = LY_SUCCESS;
+
+ if (!node1->schema) {
+ opaq1 = (struct lyd_node_opaq *)node1;
+ }
+ if (!node2->schema) {
+ opaq2 = (struct lyd_node_opaq *)node2;
+ }
+
+ if (opaq1 && opaq2 && (opaq1->format == LY_VALUE_XML) && (opaq2->format == LY_VALUE_XML)) {
+ /* opaque XML and opaque XML node */
+ if (lyxml_value_compare(LYD_CTX(node1), opaq1->value, opaq1->val_prefix_data, LYD_CTX(node2), opaq2->value,
+ opaq2->val_prefix_data)) {
+ return LY_ENOT;
+ }
+ return LY_SUCCESS;
+ }
+
+ /* get their values */
+ if (opaq1 && ((opaq1->format == LY_VALUE_XML) || (opaq1->format == LY_VALUE_STR_NS)) && (col = strchr(opaq1->value, ':'))) {
+ /* XML value with a prefix, try to transform it into a JSON (canonical) value */
+ mod = ly_resolve_prefix(LYD_CTX(node1), opaq1->value, col - opaq1->value, opaq1->format, opaq1->val_prefix_data);
+ if (!mod) {
+ /* unable to compare */
+ return LY_ENOT;
+ }
+
+ if (asprintf(&val_dyn, "%s%s", mod->name, col) == -1) {
+ LOGMEM(LYD_CTX(node1));
+ return LY_EMEM;
+ }
+ val1 = val_dyn;
+ } else {
+ val1 = lyd_get_value(node1);
+ }
+ if (opaq2 && ((opaq2->format == LY_VALUE_XML) || (opaq2->format == LY_VALUE_STR_NS)) && (col = strchr(opaq2->value, ':'))) {
+ mod = ly_resolve_prefix(LYD_CTX(node2), opaq2->value, col - opaq2->value, opaq2->format, opaq2->val_prefix_data);
+ if (!mod) {
+ return LY_ENOT;
+ }
+
+ assert(!val_dyn);
+ if (asprintf(&val_dyn, "%s%s", mod->name, col) == -1) {
+ LOGMEM(LYD_CTX(node2));
+ return LY_EMEM;
+ }
+ val2 = val_dyn;
+ } else {
+ val2 = lyd_get_value(node2);
+ }
+
+ /* compare values */
+ if (strcmp(val1, val2)) {
+ rc = LY_ENOT;
+ }
+
+ free(val_dyn);
+ return rc;
+}
+
+/**
* @brief Internal implementation of @ref lyd_compare_single.
* @copydoc lyd_compare_single
* @param[in] parental_schemas_checked Flag used for optimization.
@@ -1174,14 +1250,13 @@
* recursive calls, and this is accomplished by setting to 1 in the lyd_compare_single_ body.
*/
static LY_ERR
-lyd_compare_single_(const struct lyd_node *node1, const struct lyd_node *node2,
- uint32_t options, ly_bool parental_schemas_checked)
+lyd_compare_single_(const struct lyd_node *node1, const struct lyd_node *node2, uint32_t options,
+ ly_bool parental_schemas_checked)
{
const struct lyd_node *iter1, *iter2;
- struct lyd_node_term *term1, *term2;
struct lyd_node_any *any1, *any2;
- struct lyd_node_opaq *opaq1, *opaq2;
int len1, len2;
+ LY_ERR r;
if (!node1 || !node2) {
if (node1 == node2) {
@@ -1193,8 +1268,14 @@
if (LYD_CTX(node1) == LYD_CTX(node2)) {
/* same contexts */
- if (node1->schema != node2->schema) {
- return LY_ENOT;
+ if (options & LYD_COMPARE_OPAQ) {
+ if (lyd_node_schema(node1) != lyd_node_schema(node2)) {
+ return LY_ENOT;
+ }
+ } else {
+ if (node1->schema != node2->schema) {
+ return LY_ENOT;
+ }
}
} else {
/* different contexts */
@@ -1209,39 +1290,22 @@
}
}
- if (node1->hash != node2->hash) {
+ if (!(options & LYD_COMPARE_OPAQ) && (node1->hash != node2->hash)) {
return LY_ENOT;
}
/* equal hashes do not mean equal nodes, they can be just in collision so the nodes must be checked explicitly */
- if (!node1->schema) {
- opaq1 = (struct lyd_node_opaq *)node1;
- opaq2 = (struct lyd_node_opaq *)node2;
- if ((strcmp(opaq1->name.name, opaq2->name.name)) || (opaq1->format != opaq2->format) ||
- (strcmp(opaq1->name.module_ns, opaq2->name.module_ns))) {
+ if (!node1->schema || !node2->schema) {
+ if (!(options & LYD_COMPARE_OPAQ) && ((node1->schema && !node2->schema) || (!node1->schema && node2->schema))) {
return LY_ENOT;
}
- switch (opaq1->format) {
- case LY_VALUE_XML:
- if (lyxml_value_compare(LYD_CTX(node1), opaq1->value, opaq1->val_prefix_data, LYD_CTX(node2), opaq2->value,
- opaq2->val_prefix_data)) {
- return LY_ENOT;
- }
- break;
- case LY_VALUE_JSON:
- /* prefixes in JSON are unique, so it is not necessary to canonize the values */
- if (strcmp(opaq1->value, opaq2->value)) {
- return LY_ENOT;
- }
- break;
- default:
- /* not allowed */
- LOGINT(LYD_CTX(node1));
- return LY_EINT;
+ if ((r = lyd_compare_single_value(node1, node2))) {
+ return r;
}
+
if (options & LYD_COMPARE_FULL_RECURSION) {
- iter1 = opaq1->child;
- iter2 = opaq2->child;
+ iter1 = lyd_child(node1);
+ iter2 = lyd_child(node2);
goto all_children_compare;
}
return LY_SUCCESS;
@@ -1254,19 +1318,10 @@
return LY_ENOT;
}
}
-
- term1 = (struct lyd_node_term *)node1;
- term2 = (struct lyd_node_term *)node2;
-
- /* same contexts */
- if (LYD_CTX(node1) == LYD_CTX(node2)) {
- return term1->value.realtype->plugin->compare(&term1->value, &term2->value);
+ if ((r = lyd_compare_single_value(node1, node2))) {
+ return r;
}
- /* different contexts */
- if (strcmp(lyd_get_value(node1), lyd_get_value(node2))) {
- return LY_ENOT;
- }
return LY_SUCCESS;
case LYS_CONTAINER:
case LYS_RPC:
@@ -2508,7 +2563,7 @@
} else {
/* no children hash table */
for ( ; siblings; siblings = siblings->next) {
- if (!lyd_compare_single(siblings, target, 0)) {
+ if (!lyd_compare_single(siblings, target, LYD_COMPARE_OPAQ)) {
break;
}
}
@@ -2640,7 +2695,7 @@
} else {
/* no children hash table */
LY_LIST_FOR(siblings, siblings) {
- if (!lyd_compare_single(target, siblings, 0)) {
+ if (!lyd_compare_single(target, siblings, LYD_COMPARE_OPAQ)) {
ly_set_add(*set, (void *)siblings, 1, NULL);
}
}