xpath UPDATE improve not-found-node warnings in schema

Refs #1712
diff --git a/src/xpath.c b/src/xpath.c
index a20bc90..cf4964d 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -7150,20 +7150,20 @@
  * @param[in] all_desc Whether to search all the descendants or children only.
  * @param[in,out] set Context and result set.
  * @param[in] options XPath options.
- * @return LY_ERR (LY_EINCOMPLETE on unresolved when)
+ * @return LY_ERR (LY_EINCOMPLETE on unresolved when, LY_ENOT for not found schema node)
  */
 static LY_ERR
 eval_name_test_with_predicate(const struct lyxp_expr *exp, uint16_t *tok_idx, ly_bool attr_axis, ly_bool all_desc,
         struct lyxp_set *set, uint32_t options)
 {
-    char *path;
+    LY_ERR rc = LY_SUCCESS, r;
     const char *ncname, *ncname_dict = NULL;
     uint16_t ncname_len;
     const struct lys_module *moveto_mod = NULL;
     const struct lysc_node *scnode = NULL;
     struct ly_path_predicate *predicates = NULL;
     enum ly_path_pred_type pred_type = 0;
-    LY_ERR rc = LY_SUCCESS;
+    int scnode_skip_pred = 0;
 
     LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
             lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
@@ -7228,6 +7228,22 @@
     } else {
         if (!(options & LYXP_SKIP_EXPR) && (options & LYXP_SCNODE_ALL)) {
             int64_t i;
+            const struct lyxp_set_scnode *scparent = NULL;
+            char *path = NULL, *ppath = NULL;
+
+            /* remember parent if there is only one, to print in the warning */
+            for (i = 0; i < set->used; ++i) {
+                if (set->val.scnodes[i].in_ctx == LYXP_SET_SCNODE_ATOM_CTX) {
+                    if (!scparent) {
+                        /* remember the context node */
+                        scparent = &set->val.scnodes[i];
+                    } else {
+                        /* several context nodes, no reasonable error possible */
+                        scparent = NULL;
+                        break;
+                    }
+                }
+            }
 
             if (all_desc) {
                 rc = moveto_scnode_alldesc(set, moveto_mod, ncname_dict, options);
@@ -7243,9 +7259,30 @@
             }
             if (i == -1) {
                 path = lysc_path(set->cur_scnode, LYSC_PATH_LOG, NULL, 0);
-                LOGWRN(set->ctx, "Schema node \"%.*s\" not found (\"%.*s\") with context node \"%s\".",
-                        ncname_len, ncname, (ncname - exp->expr) + ncname_len, exp->expr, path);
+                if (scparent) {
+                    /* generate path for the parent */
+                    if (scparent->type == LYXP_NODE_ELEM) {
+                        ppath = lysc_path(scparent->scnode, LYSC_PATH_LOG, NULL, 0);
+                    } else if (scparent->type == LYXP_NODE_ROOT) {
+                        ppath = strdup("<root>");
+                    } else if (scparent->type == LYXP_NODE_ROOT_CONFIG) {
+                        ppath = strdup("<config-root>");
+                    }
+                }
+                if (ppath) {
+                    LOGWRN(set->ctx,
+                            "Schema node \"%.*s\" for parent \"%s\" not found; in expr \"%.*s\" with context node \"%s\".",
+                            ncname_len, ncname, ppath, (ncname - exp->expr) + ncname_len, exp->expr, path);
+                } else {
+                    LOGWRN(set->ctx, "Schema node \"%.*s\" not found; in expr \"%.*s\" with context node \"%s\".",
+                            ncname_len, ncname, (ncname - exp->expr) + ncname_len, exp->expr, path);
+                }
                 free(path);
+                free(ppath);
+
+                /* skip the predicates and the rest of this path to not generate invalid warnings */
+                rc = LY_ENOT;
+                scnode_skip_pred = 1;
             }
         } else {
             if (all_desc) {
@@ -7262,13 +7299,22 @@
         }
     }
 
+    if (scnode_skip_pred) {
+        /* skip predicates */
+        options |= LYXP_SKIP_EXPR;
+    }
+
     /* Predicate* */
     while (!lyxp_check_token(NULL, exp, *tok_idx, LYXP_TOKEN_BRACK1)) {
-        rc = eval_predicate(exp, tok_idx, set, options, 1);
-        LY_CHECK_GOTO(rc, cleanup);
+        r = eval_predicate(exp, tok_idx, set, options, 1);
+        LY_CHECK_ERR_GOTO(r, rc = r, cleanup);
     }
 
 cleanup:
+    if (scnode_skip_pred) {
+        /* restore options */
+        options &= ~LYXP_SKIP_EXPR;
+    }
     if (!(options & LYXP_SKIP_EXPR)) {
         lydict_remove(set->ctx, ncname_dict);
         ly_path_predicates_free(set->ctx, pred_type, predicates);
@@ -7360,7 +7406,8 @@
         uint32_t options)
 {
     ly_bool attr_axis;
-    LY_ERR rc;
+    LY_ERR rc = LY_SUCCESS;
+    int scnode_skip_path = 0;
 
     goto step;
     do {
@@ -7396,7 +7443,7 @@
             } else {
                 rc = moveto_self(set, all_desc, options);
             }
-            LY_CHECK_RET(rc);
+            LY_CHECK_GOTO(rc, cleanup);
             LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (set ? "parsed" : "skipped"),
                     lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
             ++(*tok_idx);
@@ -7409,7 +7456,7 @@
             } else {
                 rc = moveto_parent(set, all_desc, options);
             }
-            LY_CHECK_RET(rc);
+            LY_CHECK_GOTO(rc, cleanup);
             LOGDBG(LY_LDGXPATH, "%-27s %s %s[%u]", __func__, (options & LYXP_SKIP_EXPR ? "skipped" : "parsed"),
                     lyxp_print_token(exp->tokens[*tok_idx]), exp->tok_pos[*tok_idx]);
             ++(*tok_idx);
@@ -7418,21 +7465,34 @@
         case LYXP_TOKEN_NAMETEST:
             /* evaluate NameTest Predicate* */
             rc = eval_name_test_with_predicate(exp, tok_idx, attr_axis, all_desc, set, options);
-            LY_CHECK_RET(rc);
+            if (rc == LY_ENOT) {
+                assert(options & LYXP_SCNODE_ALL);
+                /* skip the rest of this path */
+                rc = LY_SUCCESS;
+                scnode_skip_path = 1;
+                options |= LYXP_SKIP_EXPR;
+            }
+            LY_CHECK_GOTO(rc, cleanup);
             break;
 
         case LYXP_TOKEN_NODETYPE:
             /* evaluate NodeType Predicate* */
             rc = eval_node_type_with_predicate(exp, tok_idx, attr_axis, all_desc, set, options);
-            LY_CHECK_RET(rc);
+            LY_CHECK_GOTO(rc, cleanup);
             break;
 
         default:
-            LOGINT_RET(set->ctx);
+            LOGINT(set->ctx);
+            rc = LY_EINT;
+            goto cleanup;
         }
     } while (!exp_check_token2(NULL, exp, *tok_idx, LYXP_TOKEN_OPER_PATH, LYXP_TOKEN_OPER_RPATH));
 
