免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4757 | 回复: 0
打印 上一主题 下一主题

libxml tutorial中文版, [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2006-06-16 16:16 |只看该作者 |倒序浏览
纯文本格式比较难看,各位可以下载附件,里面有DOC格式的文档。内容相同。
===============================================

译前言
翻译本文缘起我们有一个项目使用了libxml,却出现内存泄漏的情况。于是我想了解一点libxml的知识,却苦于没有入门的中文材料。偶尔发现网上有人翻译了这个教程,却不是很合自己用,便想自己翻译一下。
只是自己中英文皆不精,XML也不熟,中间有错误自己都看不出来。所以本文仅供初接触libxml的,又懒得看原文的人士看一下,别的用处想必不大。
英文版本见http://www.xmlsoft.org/tutorial/index.html,本文仅仅是对英文版的简单翻译。若有疑问,请直接查看英文原处。

2006-06-16                               

Libxml 简单教程
John Fleck
Copyright © 2002, 2003 John Fleck
目录
介绍
数据类型
解析文件
获取元素内容
用XPath获取元素内容
写入元素内容
写入属性
获取属性
编码转换
A. 编译
B. 例子文档
C. Keyword例子代码
D. Xpath例子代码
E. 添加Keyword的例子代码
F. 添加属性的例子代码
G. 获取属性值的例子代码
H. 编码转换的例子代码
I. 感谢
摘要
Libxml是一个自由授权的,用来处理XML的C语言库,它可以移植到很多的平台上。本教程为其基本函数提供了例子。
介绍
Libxml是一个C语言库,用来对XML数据进行读取、创建和维护。这个教程对其基本功能提供了例子代码和说明。
在libxml的项目主页http://www.xmlsoft.org/上提供了关于它如何使用的更加详尽的信息,包括完整的API文档http://xmlsoft.org/html/libxml-lib.html。本教程不能替代这些文档,而仅仅用来说明用这个库来实现XML基本操作时所用到的函数。
本教程中用例子代码来演示下列内容:
•        解析文档;
•        取出指定元素里的文本;
•        添加元素以及它的内容;
•        添加属性;
•        取出属性的值。
全部例子代码见附录。
数据类型
Libxml声明了一些数据类型,用来隐藏那些除非有特别需要就不用去理会的复杂细节,这些数据类型我们总是会一次一次的遇到。
xmlChar
对char的基本代替,是一个UTF-8编码字符串中的一个字节。如果你的数据使用了其他编码,在使用libxml函数前就必须转换为UTF-8。关于编码的更多信息见http://www.xmlsoft.org/encoding.html
xmlDoc 和 xmlDocPtr
是一个包含了从解析文档后创建出的树的结构。xmlDocPtr是指向该结构的指针。
xmlNode 和 xmlNodePtr
包含单个节点的结构。xmlNodePtr是指向该结构的指针,它用来遍历文档树。
解析文件
解析文件只需要文件的名字和简单的一个函数调用,再加上错误检查就可以了。完整代码见 附录C Keyword例子代码
        ① xmlDocPtr doc;
        ② xmlNodePtr cur;

        ③ doc = xmlParseFile(docname);
       
        ④ if (doc == NULL ) {
                fprintf(stderr,"Document not parsed successfully. \n");
                return;
        }

        ⑤ cur = xmlDocGetRootElement(doc);
       
        ⑥ if (cur == NULL) {
                fprintf(stderr,"empty document\n");
                xmlFreeDoc(doc);
                return;
        }
       
        ⑦ if (xmlStrcmp(cur->name, (const xmlChar *) "story")) {
                fprintf(stderr,"document of the wrong type, root node != story");
                xmlFreeDoc(doc);
                return;
        }

① 声明指向你要解析的文档的指针。
② 声明一个节点指针(处理单个的节点的时候需要它)。
④ 检查解析文档是否成功。如果没有,libxml会在此处报错并终止。
    → 注意
       此处常见的错误是对编码的错误处理。XML标准要求,如果一个文档不是用UTF-8或UTF-16编码的,文档内必须包含有编码的明确声明。如果文档声明了编码,libxml会自动的为你做必要的到UTF-8的编码转换。关于XML编码要求的更多详情见http://www.w3.org/TR/REC-xml#charencoding
⑤ 获取文档的根元素。
⑥ 检查确认文档包含了东西。
⑦ 在我们的例子里,我们需要确认文档内容正确,”story”是在本教程中使用到的文档的根类型。

获取元素内容
获取一个元素的内容需要遍历文档树直到发现你要找的东西。下面的例子,我们要找一个叫”keyword”的元素,它保存在一个叫”storyinfo”的元素里面。寻找这个节点的过程就需要遍历这棵树,这比较令人郁闷。我们假设你已经有了一个叫doc的xmlDocPtr和叫cur的xmlNodPtr变量。
        ① cur = cur->xmlChildrenNode;
        ② while (cur != NULL) {
                if ((!xmlStrcmp(cur->name, (const xmlChar *)"storyinfo"))){
                        parseStory (doc, cur);
                }
                 
        cur = cur->next;
        }
      
① 获得cur的第一个子节点。此时,cur指向文档的根,也就是”story”元素。
② 这个循环遍历”story的所有子元素,寻找叫”storyinfo”的元素,也就是那个我们要寻找的包含”keyword”的那个元素。这里使用了libxml的字符串比较函数--xmlStrcmp。如果有匹配的,就调用函数parseStory。

void
parseStory (xmlDocPtr doc, xmlNodePtr cur) {

        xmlChar *key;
        ① cur = cur->xmlChildrenNode;
        ② while (cur != NULL) {
            if ((!xmlStrcmp(cur->name, (const xmlChar *)"keyword"))) {
        ③            key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
                    printf("keyword: %s\n", key);
                    xmlFree(key);
            }
        cur = cur->next;
        }
    return;
}

① 又是获得了第一个子节点。
② 就像上个循环,我们遍历节点,寻找感兴趣的那个。在这个例子里是”keyword”。
③ 我们发现”keyword”元素之后,就打印出来。要记住,在XML中,一个元素包含的文本是这个元素的一个子节点,所以我们转向cur->xmlChildrenNode。要获取它,我们使用函数xmlNodeListGetString,它也要把doc指针作为一个参数。在这儿,我们仅仅把它打印出来。
    → 注意
        因为xmlNodeListGetString为它返回的字符串分配了动态内存,你必须用xmlFree来释放它。
      
使用Xpath来获取元素内容
除了用遍历文档树的方式来寻找一个元素外,libxml2还支持使用XPath表达式来获取满足指定条件的节点集合。关于XPath API 的完整文件见http://xmlsoft.org/html/libxml-xpath.html
XPath允许在一个文档中寻找到符合条件的所有节点。下面的例子中,我们在文档中寻找到所有的”keyword”元素。
    → 注意
       对XPath 的完整讨论超出了本文的范畴,关于它使用的详情参见http://www.w3.org/TR/xpath
本例子的完整代码在 附录D XPath例子程序。
使用XPath就要先设置一个xmlXPathContext,然后把这个XPath表达式和上下文提交给xmlXPathEvalExpression函数。函数返回xmlXPathObjectPtr,它包含着符合XPath表达式的节点集合。
        xmlXPathObjectPtr
        getnodeset (xmlDocPtr doc, xmlChar *xpath){
       
        ① xmlXPathContextPtr context;
        xmlXPathObjectPtr result;

        ② context = xmlXPathNewContext(doc);
        ③ result = xmlXPathEvalExpression(xpath, context);
        ④ if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
                xmlXPathFreeObject(result);
                printf("No result\n");
                return NULL;
      }
① 首先我们声明变量。
② 初始化context变量。
③ 应用XPath表达式。
④ 检查结果,如果没有结果,释放分配给结果的动态内存。
函数返回的xmlPathObjectPtr包含着节点集合以及用来遍历集合和操作结果的所需要的其它信息。在本例中,我们的函数返回了xmlXPathObjectPtr。我们用它来打印我们文档中keyword节点的内容。节点集合对象包含了集合中元素的个数(nodeNr)和一个节点的数组(nodeTab)。
        ① for (i=0; i < nodeset->nodeNr; i++) {
        ② keyword = xmlNodeListGetString(doc, nodeset->nodeTab->xmlChildrenNode, 1);
                printf("keyword: %s\n", keyword);
                xmlFree(keyword);
        }
      
① nodeset->Nr保存着节点集合中元素的个数。这里我们用来遍历数组。
② 在这儿我们打印每个返回的节点的内容。
    → 注意
        注意我们打印的是返回的节点的子节点,因为”keyword”元素的内容是个子文本节点。
写入元素内容
写入元素内容的步骤和上面我们所用到的差不多—都是解析文档然后遍历树。我们解析文档,然后遍历树寻找我们想要插入元素的地方。在下面的例子里,我们还是寻找”storyinfo”元素,但是我们这次插入一个keyword。然后我们把文件写回磁盘。完整代码见 附录 E 增加keyword例子代码。
本例子中最主要的差别在parseStory函数中:
void
parseStory (xmlDocPtr doc, xmlNodePtr cur, char *keyword) {

        ① xmlNewTextChild (cur, NULL, "keyword", keyword);
    return;
}
      
① xmlNewTextChil函数在由cur指定的当前节点指针的位置添加了一个新子元素。
一旦这个节点添加成功,我们就可以把文档写回文件。如果你想让该元素有一个namespace,也是在这儿添加。在本例中,namespace是NULL。
        xmlSaveFormatFile (docname, doc, 1);
      
第一个参数是要写入的文件名。你会注意到它和我们刚刚读的文件名相同。在本例中,我们把老文件给覆盖写了。第二个参数指向xmlDoc结构。第三个参数设为1保证输出会缩格。
写入属性
写入属性和向一个新元素中写入文本及其类似。在本例中,我们向我们文档中增加一个reference URI。文件代码见 附录F 增加属性例子代码。
reference是story元素的子节点。所以找到该位置来添加我们的新元素和属性非常的简单。在parseDoc中一进行完错误检查,就正是添加我们的元素的地方。但在去这样做之前,我们需要声明一个我们还没有见过的数据类型的变量。
        xmlAttrPtr newattr;
      
我们还需要另外一个xmlNodePtr:
        xmlNodePtr newnode;
      
parseDoc函数在检查根元素是否是story之前的部分和原来完全相同。如果是story,我们就知道这就是添加我们的元素的地方。
        ① newnode = xmlNewTextChild (cur, NULL, "reference", NULL);
        ② newattr = xmlNewProp (newnode, "uri", uri);       
     
① 首先,我们当前节点指针cur所指的位置上添加一个新节点。使用xmlNewTextChild函数。
添加完节点后,和前面增加一个文本内容的元素的例子一样,把文件写回磁盘。
获取属性
获取一个属性的值和我们前面获取一个节点的文本内容的例子非常的类似。在本例中,我们会获取在上节中添加的URI的值。完整代码见:附录G 获取属性值例子代码
本例的基本步骤和前面的非常的类似:解析文档,寻找你感兴趣的元素,调用相应函数来完成所要求的任务。在本例中,我们调用getReference:
void
getReference (xmlDocPtr doc, xmlNodePtr cur) {

        xmlChar *uri;
        cur = cur->xmlChildrenNode;
        while (cur != NULL) {
            if ((!xmlStrcmp(cur->name, (const xmlChar *)"reference"))) {
                   ① uri = xmlGetProp(cur, "uri");
                    printf("uri: %s\n", uri);
                    xmlFree(uri);
            }
            cur = cur->next;
        }
        return;
}
      
① 关键函数xmlGetProp,它返回一个保存着属性值的xmlChar,在本例中,我们仅仅把它打印出来。
    → 注意
        如果你用DTD为该属性声明了一个固定或缺省的属性,这个函数会获取到该值。
编码转换
数据编码兼容问题是开发者在初次使用XML和libxml的时候最常遇到的问题。在你设计应用的时候就要把这个问题想清楚,免得将来更加麻烦。libxml在内部是用UTF-8格式来储存和维护数据的。你程序中用到的其他格式数据,例如常用的ISO-8859-1编码,必须在传给libxml函数之前转换为UTF-8。如果你想你的程序的输出不是UTF-8的编码,同样也需要转换。
如果有iconv,libxml就可以用它来转换数据。如果没有iconv,数据的外部格式只能使用UTF-8、UTF-16以及ISO-8859-1。但有了iconv,只要能够用iconv和UTF-8来回转换的编码格式就都可以使用了。现在iconv可以支持大约150种可以来回转换的字符格式。虽然每个iconv实现实际支持格式数量不同,但几乎每个实现都能保证能够支持我们平常所遇到的格式。
△! 警告
一个常见的错误是在某个代码的不同部分内部数据使用了不同的格式。常见的例子是:一个应用采用ISO-8859-1作为内部数据格式,来和libxml联编;libxml却是用UTF-8作为内部数据格式的。结果就是一个应用内,执行的不同代码段把内部数据视为不同的格式。自然的,其中总会有几个代码段会把数据解释错。
本例中,构造了一个简单文档,然后用正确的编码把命令行输入的内容添加到文档的根元素,然后把结果输出到标准输出。本例中,我们使用ISO-8859-1编码,命令行输入的字符串的编码从ISO-8859-1到UTF-8。完整编码见 附录 H 编码转换例子代码
转换器,封装成了例子代码中的转换函数,使用了libxml的xmlFindCharEncodingHandler函数来获取。
        ① xmlCharEncodingHandlerPtr handler;
        ② size = (int)strlen(in)+1;
        out_size = size*2-1;
        out = malloc((size_t)out_size);


        ③ handler = xmlFindCharEncodingHandler(encoding);

        ④ handler->input(out, &out_size, in, &temp);
…       
        ⑤ xmlSaveFormatFileEnc("-", doc, encoding, 1);
      
①        声明一个处理器指针,指向xmlCharEncodingHandler函数。
② xmlCharEncodingHandler函数需要知道输入和输出的字符串的长度,于是这儿计算了输入和输出的字符串的长度。
③ xmlFindCharEncodingHandler把数据的原始编码作为参数,在libxml内置的转换处理器中查找。返回一个函数的指针,没有找到就返回NULL。
④ 处理器所标示的转换函数需要输入和输出的字符串的指针以及它们的长度作为参数。两个长度都必须由应用来确定。
⑤ 用不是UTF-8的编码来输出,我们需要使用xmlSaveFormatFileEnc,并要指定编码。
A. 编译
Libxml包含了一个脚本,xml2-conf,用来产生基于该库编写的程序的编译和连接标志。对预处理器和编译器标志,使用xml2-config –cflags。对库连接标志,使用xml2-config –libs。其他选项使用xml2-config –help查看。
(此处略掉例子程序,见http://www.xmlsoft.org/tutorial/apb.html
I. 感谢
很多朋友为本教程慷慨的提供了反馈、代码以及改进建议。他们是(名字不分先后):Daniel Veillard, Marcus Labib Iskander, Christopher R. Harris, Igor Zlatkovic, Niraj Tolia, David Turover

Libxml 简单教程.rar

25.02 KB, 下载次数: 791

Libxml简单教程

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP