libxml2的使用
在存取或传递数据时,考虑到可扩展性,一般会将数据按某种格式进行组织,常见的类型有ini/xml/json等,其中xml的可读性更为友好,在效率要求不是太高的情况下,还是有用武之地。操作xml常用的库有libxml2和tinyxml,下面简单介绍通过libxml2读写xml的方法。
基本数据类型
- xmlChar, xmlChar*: 字符(串)
- xmlDoc, xmlDocPtr: xml文档句柄
- xmlNode, xmlNodePtr: xml节点
- xmlAttr, xmlAttrPtr: xml节点属性
xmlChar说明
- xmlChar类型的定义为:
typedef unsigned char xmlChar;
,使用unsigned char作为内部字符格式是考虑到它能较好地适应UTF-8编码,而UTF-8编码正是libxml2的内部编码,其他格式编码的xml内容要转换为UTF-8后才能通过libxml2库进行处理。 - 将char*强转为xmlChar可使用BAD_CAST宏:
#define BAD_CAST (xmlChar*)
;将xmlChar转char*时直接转。 - 在libxml2中,很多函数会返回一个动态分配内存的xmlChar*变量,调用这类函数时记得要手动释放内存。
xmlNode的常用成员
- name: 节点名字
- doc: 所属文档
- properties: 节点属性列表
- content: 结点文字内容
常用函数
- 字符串操作:xmlStrcmp, xmlMalloc, xmlFree
- 文档操作:xmlReadFile, xmlParseFile, xmlSaveFile, xmlSaveFormatFileEnc, xmlFreeDoc, xmlNewDoc
- 根节点操作:xmlDocGetRootElement, xmlDocSetRootElement
- 内存操作:xmlDocDumpFormatMemoryEnc, xmlParseMemory, xmlReadMemory
- 属性操作:xmlHasProp, xmlGetProp, xmlNewProp, xmlSetProp
- 结点操作:xmlAddChild, xmlNewNode, xmlNodeGetContent, xmlNewChild, xmlNodeSetContent
下面是根据某个项目的实际情况,对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中必须转义的字符:
- 与符号&用
&
表示 - 小于号<用
<
表示 - 大于号>用
>
表示 - 双引号"用
"
表示 - 单引号'用
'
表示