问题描述
这是在 C 中打印 xml 树的代码。如何迭代地编写它?
static void
print_element_names(xmlNode *a_node)
{
xmlNode *cur_node = NULL;
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
printf("node type: Element,name: %s\n",cur_node->name);
}
print_element_names(cur_node->children);
}
}
解决方法
您可以利用 libxml2 中使用的 parent
结构中的 xmlNode
节点:
typedef struct _xmlNode xmlNode;
struct _xmlNode {
void *_private; // application data
xmlElementType type; // type number,must be second !
const xmlChar *name; // the name of the node,or the entity
struct _xmlNode *children; // parent->childs link
struct _xmlNode *last; // last child link
struct _xmlNode *parent; // child->parent link
struct _xmlNode *next; // next sibling link
struct _xmlNode *prev; // previous sibling link
struct _xmlDoc *doc; // the containing document End of common p
xmlNs *ns; // pointer to the associated namespace
xmlChar *content; // the content
struct _xmlAttr *properties; // properties list
xmlNs *nsDef; // namespace definitions on this node
void *psvi; // for type/PSVI informations
unsigned short line; // line number
unsigned short extra; // extra data for XPath/XSLT
};
这是一个非递归版本:
static void print_element_names(xmlNode *a_node) {
if (a_node != NULL) {
xmlNode *stop = a_node->parent;
xmlNode *cur_node = a_node;
int skip = 0;
for (;;) {
if (!skip) {
if (cur_node->type == XML_ELEMENT_NODE) {
printf("node type: Element,name: %s\n",cur_node->name);
}
if (cur_node->children) {
cur_node = cur_node->children;
continue;
}
}
if (cur_node->next) {
cur_node = cur_node->next;
skip = 0;
} else {
cur_node = cur_node->parent;
if (cur_node == stop)
break;
skip = 1;
}
}
}
}
,
在 libxml2 的上下文中,这是处理前序和后序遍历的一般方法。正如@chqrlie 所指出的,libxml2 存储一个指向父节点的指针,因此您可以使用常量内存迭代子树。
typedef void
(*callbackFn)(xmlNode *cur,void *data);
void
iterateSubtree(xmlNode *cur,callbackFn callbackPreorder,callbackFn callbackPostorder,void *data) {
xmlNode *orig;
if (!cur)
return;
orig = cur;
do {
callbackPreorder(cur,data);
while (cur->children) {
cur = cur->children;
callbackPreorder(cur,data);
}
while (cur != orig) {
// Storing a copy of next and parent allows the postorder
// callback to append to or delete a node.
xmlNode *next = cur->next;
xmlNode *parent = cur->parent;
callbackPostorder(cur,data);
if (next) {
cur = next;
break;
}
cur = parent;
}
} while (cur != orig);
callbackPostorder(cur,data);
}