@@ -3015,6 +3015,139 @@ lyd_eval_xpath4(const struct lyd_node *ctx_node, const struct lyd_node *tree, co
30153015 return ret ;
30163016}
30173017
3018+ /**
3019+ * @brief Hash table node equal callback.
3020+ */
3021+ static ly_bool
3022+ lyd_trim_equal_cb (void * val1_p , void * val2_p , ly_bool UNUSED (mod ), void * UNUSED (cb_data ))
3023+ {
3024+ struct lyd_node * node1 , * node2 ;
3025+
3026+ node1 = * (struct lyd_node * * )val1_p ;
3027+ node2 = * (struct lyd_node * * )val2_p ;
3028+
3029+ return node1 == node2 ;
3030+ }
3031+
3032+ LIBYANG_API_DEF LY_ERR
3033+ lyd_trim_xpath (struct lyd_node * * tree , const char * xpath , const struct lyxp_var * vars )
3034+ {
3035+ LY_ERR ret = LY_SUCCESS ;
3036+ struct ly_ctx * ctx ;
3037+ struct lyxp_set xp_set = {0 };
3038+ struct lyxp_expr * exp = NULL ;
3039+ struct lyd_node * node , * parent ;
3040+ struct lyxp_set_hash_node hnode ;
3041+ struct ly_ht * parent_ht = NULL ;
3042+ struct ly_set free_set = {0 };
3043+ uint32_t i , hash ;
3044+ ly_bool is_result ;
3045+
3046+ LY_CHECK_ARG_RET (NULL , tree , xpath , LY_EINVAL );
3047+
3048+ if (!* tree ) {
3049+ /* nothing to do */
3050+ goto cleanup ;
3051+ }
3052+
3053+ * tree = lyd_first_sibling (* tree );
3054+ ctx = (struct ly_ctx * )LYD_CTX (* tree );
3055+
3056+ /* parse expression */
3057+ ret = lyxp_expr_parse (ctx , xpath , 0 , 1 , & exp );
3058+ LY_CHECK_GOTO (ret , cleanup );
3059+
3060+ /* evaluate expression */
3061+ ret = lyxp_eval (ctx , exp , NULL , LY_VALUE_JSON , NULL , * tree , * tree , * tree , vars , & xp_set , LYXP_IGNORE_WHEN );
3062+ LY_CHECK_GOTO (ret , cleanup );
3063+
3064+ /* create hash table for all the parents of results */
3065+ parent_ht = lyht_new (32 , sizeof * node , lyd_trim_equal_cb , NULL , 1 );
3066+ LY_CHECK_GOTO (!parent_ht , cleanup );
3067+
3068+ for (i = 0 ; i < xp_set .used ; ++ i ) {
3069+ if (xp_set .val .nodes [i ].type != LYXP_NODE_ELEM ) {
3070+ /* ignore */
3071+ continue ;
3072+ }
3073+
3074+ for (parent = lyd_parent (xp_set .val .nodes [i ].node ); parent ; parent = lyd_parent (parent )) {
3075+ /* add the parent into parent_ht */
3076+ ret = lyht_insert (parent_ht , & parent , parent -> hash , NULL );
3077+ if (ret == LY_EEXIST ) {
3078+ /* shared parent, we are done */
3079+ break ;
3080+ }
3081+ LY_CHECK_GOTO (ret , cleanup );
3082+ }
3083+ }
3084+
3085+ hnode .type = LYXP_NODE_ELEM ;
3086+ LY_LIST_FOR (* tree , parent ) {
3087+ LYD_TREE_DFS_BEGIN (parent , node ) {
3088+ if (lysc_is_key (node -> schema )) {
3089+ /* ignore */
3090+ goto next_iter ;
3091+ }
3092+
3093+ /* check the results */
3094+ is_result = 0 ;
3095+ if (xp_set .ht ) {
3096+ hnode .node = node ;
3097+ hash = lyht_hash_multi (0 , (const char * )& hnode .node , sizeof hnode .node );
3098+ hash = lyht_hash_multi (hash , (const char * )& hnode .type , sizeof hnode .type );
3099+ hash = lyht_hash_multi (hash , NULL , 0 );
3100+
3101+ if (!lyht_find (xp_set .ht , & hnode , hash , NULL )) {
3102+ is_result = 1 ;
3103+ }
3104+ } else {
3105+ /* not enough elements for a hash table */
3106+ for (i = 0 ; i < xp_set .used ; ++ i ) {
3107+ if (xp_set .val .nodes [i ].type != LYXP_NODE_ELEM ) {
3108+ /* ignore */
3109+ continue ;
3110+ }
3111+
3112+ if (xp_set .val .nodes [i ].node == node ) {
3113+ is_result = 1 ;
3114+ break ;
3115+ }
3116+ }
3117+ }
3118+
3119+ if (is_result ) {
3120+ /* keep the whole subtree if the node is in the results */
3121+ LYD_TREE_DFS_continue = 1 ;
3122+ } else if (lyht_find (parent_ht , & node , node -> hash , NULL )) {
3123+ /* free the whole subtree if the node is not even among the selected parents */
3124+ ret = ly_set_add (& free_set , node , 1 , NULL );
3125+ LY_CHECK_GOTO (ret , cleanup );
3126+ LYD_TREE_DFS_continue = 1 ;
3127+ } /* else keep the parent node because a subtree is in the results */
3128+
3129+ next_iter :
3130+ LYD_TREE_DFS_END (parent , node );
3131+ }
3132+ }
3133+
3134+ /* free */
3135+ for (i = 0 ; i < free_set .count ; ++ i ) {
3136+ node = free_set .dnodes [i ];
3137+ if (* tree == node ) {
3138+ * tree = (* tree )-> next ;
3139+ }
3140+ lyd_free_tree (node );
3141+ }
3142+
3143+ cleanup :
3144+ lyxp_set_free_content (& xp_set );
3145+ lyxp_expr_free (ctx , exp );
3146+ lyht_free (parent_ht , NULL );
3147+ ly_set_erase (& free_set , NULL );
3148+ return ret ;
3149+ }
3150+
30183151LIBYANG_API_DEF LY_ERR
30193152lyd_find_path (const struct lyd_node * ctx_node , const char * path , ly_bool output , struct lyd_node * * match )
30203153{
0 commit comments