Linux C操作XML文件
1 简介
介绍使用C语言操作xml文件。
使用的开源库:mxml
mxml源码路径:michaelrsweet/mxml: Tiny XML library. (github.com)
mxml官网:Mini-XML (msweet.org)
mxml官方API使用文档:Mini-XML 3.2 API Reference (msweet.org)
2 安装
提前说明:mxml编译之后会生成一个静态库和动态链接库。
首先下载源码压缩包:michaelrsweet/mxml: Tiny XML library. (github.com)
然后解压之后,按照官方网站的说明进行执行。
- 配置编译环境
./configure
配置之后,会检查编译环境和配置编译生成的库存放路径,默认放在usr/local中。
如何需要指定库存放路径,可使用如下命令修改:
./configure --prefix=/foo
2)编译
直接运行:
make
编译完成之后会生成:libmxml.so.1.6、libmxml.a、testmxml(测试代码)。
3)将mxml安装到系统库中
执行:
make install
安装之后,使用时包含mxml.h即可。
#include <mxml.h>
在编译程序的使用,可使用 -lmxml 来链接mxml库。
3 测试
使用源文件自带的测试案例进行测试。
编译testmxml.c:
gcc testmxml.c -lmxml -o testxml
运行:
./testxml test.xml
如果运行出现以下错误,表示没找到libmxml.so.1库。
原因:我使用的gcc编译默认使用的是64位的库,也就是/usr/lib64,但是这个库中没有libmxml.so.1
编译的libmxml.so也是一个64位的库:
$ file /usr/local/lib/libmxml.so.1.6
/usr/local/lib/libmxml.so.1.6: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=4e488abf69cf58184b46a03b881e67a5a92c155f, not stripped
解决方式:建立一个软连接,将安装库的路径链接到系统库中。
sudo ln -s /usr/local/lib/libmxml.so.1 /usr/lib64/libmxml.so.1
然后重新执行即可。
4 部分函数介绍
首先先介绍一些基本信息。
4.1 节点
XML文件中的信息都存放在节点中,节点使用mxml_node_t数据结构进行定义,每个节点有个type成员(定义了节点的类型)、可选数据、父节点(parent 上)、子节点(child 下)、兄弟节点(prev 左和next右)。
struct _mxml_node_s /**** An XML node. ****/
{
mxml_type_t type; /* Node type */
struct _mxml_node_s *next; /* Next node under same parent */
struct _mxml_node_s *prev; /* Previous node under same parent */
struct _mxml_node_s *parent; /* Parent node */
struct _mxml_node_s *child; /* First child node */
struct _mxml_node_s *last_child; /* Last child node */
_mxml_value_t value; /* Node value */
int ref_count; /* Use count */
void *user_data; /* User data */
};
举例说明,有个xml文件格式如下:
<?xml version="1.0" encoding="utf-8"?>
<data>
<node>val1</node>
<node>val2</node>
<node>val3</node>
<group>
<node>val4</node>
<node>val5</node>
<node>val6</node>
</group>
<node>val7</node>
<node>val8</node>
</data>
则其在内存中的节点树关系如下:
?xml version="1.0" encoding="utf-8"?
|
data
|
node - node - node - group - node - node
| | | | | |
val1 val2 val3 | val7 val8
|
node - node - node
| | |
val4 val5 val6
”-“:表示兄弟节点;"|":指向第一个子节点。
4.1.1 节点类型
节点类型数据结构定义如下:
typedef enum mxml_type_e /**** The XML node type. ****/
{
MXML_IGNORE = -1, /* Ignore/throw away node @since Mini-XML 2.3@ */
MXML_ELEMENT, /* XML element with attributes 节点带属性 */
MXML_INTEGER, /* Integer value 整型值 */
MXML_OPAQUE, /* Opaque string 不透明字符串,不进行字符串分割 */
MXML_REAL, /* Real value 实数 */
MXML_TEXT, /* Text fragment 文本片段 */
MXML_CUSTOM /* Custom data @since Mini-XML 2.1@ */
} mxml_type_t;
相关函数:获取节点类型。
mxml_type_t mxmlGetType(mxml_node_t *node);
4.1.2 相关函数
获取第一个子节点:
mxml_node_t *mxmlGetFirstChild(mxml_node_t *node);
获取最后一个子节点:
mxml_node_t *mxmlGetLastChild(mxml_node_t *node);
获取兄弟节点(next右):
mxml_node_t *mxmlGetNextSibling(mxml_node_t *node);
获取兄弟节点(prev 左):
mxml_node_t *mxmlGetPrevSibling(mxml_node_t *node);
获取父节点:
mxml_node_t *mxmlGetParent(mxml_node_t *node);
4.2 创建xml文件并保存
通过实例简述一下如何创建一个XML文件,并保存它。
void creat_xml(void)
{
mxml_node_t *xml; /* <?xml ... ?> */
mxml_node_t *data; /* <data> */
mxml_node_t *node; /* <node> */
mxml_node_t *group; /* <group> */
xml = mxmlNewXML("1.0"); //xml头部
data = mxmlNewElement(xml, "data"); //创建节点<data>,父节点为xml
node = mxmlNewElement(data, "node"); //创建节点<note>,父节点为data
mxmlNewText(node, 0, "val1"); //设置节点<note>的值
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val2");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 0, "val3");
group = mxmlNewElement(data, "group");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val4");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val5");
node = mxmlNewElement(group, "node");
mxmlNewText(node, 0, "val6");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 1, "val7");
node = mxmlNewElement(data, "node");
mxmlNewText(node, 1, "val8");
//save xml
FILE *fp;
fp = fopen("filename.xml", "w");
mxmlSaveFile(xml, stdout, MXML_NO_CALLBACK);
fclose(fp);
}
对涉及的函数进行简单介绍:
/*
* brife: 新建一个新的XML文档
* para[in] version: Version number to use
* return: 新XML文档父节点
*/
mxml_node_t *mxmlNewXML(const char *version);
/*
* brife: 创建一个新的节点
* para[in] parent: 父节点
* para[in] name: 创建节点名
* return: 新节点
*/
mxml_node_t *mxmlNewElement(mxml_node_t *parent, const char *name);
/*
* brife: 创建一个新的节点文本内容
* para[in] parent: 父节点
* para[in] whitespace: 1 = leading whitespace, 0 = no whitespace
* para[in] string: 文本内容
* return: 新节点
*/
mxml_node_t *mxmlNewText(mxml_node_t *parent, int whitespace, const char *string);
/*
* brife: 保存一个xml树到文件中
* para[in] note: xml树节点
* para[in] fp: 写入的文件流指针
* para[in] cb: 空白回调函数,控制保存文件时插入的"空白"字符
* return: 成功返回0,出错返回-1
*/
int mxmlSaveFile(mxml_node_t *node, FILE *fp, mxml_save_cb_t cb);