/** * Free an XML node. * * This is the user-visible routine that can succeed only if the node is * not part of a tree structure. */ void xnode_free(xnode_t *xn) { etree_t t; xnode_check(xn); etree_init_root(&t, xn, TRUE, offsetof(xnode_t, node)); g_assert(etree_is_standalone(&t, xn)); switch (xn->type) { case XNODE_T_COMMENT: HFREE_NULL(xn->u.c.text); break; case XNODE_T_TEXT: HFREE_NULL(xn->u.t.text); break; case XNODE_T_PI: atom_str_free_null(&xn->u.pi.name); HFREE_NULL(xn->u.pi.target); break; case XNODE_T_ELEMENT: atom_str_free_null(&xn->u.e.name); atom_str_free_null(&xn->u.e.ns_uri); nv_table_free_null(&xn->u.e.ns); xattr_table_free_null(&xn->u.e.attrs); break; case XNODE_T_MAX: g_assert_not_reached(); } xn->magic = 0; WFREE(xn); }
/** * Make sure node is orphan. */ static void xnode_orphan_check(const xnode_t * const xn) { etree_t t; xnode_check(xn); etree_init_root(&t, xn, TRUE, offsetof(xnode_t, node)); g_assert(etree_is_orphan(&t, xn)); }
/** * @return last child node, or NULL if the node has no children (leaf node). */ xnode_t * xnode_last_child(const xnode_t *xn) { etree_t t; xnode_check(xn); etree_init_root(&t, xn, TRUE, offsetof(xnode_t, node)); return etree_last_child(&t, xn); }
/** * @return next sibbling node, or NULL if the node has no more siblings. */ xnode_t * xnode_next_sibling(const xnode_t *xn) { etree_t t; xnode_check(xn); etree_init_root(&t, xn, TRUE, offsetof(xnode_t, node)); return etree_next_sibling(&t, xn); }
/** * Recursively apply function on each node, in depth-first mode. * * Traversal is done in such a way that the applied function can safely * free up the local node. */ void xnode_tree_foreach(xnode_t *root, data_fn_t func, void *data) { etree_t t; xnode_check(root); etree_init_root(&t, root, TRUE, offsetof(xnode_t, node)); etree_foreach(&t, func, data); }
/** * Detach node and all its sub-tree from a tree, making it the new root of * a smaller tree. */ void xnode_detach(xnode_t *xn) { etree_t t; xnode_check(xn); etree_init_root(&t, xn, TRUE, offsetof(xnode_t, node)); etree_detach(&t, xn); }
/** * Free an XML tree, recursively. */ void xnode_tree_free(xnode_t *root) { etree_t t; xnode_check(root); etree_init_root(&t, root, TRUE, offsetof(xnode_t, node)); etree_free(&t, xnode_item_free); }
/** * Recursively apply matching function on each node, in depth-first order, * until it returns TRUE, at which time we return the matching node. * * @return the first matching node in the traversal path, NULL if none matched. */ xnode_t * xnode_tree_find(xnode_t *root, match_fn_t func, void *data) { etree_t t; xnode_check(root); etree_init_root(&t, root, TRUE, offsetof(xnode_t, node)); return etree_find(&t, func, data); }
/** * Add orphan node as right-sibling of previous node (cannot be the root node). */ void xnode_add_sibling(xnode_t *previous, xnode_t *node) { etree_t t; xnode_check(previous); xnode_orphan_check(node); etree_init_root(&t, previous, TRUE, offsetof(xnode_t, node)); etree_add_right_sibling(&t, previous, node); }
/** * Add parentless node under parent as first child. */ void xnode_add_first_child(xnode_t *parent, xnode_t *node) { etree_t t; xnode_check(parent); xnode_orphan_check(node); etree_init_root(&t, parent, TRUE, offsetof(xnode_t, node)); etree_prepend_child(&t, parent, node); }
/** * Free sub-tree, destroying all its items and removing the reference in * the parent node, if any. * * @param tree the tree descriptor * @param item root item of sub-tree to remove * @param fcb free routine for each item */ void etree_sub_free(etree_t *tree, void *item, free_fn_t fcb) { etree_t dtree; etree_check(tree); etree_detach(tree, item); etree_init_root(&dtree, item, etree_is_extended(tree), tree->offset); etree_free(&dtree, fcb); }
/** * Recursively apply two functions on each node, in depth-first mode. * * The first function "enter" is called when we enter a node and the * second "leave" is called when all the children have been processed, * before returning. * * Traversal is done in such a way that the "leave" function can safely * free up the local node. * * Traversal of a branch is aborted when "enter" returns FALSE, i.e. the * children of the node are not traversed and the "leave" callback is not * called since we did not enter... */ void xnode_tree_enter_leave(xnode_t *root, match_fn_t enter, data_fn_t leave, void *data) { etree_t t; xnode_check(root); etree_init_root(&t, root, TRUE, offsetof(xnode_t, node)); etree_traverse(&t, ETREE_TRAVERSE_ALL | ETREE_CALL_AFTER, 0, ETREE_MAX_DEPTH, enter, leave, data); }
/** * Same as xnode_tree_find() but limit search to specified depth: 0 means * the root node only, 1 corresponds to the immediate children of the root, * and so on. * * @return the first matching node in the traversal path, NULL if none matched. */ xnode_t * xnode_tree_find_depth(xnode_t *root, unsigned depth, match_fn_t func, void *data) { etree_t t; xnode_check(root); g_assert(uint_is_non_negative(depth)); etree_init_root(&t, root, TRUE, offsetof(xnode_t, node)); return etree_find_depth(&t, depth, func, data); }