schema tree FEATURE lys_find_xpath() function
diff --git a/src/tree_schema.c b/src/tree_schema.c
index 8614c9b..084d527 100644
--- a/src/tree_schema.c
+++ b/src/tree_schema.c
@@ -333,6 +333,50 @@
     return ret;
 }
 
+API LY_ERR
+lys_find_xpath(const struct lysc_node *ctx_node, const char *xpath, int options, struct ly_set **set)
+{
+    LY_ERR ret = LY_SUCCESS;
+    struct lyxp_set xp_set;
+    struct lyxp_expr *exp;
+    uint32_t i;
+
+    LY_CHECK_ARG_RET(NULL, ctx_node, xpath, set, LY_EINVAL);
+    if (!(options & LYXP_SCNODE_ALL)) {
+        options = LYXP_SCNODE;
+    }
+
+    memset(&xp_set, 0, sizeof xp_set);
+
+    /* compile expression */
+    exp = lyxp_expr_parse(ctx_node->module->ctx, xpath, 0, 1);
+    LY_CHECK_ERR_GOTO(!exp, ret = LY_EINVAL, cleanup);
+
+    /* atomize expression */
+    ret = lyxp_atomize(exp, LYD_JSON, ctx_node->module, ctx_node, LYXP_NODE_ELEM, &xp_set, options);
+    LY_CHECK_GOTO(ret, cleanup);
+
+    /* allocate return set */
+    *set = ly_set_new();
+    LY_CHECK_ERR_GOTO(!*set, LOGMEM(ctx_node->module->ctx); ret = LY_EMEM, cleanup);
+
+    /* transform into ly_set */
+    (*set)->objs = malloc(xp_set.used * sizeof *(*set)->objs);
+    LY_CHECK_ERR_GOTO(!(*set)->objs, LOGMEM(ctx_node->module->ctx); ret = LY_EMEM, cleanup);
+    (*set)->size = xp_set.used;
+
+    for (i = 0; i < xp_set.used; ++i) {
+        if ((xp_set.val.scnodes[i].type == LYXP_NODE_ELEM) && (xp_set.val.scnodes[i].in_ctx == 1)) {
+            ly_set_add(*set, xp_set.val.scnodes[i].scnode, LY_SET_OPT_USEASLIST);
+        }
+    }
+
+cleanup:
+    lyxp_set_free_content(&xp_set);
+    lyxp_expr_free(ctx_node->module->ctx, exp);
+    return ret;
+}
+
 char *
 lysc_path_until(const struct lysc_node *node, const struct lysc_node *parent, LYSC_PATH_TYPE pathtype, char *buffer,
                 size_t buflen)
diff --git a/src/tree_schema.h b/src/tree_schema.h
index e102209..8499a76 100644
--- a/src/tree_schema.h
+++ b/src/tree_schema.h
@@ -1777,6 +1777,10 @@
  */
 LY_ERR lysc_feature_value(const struct lysc_feature *feature);
 
+#define LYXP_SCNODE 0x02        /**< No special tree access modifiers. */
+#define LYXP_SCNODE_SCHEMA 0x04 /**< Apply node access restrictions defined for 'when' and 'must' evaluation. */
+#define LYXP_SCNODE_OUTPUT 0x08 /**< Search RPC/action output nodes instead of input ones. */
+
 /**
  * @brief Get all the schema nodes (atoms) that are required for \p xpath to be evaluated.
  *
@@ -1790,9 +1794,18 @@
  */
 LY_ERR lys_atomize_xpath(const struct lysc_node *ctx_node, const char *xpath, int options, struct ly_set **set);
 
-#define LYXP_SCNODE 0x02        /**< No special tree access modifiers. */
-#define LYXP_SCNODE_SCHEMA 0x04 /**< Apply node access restrictions defined for 'when' and 'must' evaluation. */
-#define LYXP_SCNODE_OUTPUT 0x08 /**< Search RPC/action output nodes instead of input ones. */
+/**
+ * @brief Evaluate an \p xpath expression on schema nodes.
+ *
+ * @param[in] ctx_node XPath schema context node.
+ * @param[in] xpath Data XPath expression filtering the matching nodes. ::LYD_JSON format is expected.
+ * @param[in] options Whether to apply some node access restrictions, one of the options should always be used.
+ * If none is set, ::LYXP_SCNODE is used.
+ * @param[out] set Set of found schema nodes.
+ * @return LY_SUCCESS on success, @p set is returned.
+ * @return LY_ERR value if an error occurred.
+ */
+LY_ERR lys_find_xpath(const struct lysc_node *ctx_node, const char *xpath, int options, struct ly_set **set);
 
 /**
  * @brief Types of the different schema paths.