翻译下Mini-XML官方提供的帮助文档1

翻译下Mini-XML官方提供的帮助文档。链接:Getting Started with Mini-XML

来源:http://www.fuzhijie.me/?p=283

这章讲述如果使用Mini-XML操作XML文件。Mini-XML提供了如下功能:
1、在内存中创建和操作XML文档的函数
2、读取UTF-8/UTF-16编码的XML文件或字符串
3、输出UTF-8编码的XML文件或字符串
4、在内存足够的前提下,支持任意的元素名称、属性和属性值
5、支持叶子节点中的整型、实数、cdata和文本类型
6、”Find”、”index”、”walk”等函数用于便捷地存取XML文档中的数据

The Bascis

使用Mini-XML,只需要包含一个头文件:

?
1
#include <mxml.h>

当使用”-lmxml”选项时,Mini-XML库将被你的程序包含。(注:编译使用mxml 2.6的程序居然要链接pthread库,不知为何)

?
1
gcc -o myprogram myprogram.c -lmxml ENTER

如果你安装了pkg-config软件,你可以使用它来决定适合的编译和链接选项。

?
1
2
pkg-config --cflags mxml ENTER
pkg-config --libs mxml ENTER

Nodes

XML文件的每块信息(元素、文本、数字)都以内存中的”Nodes”表示。Nodes被定义为mxml_node_t结构体。mxml_node_t结构体中的type成员定义了节点了类型(元素、整型、opaque、实数或者文本),它决定了你想获取的数据。

每个节点都有一个user_data成员,它用于将程序指定的数据同节点关联起来。

使用mxmlNewElement, mxmlNewInteger, mxmlNewOpaque, mxmlNewReal, mxmlNewText mxmlNewTextf mxmlNewXML函数可以创建新的节点。只有元素有子节点,顶级的node必须是一个元素,它通常是mxmlNewXML()创建的<?xml version=”1.0″?>。

每个节点有很多指针指向父节点、孩子节点、左右兄弟节点。如果你有一个如下的XML文件:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
<? xml version = "1.0" ?>
     < 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,这是DOM方式;Mini-XML也支持SAX方式):

?
01
02
03
04
05
06
07
08
09
10
11
?xml
    |
  data
    |
  node - node - node - group - node - node
    |      |      |      |       |      |
  val1   val2   val3     |     val7   val8
                         |
                       node - node - node
                         |      |      |
                       val4   val5   val6

“-”表示下一个节点,”|”指向第一个孩子节点。

一旦XML数据使用完毕,使用mxmlDelete函数递归地释放一个节点或者整棵树的内存。

?
1
mxmlDelete(tree);

创建XML文档

通过大量的mxmlNew函数可以创建和更新内存中的XML文档。下面的代码创建了一个上面例子所使用XML文档。(注:使用者不需要自己申请内存)

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
mxml_node_t *xml;    /* <?xml ... ?> */
mxml_node_t *data;   /* <data> */
mxml_node_t *node;   /* <node> */
mxml_node_t *group;  /* <group> */
 
xml = mxmlNewXML( "1.0" );
 
data = mxmlNewElement(xml, "data" );
 
     node = mxmlNewElement(data, "node" );
     mxmlNewText(node, 0, "val1" );
     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, 0, "val7" );
     node = mxmlNewElement(data, "node" );
     mxmlNewText(node, 0, "val8" );

我们通过mxmlNewXML创建所有XML文件都需要的<?xml version=”1.0″?>节点。

?
1
xml = mxmlNewXML( "1.0" );

接着使用mxmlNewElement函数创建节点。第一个参数指定父节点,第二个参数指定元素名字。

?
1
data = mxmlNewElement(xml, "data" );

文件中的每个<node>…</node>是用mxmlNewElement和mxmlNewText函数创建的。mxmlNewText第一个参数指明了父节点。第二个节点指明文本之前是否需要空格(本例中是0或者false)。最后一个参数指明实际要添加的文本。

?
1
2
node = mxmlNewElement(data, "node" );
mxmlNewText(node, 0, "val1" );

最后的XML文档可以被保存或者处理,就象从硬盘和字符串加载而来的一样。

