libxml2的使用

在存取或传递数据时,考虑到可扩展性,一般会将数据按某种格式进行组织,常见的类型有ini/xml/json等,其中xml的可读性更为友好,在效率要求不是太高的情况下,还是有用武之地。操作xml常用的库有libxml2和tinyxml,下面简单介绍通过libxml2读写xml的方法。

基本数据类型

xmlChar说明

xmlNode的常用成员

常用函数

下面是根据某个项目的实际情况,对libxml2接口做了封装,基本涵盖了上述提及的内容。

#ifndef XML_IF_H
#define XML_IF_H

#include <libxml/tree.h>
#include <libxml/parser.h>

typedef enum
{
    XML_RET_SUCCESS,
    XML_RET_NULL_POINTER,
    XML_RET_EMPTY_XML_DATA,
    XML_RET_ADD_CHILD_ERROR,
    XML_RET_DUPLICATE_ATTR,
    XML_RET_SYSTEM_ERROR,
    XML_RET_NO_SUCH_ATTR,
}XmlRetCode;

typedef xmlChar        XmlChar;
typedef xmlNodePtr     XmlNodePtr;
typedef xmlAttrPtr     XmlAttrPtr;
typedef xmlDocPtr      XmlDocPtr;

typedef struct
{
    XmlDocPtr   doc;
    XmlNodePtr  root;
}XmlHandle, *XmlHandlePtr;

XmlRetCode XmlGetData(const char *xmlData, XmlHandlePtr handle);
XmlRetCode XmlGetDataFromFile(const char *xmlPath, XmlHandlePtr handle);
XmlRetCode XmlPutData(const XmlHandlePtr handle, char **xmlData);
XmlRetCode XmlPutDataToFile(const XmlHandlePtr handle, char *xmlPath);
XmlRetCode XmlNewXml(XmlHandlePtr handle, const char *rootName);
XmlRetCode XmlFreeXml(XmlHandlePtr handle);
XmlNodePtr XmlNewNode(const char *name);
XmlRetCode XmlNewAttr(XmlNodePtr node, const char *attrName, const char *attrValue);
XmlRetCode XmlGetAttr(const XmlNodePtr node, const char *attrName, char *attrValue);
XmlRetCode XmlSetAttr(XmlNodePtr node, const char *attrName, const char *attrValue);
XmlNodePtr XmlAddNode(XmlHandlePtr handle, const char *nodeName, const char *attrs, ...);

#endif
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include "xmlif.h"

XmlRetCode XmlGetData(const char *xmlData, XmlHandlePtr handle)
{
    if (NULL == xmlData || NULL == handle)
        return XML_RET_NULL_POINTER;
    xmlKeepBlanksDefault(0);
    handle->doc = xmlReadMemory(xmlData, strlen(xmlData), NULL, "UTF-8", 0);
    if (NULL == (handle->root = xmlDocGetRootElement(handle->doc)))
        return XML_RET_EMPTY_XML_DATA;
    return XML_RET_SUCCESS;
}

XmlRetCode XmlGetDataFromFile(const char *xmlPath, XmlHandlePtr handle)
{
    if (NULL == xmlPath || NULL == handle)
        return XML_RET_NULL_POINTER;
    xmlKeepBlanksDefault(0);
    xmlParserInputBufferCreateFilenameDefault(NULL);
    handle->doc = xmlReadFile(xmlPath, "UTF-8", 0);
    if (NULL == (handle->root = xmlDocGetRootElement(handle->doc)))
        return XML_RET_EMPTY_XML_DATA;
    return XML_RET_SUCCESS;
}

XmlRetCode XmlPutData(const XmlHandlePtr handle, char **xmlData)
{
    xmlChar *buf = NULL;
    int bufSize = 0;
    if (NULL == handle) return XML_RET_NULL_POINTER;
    xmlDocDumpFormatMemoryEnc(handle->doc, &buf, &bufSize, "UTF-8", 1);
    *xmlData = strdup((const char*)buf);
    xmlFree(buf);
    return XML_RET_SUCCESS;
}

