Friday, March 11, 2011

LibXML Tutorial

Download: Fast, Fun, Awesome

In this blog post I will show some basic function of libxml, which is a freely licensed C language XML library.
This post gives an idea to beginners how to manipulate xml files using libxml library function. This post does not cover all XML API available in libxml, but it just gives an idea how to use libxml API's with the help of some basic functions.

For detailed XML API list please visit official website of libxml.

To Parse XML file:
xmlDocPtr doc;  // pointer to parse xml Document
  
  // Parse XML file
  doc = xmlParseFile(xmlFileName);

  // Check to see that the document was successfully parsed.
  if (doc == NULL ) {
    fprintf(stderr,"Error!. Document is not parsed successfully. \n");
    return;
  }


To Get the root Document:

// Retrieve the document's root element.
  cur = xmlDocGetRootElement(doc);

  // Check to make sure the document actually contains something
  if (cur == NULL) {
    fprintf(stderr,"Document is Empty\n");
    xmlFreeDoc(doc);
    return;
  }


To Get the child Nodes of the current node element:

  cur = cur->xmlChildrenNode;


To Search for an attribute:

// search for "hash" attribute in the node pointed by cur
 attr = xmlHasProp(cur, (const xmlChar*)"hash");


To add new Attribute:

/*
 * New Attribute "hash" is added to element node pointed by cur,
*  and default value of the attribute is set to "12345678"
 */
 attr = xmlNewProp(cur, (const xmlChar*)"hash", (const xmlChar*)"12345678");


To Save XML document to Disk:

xmlSaveFormatFile (xmlFileName, doc, 1);



Complete Example is given below:
Suppose data.xml file is as follows:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root SYSTEM "secPolicy2.dtd">
<root>
  <url>
    <host hash="12345678">www.example1.com</host>
    <sctxid>2</sctxid>
  </url>
  <url>
    <host>www.example2.com</host>
    <sctxid>2</sctxid>
  </url>
    <url>
    <host>www.example3.com</host>
    <sctxid>3</sctxid>
  </url>

</root>

Following program reads the above xml file supplied as command line argument.
It adds "hash" attribute with default value set to "12345678" if its not present in the "host" element node.

/*
 * Filename = xmlexample.c
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

/*
 * Parse URL Element Node in XML file
 * <url>
 *    <host hash="hash_val_of_hostname">www.example.com</host>
 *    <sctxid>Integer</sctxid>
 * </url>
 */
void parseURL (xmlDocPtr doc, xmlNodePtr cur) {
  xmlChar *key;
  xmlAttrPtr attr;

  // Get the childern Element Node of "url" node
  cur = cur->xmlChildrenNode;

  while (cur != NULL) {
    // check for "host" childern element node of "url" node
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"host"))) {
      key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
      fprintf(stderr,"host: %s\n", key);
      xmlFree(key);
  
      // search for "hash" attribute in the "host" node
      attr = xmlHasProp(cur, (const xmlChar*)"hash");
     
      // if attr is not found then set it
      if(attr == NULL){
    /*
     * Add the Attribute and value of the attribute
     */
    attr = xmlNewProp(cur, (const xmlChar*)"hash", (const xmlChar*)"12345678");
   
    /* Attribute is now set and has value.
     * Just retrieve the value and display it
     */
    key = xmlGetProp(cur, (const xmlChar*)"hash");
    fprintf(stderr,"hash: %s\n", key);
    xmlFree(key);   

      }else{
    /* Attribute is available
     * Just retrieve the value and display it
     */
    key = xmlGetProp(cur, (const xmlChar*)"hash");
    fprintf(stderr, "hash: %s\n", key);
    xmlFree(key);     
      }
          
    } // end of IF loop " host"
     
    // check for "sctxid" childern element node of "url" node
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"sctxid"))) {
      key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
      fprintf(stderr,"sctxid: %s\n", key);
      xmlFree(key);
    } // end of If loop "sctxid"
 
      cur = cur->next;
  } // end of While loop

  return;

} // end of parseURL function()

/*
 * Parsing the XML file and Reading the Element Nodes
 */
static void parseDoc(char *xmlFileName) {
  xmlDocPtr doc;  // pointer to parse xml Document
  xmlNodePtr cur; // node pointer. It interacts with individual node

  // Parse XML file
  doc = xmlParseFile(xmlFileName);

  // Check to see that the document was successfully parsed.
  if (doc == NULL ) {
    fprintf(stderr,"Error!. Document is not parsed successfully. \n");
    return;
  }

  // Retrieve the document's root element.
  cur = xmlDocGetRootElement(doc);

  // Check to make sure the document actually contains something
  if (cur == NULL) {
    fprintf(stderr,"Document is Empty\n");
    xmlFreeDoc(doc);
    return;
  }

  /* We need to make sure the document is the right type.
   * "root" is the root type of the documents used in user Config XML file
   */
  if (xmlStrcmp(cur->name, (const xmlChar *) "root")) {
    fprintf(stderr,"Document is of the wrong type, root node != root");
    xmlFreeDoc(doc);
    return;
  }

  /* Get the first child node of cur.
   * At this point, cur points at the document root,
   * which is the element "root"
   */
  cur = cur->xmlChildrenNode;

  // This loop iterates through the elements that are children of "root"
  while (cur != NULL) {
    if ((!xmlStrcmp(cur->name, (const xmlChar *)"url"))){
      parseURL (doc, cur);
    }
    cur = cur->next;
  }

  /* Save XML document to the Disk
   * Otherwise, you changes will not be reflected to the file.
   * Currently it's only in the memory
   */
  xmlSaveFormatFile (xmlFileName, doc, 1);

  /*free the document */
  xmlFreeDoc(doc);

  /*
   * Free the global variables that may
   * have been allocated by the parser.
   */
    xmlCleanupParser();

  return;

} // end of XMLParseDoc function


int main(int argc, char **argv) {
  char *xmlFileName;

  if (argc <= 1) {
    printf("Usage: %s inputfile.xml\n", argv[0]);
    return(0);
  }

  // Get the file name from the argv[1]
  xmlFileName = argv[1];

  // Custom function to parse XML file
  parseDoc (xmlFileName);

  return (1);
}


To compile the above program use following command:
$ gcc `xml2-config --cflags --libs` -o xmlexample xmlexample.c

To run the program, use following command:
$ ./xmlexample data.xml

4 comments:

  1. alternatively, u could compile this way
    $ gcc xmlexample.c -I/user/include/libxml2 -lxml2 -o xmlexample

    ReplyDelete
  2. Hi i am on ubuntu 12 which packages should i have installed in order to compile your example ?

    ReplyDelete
  3. thanks for tutorial.i want to form xml which is as follows

    base64 encoded fully valid Auth XML for resident



    but i m able to create a xml which is as follows

    base64 encoded fully valid Auth XML for resident



    using following code
    doc = xmlNewDoc("1.0");
    root = xmlNewNode(NULL, "Kyc");
    xmlSetProp(root, "ver", "1.6");
    xmlSetProp(root, "ts", "public");
    xmlSetProp(root, "ra", "public");
    xmlSetProp(root, "rc", "public");
    xmlDocSetRootElement(doc, root);

    tempnode=xmlNewNode(NULL,"Rad");
    xmlAddChild(root, tempnode);
    xmlNodeSetContent(tempnode,b64authxmldata);

    xmlDocDumpFormatMemory(doc, &preDigSignedXmlBuff, &buffersize, 1);

    how to add



    these elements
    what change i have to do in code

    ReplyDelete