加载XML

你可以使用mxmlLoadFile函数加载一个XML文件。

?
1
2
3
4
5
6
7
FILE *fp;
mxml_node_t *tree;
 
fp = fopen ( "filename.xml" , "r" );
tree = mxmlLoadFile(NULL, fp,
                     MXML_TEXT_CALLBACK);
fclose (fp);

第一个参数指定了一个存在的XML父节点(如果存在的话)。除非你想将许多XML数据连接起来,一般情况这个参数传递一个NULL。如果node不为空,XML文件必须包含一个拥有?xml元素的完整XML文档。

第二个参数指明使用fopen和popen打开文件后得到的文件句柄。XML过滤程序可以使用标准输入。

第三个参数指明了回调函数。这个回调函数返回孩子数值类型:MXML_CUSTOM, MXML_IGNORE, MXML_INTEGER, MXML_OPAQUE, MXML_REAL, or MXML_TEXT。加载的回调函数在Chapter 3中有详细介绍。示例代码中使用MXML_TEXT_CALLBACK常量指明了所有的数据节点包含的以空格分隔的文本值。另外一些标准的回调函数包括MXML_IGNORE_CALLBACK, MXML_INTEGER_CALLBACK, MXML_OPAQUE_CALLBACK, 和MXML_REAL_CALLBACK。(注:Mini-XML生成的xml没有格式,所有的数据都放在一行,可以在保存的时候调用一个回调函数,生成格式美观的xml文件。)

mxmlLoadString函数从一个字符串中加载XML节点。

?
1
2
3
4
5
6
char buffer[8192];
     mxml_node_t *tree;
 
     ...
     tree = mxmlLoadString(NULL, buffer,
                           MXML_TEXT_CALLBACK);

第一个和第三个参数同mxmlLoadFile是一样的。第二个参数指明了XML来源字符串和字符缓存。如果父节点为空的话,它们必须包含?xml元素。

保存XML

使用mxmlSaveFile保存XML文件。

?
1
2
3
4
5
6
FILE *fp;
mxml_node_t *tree;
 
fp = fopen ( "filename.xml" , "w" );
mxmlSaveFile(tree, fp, MXML_NO_CALLBACK);
fclose (fp);

第一个参数是要保存的XML节点。它一般是一个指向XML文档的顶层?xml节点的指针。

第二个参数是用fopen或popen打开文件后得到的文件句柄。XML过滤程序可以使用标准输出。

第三个参数是保存文件时的空格回调函数。空格回调函数在Chapter 3已经介绍过了。前面的例子使用MXML_NO_CALLBACK常量指明了没有特殊的空格需要处理。

mxmlSaveAllocString和mxmlSaveString 函数把XML节点保存为字符串:

?
01
02
03
04
05
06
07
08
09
10
char buffer[8192];
char *ptr;
mxml_node_t *tree;
 
...
mxmlSaveString(tree, buffer, sizeof (buffer),
                MXML_NO_CALLBACK);
 
...
ptr = mxmlSaveAllocString(tree, MXML_NO_CALLBACK);

第一个和最后一个参数同mxmlSaveFile是一样的。mxmlSaveString需要一个固定大小的字符串缓冲来保存XML文档,需要指明该缓冲的大小。mxmlSaveAllocString()则使用malloc()自行申请字符串缓冲。

控制行包装

当保存XML文档时,Mini-XML通常将输出的列设置为75,这样文本在终端中比较适合查看。mxmlSetWrapMargin函数可以覆盖默认的边距。

查找和遍历节点

mxmlWalkPrev和mxmlWalkNext函数用于迭代XML节点数。

?
1
2
3
4
5
6
7
mxml_node_t *node;
 
node = mxmlWalkPrev(current, tree,
                     MXML_DESCEND);
 
node = mxmlWalkNext(current, tree,
                     MXML_DESCEND);

另外,通过mxmlFindElement可以通过名字查找元素或者节点。

?
1
2
3
4
5
mxml_node_t *node;
 
node = mxmlFindElement(tree, tree, "name" ,
                        "attr" , "value" ,
                        MXML_DESCEND);

