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);