[Tutorial] Xử lý file XML với libxml2 trong C

Bài viết này hướng dẫn cách xử lý file XML trong C/C++ với libxml2.

Bài viết dựa trên LibXML tutorial download tại: http://xmlsoft.org/tutorial/xmltutorial.pdf

Mục tiêu:

+ Hướng dẫn các thao tác cơ bản trong xử lý XML: như kiểm tra hợp lệ của file XML, lấy các thông attibute của các node, lấy text content của các node, duyệt các node trong XML Tree với XPath

+ Cung cấp các tài liệu tham khảo cần thiết khi xử lý file XML với C/C++

+ Cung cấp các hàm tiện ích cho xử lý file XML

(1) Định dạng XML: Dùng để lưu trữ và biểu diễn dữ liệu, đặc biệt quan trọng với các dữ liệu trên Web.

Nếu chưa quen thuộc với XML, có thể tham khảo thêm tại: http://www.w3schools.com/xml/default.asp

Ví dụ file XML:

<?xml version="1.0"?>
<note>
 <to>Tove</to>
 <from>Jani</from>
 <heading>Reminder</heading>
 <body>Don't forget me this weekend!</body>
</note>

(2) Xử lý file XML với libxml

3 kiểu dữ liệu cơ bản:

+ xmlChar: Kiểu dữ liệu cơ bản, lưu trữ 1 bye trong UTF-8 Encoding
+ xmlDoc: Cấu trúc dữ liệu chứa tree của xml doc được parsed. xmlDocPtr để lưu trữ con trỏ tới xmlDoc
+ xmlNode và xmlNodePtr: Lưu trữ 1 sing node trong cây

Function 1: Parse một xml file, trả về con trỏ xmlDocPtr, nếu văn bản không được parse thành công trả về NULL.

Thêm các dòng #include sau vào đầu các file

#include <string>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xmlmemory.h>

// Return a pointer of type xmlDocPtr point to xmlDoc
// @docname: xml document name
xmlDocPtr getDoc( const char* docname ) {
  xmlDocPtr doc;
  doc = xmlParseFile( docname );
  if ( doc == NULL ) {
    cerr << "Document not parsed successfully" << endl;
    return NULL;
  }
  return doc;
}

Function 2: Tìm một node với tên cho trước, trả về con trỏ xmlNodePtr

// Return a pointer to xmlNodePtr
// Find the child node with name node_name
xmlNodePtr getChildNode( xmlNodePtr parent, string node_name ) {
  xmlNodePtr cur = parent->xmlChildrenNode;
  while ( cur != NULL ) {
    if ( !xmlStrcmp( cur->name, ( xmlChar* ) node_name.c_str() ) ) {
      return cur;
    }
    cur = cur->next;
  }
  return NULL;
}

Function 3: Tìm node anh em của một node, với tên node được cho trước (Sử dụng hàm next())

// Get sibling node with @node_name
xmlNodePtr getSiblingNode( xmlNodePtr a_node, string node_name ) {
  xmlNodePtr cur = a_node->next;
  while ( cur != NULL ) {
    if ( !xmlStrcmp( cur->name, ( xmlChar* ) node_name.c_str() ) ) {
      return cur;
    }
    cur = cur->next;
  }
    return NULL;
}

Function 4: Trả về giá trị của một attribute của một node, tên cho trước

// Get attribute value of @att_name
string getAttrStr( xmlNodePtr cur, string att_name ) {
 xmlChar* uri = xmlGetProp( cur, (xmlChar*) att_name.c_str() );
 if ( uri == NULL ) {
 cerr << "Attribute " << att_name << " does not exist" << endl;
 return "";
 }
 string att_val = (char*) uri;
 xmlFree(uri);
 return att_val;
}

Function 5: Lấy text content của một node

string getElementContent( xmlDocPtr doc, xmlNodePtr cur ) {
 xmlChar * txt_content = xmlNodeListGetString( doc, cur->xmlChildrenNode, 1);
 if ( txt_content == NULL ) {
 cerr << "Text content does not exist!!!" << endl;
 return "";
 }
 string strContent = (char*) txt_content;
 trimSpaces( strContent );
 xmlFree( txt_content );
 return strContent;
}

Function 6: Trả về một tập các node theo xPath

// Return a pointer to xmlPathObject
// @doc: context of the type xmlDocPtr
// @xpath: criteria for the xpath to retrieve set of nodes
xmlXPathObjectPtr getNodeSet(xmlDocPtr doc, xmlChar* xpath) {
 xmlXPathContextPtr context;
 xmlXPathObjectPtr result;
 context = xmlXPathNewContext( doc );
 if ( context == NULL ) {
 cerr << "Error in xmlXPathNewContext" << endl;
 return NULL;
 }

 result = xmlXPathEvalExpression( xpath, context );
 xmlXPathFreeContext( context );

 if ( result == NULL ) {
 cerr << "Error in xmlXPathEvalExpression" << endl;
 return NULL;
 }

 if ( xmlXPathNodeSetIsEmpty ( result->nodesetval ) ) {
 xmlXPathFreeObject( result );
 // cerr << "No result" << endl;
 return NULL;
 }
 return result;
}