名字,属性和值可以传递NULL指针,这样将从匹配所有类型(如果”name”、”attr”为空时,通过”value”似乎搜不到节点)。

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Find the first "a" element */
node = mxmlFindElement(tree, tree, "a" ,
                        NULL, NULL,
                        MXML_DESCEND);
/* Find the first "a" element with "href"
    attribute */
node = mxmlFindElement(tree, tree, "a" ,
                        "href" , NULL,
                        MXML_DESCEND);
/* Find the first "a" element with "href"
    to a URL */
node = mxmlFindElement(tree, tree, "a" ,
                        "href" ,
                        "http://www.easysw.com/" ,
                        MXML_DESCEND);
/* Find the first element with a "src"
    attribute */
node = mxmlFindElement(tree, tree, NULL,
                        "src" , NULL,
                        MXML_DESCEND);
/* Find the first element with a "src"
    = "foo.jpg" */
node = mxmlFindElement(tree, tree, NULL,
                        "src" , "foo.jpg" ,
                        MXML_DESCEND);

可以使用mxmlFindElement函数进行循环访问:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
mxml_node_t *node;
 
for (node = mxmlFindElement(tree, tree,
                             "name" ,
                             NULL, NULL,
                             MXML_DESCEND);
      node != NULL;
      node = mxmlFindElement(node, tree,
                             "name" ,
                             NULL, NULL,
                             MXML_DESCEND))
{
   ... do something ...
}

MXML_DESCEND参数出现的这个位置事实上还可以是以下三种:

1、MXML_NO_DESCEND表示不要查找任何孩子节点,仅仅在同层的兄弟节点和父节点中查找,直到文档顶层。

The previous node from “group” would be the “node” element to the left, while the next node from “group” would be the “node” element to the right. (没大看明白这句话的意思)

2、MXML_DESCEND_FIRST表示仅仅查找到第一层孩子节点。你可能经常使用它来迭代一个父节点的直接孩子。比如”?xml”父节点的所有”group”元素和”node”元素。

这种模式仅仅适用于搜索函数。walk函数把它当成MXML_DESCEND,因为每次调用都是第一次。

3、MXML_DESCEND表示持续查找,直到文档最底部。”group”前一个节点是”val3″,下一个节点是”group”下面的第一个节点元素。

如果你想使用mxmlWalkNext()从”?xml”根节点遍历到树的底层,节点顺序应该是这样的:
?xml data node val1 node val2 node val3 group node val4 node val5 node val6 node val7 node val8

如果你从”val8″开始使用mxmlWalkPrev()遍历树,顺序将是反的,到”?xml”结束。

最后附上一个测试的例子,这段代码要解释一个XML文件。从代码可以看出Mini-XML提取元素值还是比较麻烦的,文本被当作是孩子节点,然后空格分隔的每个word都会成为节点,这些节点可以通过next遍历。XML文件格式如下:

?
1
2
3
4
5
6
7
8
<? xml version = "1.0" encoding = "UTF-8" ?>
< config version = "1.0" >
     < globals name = "globals"
         root = "/home/admin/search/var"
         >
     What is this?
     </ globals >
</ config >

解释程序如下:

?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
 
#include <mxml.h>
 
int main()
{
     FILE *fp;
     mxml_node_t *tree;
 
     mxml_node_t *m_pXMLTree, *pXMLNode;
 
     const char * szAttr;
 
     fp = fopen ( "se.conf" , "r" );
     m_pXMLTree = mxmlLoadFile(NULL, fp,
             MXML_TEXT_CALLBACK);
     fclose (fp);
 
     //查找globals元素
     pXMLNode = mxmlFindElement(m_pXMLTree, m_pXMLTree, "globals" , NULL, NULL, MXML_DESCEND);
 
     //把globals元素的值打印出来
     mxml_node_t* pNode = pXMLNode->child;
 
     do
     {
         printf ( "%s\n" , pNode->value.text.string);
 
         pNode = pNode->next;
     } while (pNode != NULL);
 
     //查找root属性
     szAttr = mxmlElementGetAttr(pXMLNode, "root" );
 
     printf ( "root: %s\n" , szAttr);
 
     return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值