[xml] libxml missing tree_walker?



Hi

Ive been a bit back and forth through the reference manual, and usually
end up in the Tree API. What ive been missing though, is a way to
traverse the document for a particular node. Now, i know xpath might do
the trick, but then one would have to inlcude more headers and extract
the path at first. While operating a tree, one can easier get the root
from the document and walk a bit back n forth till the right node pops
up in your 'hands' :)

So i wrote this little recursive tree search, which i'd like to share;
set/get message is just placed in a buffer string, suit error handling
to your needs.
ï
#include <libxml/tree.h>
#include <stdio.h>

xmlDocPtr g_doc;
xmlNodePtr search_result;
int cur_depth = 0;
int validate(xmlNodePtr node)
{
  int x = node->type;
// just a few types of nodes, i wouldnt be too interested in
  if(x != XML_TEXT_NODE  
  && x != XML_NAMESPACE_DECL
  && x != XML_CDATA_SECTION_NODE 
  && x != XML_COMMENT_NODE) {
     return 1;
  } else {
    return 0;
  }
}
int lookup_node(xmlNodePtr node, const char * search_id, int max)
{
  while(node)
  {
    if(validate(node))
    {
      if(xmlStrEqual(node->name, (xmlChar *) search_id) )
      {
        search_result = node;
        return 1;
      }
    }
    if(node->children && cur_depth < max) {
    cur_depth++;
    if(lookup_node(node->children, search_id, max) )
      return 1;
    }
    node = node->next;
  } // WHILE siblings
  cur_depth--;
  return 0;
}
char *node_as_xml(const char * search_id, int search_depth)
{
  search_result = NULL;
  xmlBufferPtr buf = xmlBufferCreate();
  xmlNodePtr node = xmlDocGetRootElement(g_doc);
  while (node)
  { // ROOT sibling loop
    if(validate(node))
    {
      if( xmlStrEqual(node->name,(xmlChar *)search_id) ) {
        search_result = node;
        break;
      }
    }
    if(node->children)
    { 
      if(lookup_node(node->children, search_id,search_depth) )
        break;
    }
    node = node->next;
  }
  if(search_result) { // Success!
    if(xmlNodeDump(buf, g_doc, search_result, 0, 1))
    {
      search_result = NULL;
      return (char *) xmlBufferContent(buf);
    } else {
      //set_message("node_as_xml: FAILED buffering node in query\n");
      return NULL;
    }
  } else { // failed..
    //set_message("node_as_xml: FAILED in search, no such node in tree
\n");
    return NULL;
  }
}
/* Example usage: */
int main(void)
{
  g_doc = xmlNewDoc(BAD_CAST "1.0");
  xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "aRoot");
  xmlDocSetRootElement(g_doc, root);

  xmlNewChild(root, NULL, BAD_CAST "1", NULL);
  xmlNewChild(root, NULL, BAD_CAST "2", NULL);
  xmlNewChild(root, NULL, BAD_CAST "3", NULL);  

  xmlNodePtr node = xmlNewChild(root, NULL, BAD_CAST "4", NULL);
  xmlNewChild(node, NULL, BAD_CAST "4_1", NULL);
  xmlNewChild(node, NULL, BAD_CAST "4_2", BAD_CAST "tryme");
/*
* We look for a node, lookup_node is called recursively while there are
* children. Second parameter is a maximum depth for recursion - we dont
* care here, but large trees might need the option
* First occurence found is return as a char *, which is unfortunately
* never free'd though. Alternatively, return the search_result node 
*  from 'node_as_xml' function.
*/
  char * subtree = node_as_xml("4_2", 999);
  printf("Recursive contents from '4_2'-node \n%s\n", subtree);
}





[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]