@@ -386,6 +386,59 @@ lyd_validate_autodel_node_del(struct lyd_node **first, struct lyd_node *del, con
386386 return node_autodel ;
387387}
388388
389+ /**
390+ * @brief Handle a node whose "when" evaluated to false during multi-error validation.
391+ *
392+ * The node is kept in the tree (so validation can continue) and marked ::LYD_WHEN_FALSE so
393+ * that XPath evaluation treats it as non-existent (returns LY_ENOT) instead of LY_EINCOMPLETE.
394+ * Its descendants are removed from @p node_types and @p node_when so their leafrefs and own
395+ * "when" conditions are not validated against the logically non-existent subtree, which would
396+ * produce spurious cascading errors.
397+ *
398+ * @param[in] node Node with a false "when".
399+ * @param[in,out] node_when Set with nodes with "when" conditions, descendants of @p node are removed.
400+ * @param[in,out] node_types Set with nodes with unresolved types, descendants of @p node are removed.
401+ * @param[in,out] idx Index of @p node in @p node_when, refreshed if any descendants were removed.
402+ */
403+ static void
404+ lyd_validate_when_false (struct lyd_node * node , struct ly_set * node_when , struct ly_set * node_types , uint32_t * idx )
405+ {
406+ struct lyd_node * iter ;
407+ uint32_t j , count ;
408+
409+ /* mark so subsequent XPath evaluations on this node return "no match" instead of LY_EINCOMPLETE */
410+ node -> flags |= LYD_WHEN_FALSE ;
411+
412+ /* remove descendants from node_types so their leafrefs are not validated against the
413+ * when-false subtree (mirrors the cleanup done by lyd_validate_autodel_node_del) */
414+ if (node_types && node_types -> count ) {
415+ LYD_TREE_DFS_BEGIN (node , iter ) {
416+ if ((iter -> schema -> nodetype & LYD_NODE_TERM ) &&
417+ LYSC_GET_TYPE_PLG (((struct lysc_node_leaf * )iter -> schema )-> type -> plugin_ref )-> validate_tree &&
418+ ly_set_contains (node_types , iter , & j )) {
419+ ly_set_rm_index (node_types , j , NULL );
420+ }
421+ LYD_TREE_DFS_END (node , iter );
422+ }
423+ }
424+
425+ /* remove descendants from node_when so their own "when" conditions are not evaluated; a
426+ * when-false subtree is logically non-existent, so child whens are moot */
427+ if (node_when -> count > 1 ) {
428+ count = node_when -> count ;
429+ LYD_TREE_DFS_BEGIN (node , iter ) {
430+ if ((iter != node ) && ly_set_contains (node_when , iter , & j )) {
431+ ly_set_rm_index_ordered (node_when , j , NULL );
432+ }
433+ LYD_TREE_DFS_END (node , iter );
434+ }
435+ if (count > node_when -> count ) {
436+ /* descendants were removed, refresh the iteration index */
437+ ly_set_contains (node_when , node , idx );
438+ }
439+ }
440+ }
441+
389442/**
390443 * @brief Evaluate when conditions of collected unres nodes.
391444 *
@@ -436,43 +489,12 @@ lyd_validate_unres_when(struct lyd_node **tree, const struct lys_module *mod, st
436489 /* only a warning */
437490 LOGWRN (LYD_CTX (node ), "When condition \"%s\" not satisfied." , disabled -> cond -> expr );
438491 } else {
439- /* invalid data; mark the when as resolved-to-false so subsequent XPath
440- * evaluations on this node return "no match" instead of LY_EINCOMPLETE */
441- node -> flags |= LYD_WHEN_FALSE ;
442- /* remove descendants from node_types so their leafrefs are not validated
443- * against the when-false subtree, which would produce spurious cascading
444- * errors (mirrors the cleanup done by lyd_validate_autodel_node_del) */
445- if (node_types && node_types -> count ) {
446- struct lyd_node * iter ;
447- uint32_t idx ;
448-
449- LYD_TREE_DFS_BEGIN (node , iter ) {
450- if ((iter -> schema -> nodetype & LYD_NODE_TERM ) &&
451- LYSC_GET_TYPE_PLG (((struct lysc_node_leaf * )iter -> schema )-> type -> plugin_ref )-> validate_tree &&
452- ly_set_contains (node_types , iter , & idx )) {
453- ly_set_rm_index (node_types , idx , NULL );
454- }
455- LYD_TREE_DFS_END (node , iter );
456- }
457- }
458- /* remove descendants from node_when so their own when conditions are not
459- * evaluated; a when-false subtree is logically non-existent, so child
460- * whens are moot and would otherwise produce spurious cascading errors */
461- if (node_when -> count > 1 ) {
462- struct lyd_node * iter ;
463- uint32_t idx ;
464-
465- count = node_when -> count ;
466- LYD_TREE_DFS_BEGIN (node , iter ) {
467- if ((iter != node ) && ly_set_contains (node_when , iter , & idx )) {
468- ly_set_rm_index_ordered (node_when , idx , NULL );
469- }
470- LYD_TREE_DFS_END (node , iter );
471- }
472- if (count > node_when -> count ) {
473- /* descendants were removed, refresh the iteration index */
474- ly_set_contains (node_when , node , & i );
475- }
492+ /* invalid data; only for multi-error validation keep the node in the tree
493+ * marked as when-false so XPath treats it as non-existent and validation can
494+ * continue without spurious cascading errors. In single-error validation this
495+ * is needless work because validation stops at this error. */
496+ if (val_opts & LYD_VALIDATE_MULTI_ERROR ) {
497+ lyd_validate_when_false (node , node_when , node_types , & i );
476498 }
477499 LOGVAL (LYD_CTX (node ), node , LY_VCODE_NOWHEN , disabled -> cond -> expr );
478500 r = LY_EVALID ;
0 commit comments