XmlRetCode XmlPutDataToFile(const XmlHandlePtr handle, char *xmlPath)
{
    if (NULL == handle || NULL == xmlPath)
        return XML_RET_NULL_POINTER;
    xmlKeepBlanksDefault(1);
    xmlSaveFormatFileEnc(xmlPath, handle->doc, "UTF-8", 1);
    return XML_RET_SUCCESS;
}

XmlRetCode XmlNewXml(XmlHandlePtr handle, const char *rootName)
{
    if (NULL == handle || NULL == rootName)
        return XML_RET_NULL_POINTER;
    handle->doc = xmlNewDoc(BAD_CAST"1.0");
    handle->root = xmlNewNode(NULL, BAD_CAST(rootName));
    xmlDocSetRootElement(handle->doc, handle->root);
    return XML_RET_SUCCESS;
}

XmlRetCode XmlFreeXml(XmlHandlePtr handle)
{
    if (handle) {
        if (handle->doc)
            xmlFreeDoc(handle->doc);
        handle->doc = NULL;
    }
    return XML_RET_SUCCESS;
}

XmlNodePtr XmlNewNode(const char *name)
{
    return name ? xmlNewNode(NULL, BAD_CAST(name)) : NULL;
}

XmlRetCode XmlNewAttr(XmlNodePtr node, const char *attrName, const char *attrValue)
{
    if (NULL == node || NULL == attrName || NULL == attrValue)
        return XML_RET_NULL_POINTER;
    if (xmlHasProp(node, BAD_CAST(attrName)))
        return XML_RET_DUPLICATE_ATTR;
    xmlNewProp(node, BAD_CAST(attrName), BAD_CAST(attrValue));
    return XML_RET_SUCCESS;
}

XmlRetCode XmlGetAttr(const XmlNodePtr node, const char *attrName, char *attrValue)
{
    if (NULL == node || NULL == attrName || NULL == attrValue)
        return XML_RET_NULL_POINTER;
    xmlChar *buf = xmlGetProp(node, BAD_CAST(attrName));
    if (NULL == buf)
        return XML_RET_NO_SUCH_ATTR;
    strcpy(attrValue, (char*)buf);
    xmlFree(buf);
    return XML_RET_SUCCESS;
}

XmlRetCode XmlSetAttr(XmlNodePtr node, const char *attrName, const char *attrValue)
{
    const char *val;
    if (NULL == node || NULL == attrName)
        return XML_RET_NULL_POINTER;
    val = attrValue ? attrValue : "";
    if (xmlHasProp(node, attrName))
        xmlSetProp(node, attrName, val);
    else
        xmlNewProp(node, attrName, val);
    return XML_RET_SUCCESS;
}

XmlNodePtr XmlAddNode(XmlHandlePtr handle, const char *nodeName, const char *attrs, ...)
{
    va_list ap;
    char attrName[256], attrValue[1024], *p;
    int val;

    if (NULL == handle || NULL == nodeName)
        return NULL;
    XmlNodePtr node = xmlNewNode(NULL, BAD_CAST(nodeName));
    for (va_start(ap, attrs); attrs; attrs = va_arg(ap, const char*)) {
        p = strcpy(attrName, attrs);
        if (strchr("<>", *p)) {
            val = va_arg(ap, int);
            if ('<' == *p) sprintf(attrValue, "%d", val);
            else sprintf(attrValue, "0x%x", val);
            p++;
        } else {
            attrs = va_arg(ap, const char*);
            strcpy(attrValue, attrs);
        }
        xmlNewProp(node, BAD_CAST(p), BAD_CAST(attrValue));
    }
    if (NULL == xmlAddChild(handle->root, node)) {
        xmlFree(node);
        return NULL;
    }
    return node;
}

使用libxml2库时,需要包含头文件<libxml/parse.h>和<libxml/tree.h>,在链接时带上-lxml2。

最后是xml中必须转义的字符:

Table of Contents