Mini-XML是一个用C语言开发的开源XML解析器,其最大的好处是文件体积很小巧,网站是http://www.minixml.org/index.php
在Linux下体验了一下,说说过程:先下载2.7版本的压缩包,当时是把文件解压到/usr/local/src/mxml 目录下。按照网页 http://www.minixml.org/mxml.html 上介绍的方法编译,网页上说 ./configure 时如果不用 --prefix= 指定安装目录,默认的安装目录是 /usr/local 。
1) 安装
实验了一下,安装以后 /usr/local 目录下没有出现新文件,倒是 /usr/local/lib 新增了四个文件:
libmxml.a(大小为184.8KB),libmxml.so(大小为113.5KB),libmxml.so.1 (大小为113.5KB),libmxml.so.1.5 (大小为113.5KB)。其实在 /usr/local/src/mxml 下也有同样的这四个文件。
在 /usr/local/include 目录下新增了mxml.h(大小为118.KB)。
2)执行测试程序
想在 /usr/local/src/mxml 目录下运行自带的测试程序 testmxml.c,按照官网上说明的方法执行 gcc -o testmxml testmxml.c -lmxml 会报错,说是需要pthread库,用到该库的目的可能是为了支持多线程吧。
执行命令 gcc -o testmxml testmxml.c -lmxml -lpthread 可以产生testmxml可执行文件。
但是运行命令 ./testmxml 时会提示:error while loading shared libraries: libmxml.so.1: cannot open shared object file: No such file or directory
这说明需要设置动态库路径,一开始没有发现 libmxml.so.1 是在 /usr/local/lib 下,在 /usr/local/src/mxml 目录下看见有这个文件,就使用命令
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/src/mxml
后来想想,如果执行命令
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
也是可以的。但是使用export命令设置动态库路径只在当前会话中有效,要想长期有效需要修改.bashrc文件或修改/etc/profile文件,这方面的细节在网上可以找到,这里就不说了。
设置了动态库路径,然后运行 ./testmxml 就可以正确执行了,由于自带了一个test.xml文件用于测试,可以执行命令
./testmxml test.xml
可以正确执行并有结果显示。
3) mxmlSaveFile( )函数
该函数的定义是:
int mxmlSaveFile(
mxml_node_t *node,
FILE *fp,
mxml_save_cb_t cb
);
其中cb可以是用户自定义的空白回调(Whitespace callback)函数或MXML_NO_CALLBACK,如果使用MXML_NO_CALLBACK,保存的xml文件中所有的内容都是放在一行里,没有换行。
如果用户希望保存的xml文件在格式上更好看,需要自己开发Whitespace callback函数,在自带的testxml.c测试程序中有一个whitespace_cb( )函数,可以作为示例参考。
4) mxmlFindElement( )函数
该函数的定义是:
mxml_node_t *mxmlFindElement(
mxml_node_t *node,
mxml_node_t *top,
const char *name,
const char *attr,
const char *value,
int descend
);
参数的定义是:
node: Current node
top: Top node
name: Element name or NULL for any
attr: Attribute name, or NULL for none
value: Attribute vale, or NULL for any
descend: Descend into tree - MXML_DESCEND, MXML_NO_DESCEND, or MXML_DESCEND_FIRST
要注意descend参数的用法:
1、MXML_NO_DESCEND表示不要查找任何孩子节点,仅仅在同层的兄弟节点和父节点中查找,直到文档顶层。
2、MXML_DESCEND_FIRST表示仅仅查找到第一层孩子节点。
3、MXML_DESCEND表示持续查找,直到文档最底部。
在网上看到一个Mini-XML的示例程序,但运行起来发现有问题。示例程序相关的xml文件内容如下:
<?xml version="1.0">
<note>
<id>5000</id>
<password>FE-D0-18-00</password>
</note>
现在看看示例程序,摘录出其中读取xml文件的部分代码如下:
...
node = mxmlFindElement(tree, tree, "note",
NULL, NULL,
MXML_DESCEND);
id = mxmlFindElement(node, tree, "id",
NULL, NULL,
MXML_NO_DESCEND);
printf("%s\n",id->child->value.text.string);
password = mxmlFindElement(node, tree, "password",
NULL, NULL,
MXML_NO_DESCEND);
printf("%s\n",password->child->value.text.string);
...
结果在运行该示例程序时显示“段错误”,错误的原因就在于mxmlFindElement( )函数的最后一个参数使用有问题。第一次调用mxmlFindElement( )函数以后node指针指向xml文件中的note结点,第二次、第三次调用mxmlFindElement( )函数时都是从note结点开始查找,想找的内容是note的子结点id和password,但是由于参数设置成了MXML_NO_DESCEND,程序不会去查找note结点的子节点,仅在note同层的兄弟节点和父节点中查找,直到文档顶层,所以会报告段错误。
如果把其中的两个MXML_NO_DESCEND都改为MXML_DESCEND,程序就可以正常运行并输出结果了。
补充:
一、链接时用的是哪个目录下的库文件?
尽管在/usr/local/src/mxml目录下存在libmxml.a,libmxml.so,libmxml.so.1,libmxml.so.1.5四个库文件,但GCC在链接时其实没有用到它们,GCC链接时用的是 /usr/local/lib 目录下的文件,可以做一个实验,把/usr/local/src/mxml目录下的四个库文件删除,然后再执行命令:
gcc -o gcc testmxml.c -lmxml -lpthread
照样可以生成testmxml可执行文件,说明/usr/local/src/mxml目录下的四个库文件只不过是起备份作用而已。
gcc在编译时会这样去找库文件:
1. 检查-L参数后面指定的目录;
2. 检查gcc的环境变量LIBRARY_PATH指定的目录;
3. 检查内定目录 /lib, /usr/lib和/usr/local/lib, 所以放在这些目录中的库用 -l 参数就能链接了。
二、链接的是mxml的静态库还是动态库?
GCC默认优先使用动态库,找不到才使用静态库。如果要强制指定使用静态库可以使用 -static 参数。
可以做一个实验:
1. 把/usr/local/lib 目录下的libmxml.so,libmxml.so.1,libmxml.so.1.5三个文件移动到其他gcc找不到的目录下,再执行命令:
gcc -o testmxml testmxml.c -lmxml -lpthread
产生的testmxml文件大小为103.4KB,因为此时GCC链接的是静态库libmxml.a。此时运行命令 ./testmxml 时不会像前面提到的那样提示加载共享库失败,因为根本就不需要加载共享库。
2. 删掉这个103.4KB的testmxml文件,再将libmxml.so,libmxml.so.1,libmxml.so.1.5三个文件移回到把/usr/local/lib 目录下,执行命令:
gcc -o testmxml testmxml.c -lmxml -lpthread
产生的testmxml文件大小为20.8KB,因为此时GCC是按照默认设置链接动态库,所以生成的文件体积要小很多。也因为这样,在运行此时生成的testmxml文件时会提示加载共享库失败,需要按前面讲到的设置LD_LIBRARY_PATH。
LD_LIBRARY_PATH环境变量的作用是:在程序加载运行期间查找动态链接库时,指定除了系统默认路径之外的其他路径。