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)

然后解压之后,按照官方网站的说明进行执行。

  1. 配置编译环境
./configure

配置之后,会检查编译环境和配置编译生成的库存放路径,默认放在usr/local中。

如何需要指定库存放路径,可使用如下命令修改:

./configure --prefix=/foo

image-20210507181722591

2)编译

直接运行:

make

image-20210507181828400

编译完成之后会生成:libmxml.so.1.6、libmxml.a、testmxml(测试代码)。

3)将mxml安装到系统库中

执行:

make install

image-20210507182211455

安装之后,使用时包含mxml.h即可。

#include <mxml.h>

在编译程序的使用,可使用 -lmxml 来链接mxml库。

3 测试

使用源文件自带的测试案例进行测试。

编译testmxml.c:

gcc testmxml.c -lmxml -o testxml	

运行:

./testxml test.xml

如果运行出现以下错误,表示没找到libmxml.so.1库。

image-20210508101409374

原因:我使用的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

然后重新执行即可。

image-20210508101604090

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);
原文地址:https://www.cnblogs.com/mrlayfolk/p/14743985.html