-    return LY_SUCCESS;
+cleanup:
+    if (scnode_skip_path) {
+        options &= ~LYXP_SKIP_EXPR;
+    }
+    return rc;
 }
 
 /**
diff --git a/tests/utests/schema/test_schema_common.c b/tests/utests/schema/test_schema_common.c
index cd6559b..2f4fb4f 100644
--- a/tests/utests/schema/test_schema_common.c
+++ b/tests/utests/schema/test_schema_common.c
@@ -637,7 +637,8 @@
             "    }\n"
             "}";
     assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
-    CHECK_LOG_CTX("Schema node \"l\" not found (\"../../cont/l\") with context node \"/b:cont2/l2\".", NULL);
+    CHECK_LOG_CTX("Schema node \"cont\" for parent \"<config-root>\" not found; in expr \"../../cont\" "
+            "with context node \"/b:cont2/l2\".", NULL);
 
     /* state -> config */
     str = "module c {\n"
@@ -788,7 +789,7 @@
             "    }\n"
             "}";
     assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
-    CHECK_LOG_CTX("Schema node \"l\" not found (\"../l\") with context node \"/h:rp/input/l2\".", NULL);
+    CHECK_LOG_CTX("Schema node \"l\" for parent \"/h:rp\" not found; in expr \"../l\" with context node \"/h:rp/input/l2\".", NULL);
 
     /* rpc input -> notif leafref */
     str = "module i {\n"
@@ -831,7 +832,8 @@
             "    }\n"
             "}";
     assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
-    CHECK_LOG_CTX("Schema node \"l\" not found (\"/notif/l\") with context node \"/i:rp/input/l2\".", NULL);
+    CHECK_LOG_CTX("Schema node \"notif\" for parent \"<root>\" not found; in expr \"/notif\" "
+            "with context node \"/i:rp/input/l2\".", NULL);
 
     /* action output -> state */
     str = "module j {\n"
@@ -923,7 +925,8 @@
             "    }\n"
             "}";
     assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS);
-    CHECK_LOG_CTX("Schema node \"l\" not found (\"/cont/ll/act/l\") with context node \"/k:cont/ll/act/output/l2\".", NULL);
+    CHECK_LOG_CTX("Schema node \"l\" for parent \"/k:cont/ll/act\" not found; in expr \"/cont/ll/act/l\" "
+            "with context node \"/k:cont/ll/act/output/l2\".", NULL);
 }
 
 void