首页 expat xml解析器

expat xml解析器

举报
开通vip

expat xml解析器 Expat Expat 是什么? Expat 是一个用 C 语言开发的、用来解析 XML 文档的开发库,它最初是开源的、 Mozilla 项目下的一个 XML 解析器。 关于作者 这个库的开发者是 James Clark, 还开发了很多我们所熟知的工具包:groff、 Jade、 XP (a Java XML parser package)、 and XT (a Java XSL engine)。 Expat XML Parser 概述 Expat 是一个面向流的...

expat xml解析器
Expat Expat 是什么? Expat 是一个用 C 语言开发的、用来解析 XML 文档的开发库,它最初是开源的、 Mozilla 项目下的一个 XML 解析器。 关于作者 这个库的开发者是 James Clark, 还开发了很多我们所熟知的工具包:groff、 Jade、 XP (a Java XML parser package)、 and XT (a Java XSL engine)。 Expat XML Parser 概述 Expat 是一个面向流的解析器。您注册的解析器回调(或 handler)功能,然后 开始搜索它的文档。当解析器识别该文件的指定的位置,它会调用该部分相应的处理 程序(如果您已经注册的一个)。该文件被输送到解析器,会被分割成多个片断,并 分段装到内存中。因此 expat 可以解析那些巨大的文件。 如何使用它们 Expat XML Parser 支持设置多种不同的处理器。但是要使用它们,你只需要学习 四个功能,即可满足 80%的需要。 它们是: XML_ParserCreate Create a new parser object. XML_SetElementHandler Set handlers for start and end tags. XML_SetCharacterDataHandler Set handler for text. XML_Parse Pass a buffer full of document to the parser 开源的 XML Parser expat 文章分类:C++编程 expat是使用 C所写的 XML 解释器,采用流的方式来解析 XML 文件,并且基于事件 通知 关于发布提成方案的通知关于xx通知关于成立公司筹建组的通知关于红头文件的使用公开通知关于计发全勤奖的通知 型来调用 分析 定性数据统计分析pdf销售业绩分析模板建筑结构震害分析销售进度分析表京东商城竞争战略分析 到的数据,并不需要把所有 XML文件全部加载到内存里,这样可以分析非常大 的 XML文件。由于 expat库是由 XML的主要负责人 James Clark来实现的,因此它是符合 W3C 的 XML 标准 excel标准偏差excel标准偏差函数exl标准差函数国标检验抽样标准表免费下载红头文件格式标准下载 的。 正因为源码全部是纯 C所写,因此,非常容易移植,尤其是适用于嵌入式平台,我在往 联芯的手机平台上移植时,几乎没改任何东西。 不过,优点也带来了缺点,因为是采用流的方式解析 XML,所以不会像 TinyXML那样在 一块内存中生成基于 DOM的树。 虽然这样解析起来略显麻烦,但是基于回调的机制,在我 看来还是蛮方便的。下面就说使用方法: 首先是用 XML_ParserCreate(const XML_Char *encodingName),参数一般为 NULL,函 数返回一个 XML_Parser类型指针,我们就当他是一个句柄吧,类似于 Windows里的内核对 象,一般需要保存在一个全局的指针里。 然后调用 XML_SetElementHandler(XML_Parser parser, XML_StartElementHandler start, XML_EndElementHandler end) 第一个参数是那个 Parser句柄,第二个和第三个参数则是整个 Parser的核心,类型 为 CallBack的函数,不了解 CallBack函数的,我在这里简单说下,函数调用一般分 为两种,一种是主调,即编写代码者自己调用的函数,还一种称为 Callback函数,编 码者写好,但他自己却不主动调用,而是在某些条件下(编码者并不清楚具体时间和 流程),由其他函数调用,比如设备驱动,操作系统提供了一组某个设备的函数指针, 比如 LCD 屏驱动,由一组画点,画线,画块等函数组成,当更换 LCD 时,只需要把操 作系统开放的函数指针,指向你提供的接口即可,操作系统再需要时,会自动调用你 的驱动函数,这就是回调函数一个典型的例子。 这二个回调分别是对应于解析<>和, 下面分别详细介绍这个 2个回调函数。 typedef void (XMLCALL *XML_StartElementHandler) ( void *userData, const XML_Char *name, const XML_Char **atts); 其中第一个参数 userData, 可以由函数 XML_SetUserData(XML_Parser parser, void *p) 设置,参数就不用说了吧? 后面两个参数,我用个具体的列子说明下,这样更好理解: 比如有个标准 XML,某个标签属性如下: 那么 StartElementHandler回调返回的 name就是标签"feed", **atts是一个指针数 组,分别指向标签的一组属性,atts[0]就是"version", atts[1]就是"2.0", 以此类 推。应该很清楚了吧?呵呵。 这时候必然有个对应的: typedef void (XMLCALL *XML_EndElementHandler) ( void *userData, const XML_Char *name); 就是处理标签结束的,name 就是"feed”了,这个回调一般是用户设置自己的状态机的。 最后一个函数就是 XML_SetCharacterDataHandler( XML_Parser parser, XML_CharacterDataHandler handler) 这个函数是设置处理一个<>和之间的字段的回调。回调原型如下: typedef void (XMLCALL *XML_CharacterDataHandler) ( void *userData, const XML_Char *s, int len); 其中第二个参数是一块 Buffer的指针,如果你单步 DEBUG后,你会发现 expat用的就 是你传入的那块 Buffer(这块 Buffer下面讲解),比如: 天气 28日 08时至 29日 08时,陕西中南部、山西西南部、河南中南部、 湖北北部、四川中东部、重庆西部和北部、贵州西部等地的部分地区有大雨或 暴雨,河南南部、湖北北部等地局部有大暴雨。【点击“更多”查询其他城市 天气】 假设目前解析到天气这个 charData, 如果你看那个指针的所有内容的话,实际上是这样的: 天气 28日 08 时至 29日 08时,陕西中南部、山西西南部、河南中南部、湖北 北部、四川中东部、重庆西部和北部、贵州西部等地的部分地区有大雨或暴雨,河南南部、 湖北北部等地局部有大暴雨。【点击“更多”查询其他城市天气】 所以要根据第三个参数 len来确定正确的数据。 但这里有个非常隐晦的问题,如果不知道的话,会带来很大麻烦,下面说。 最后就是 parse,调用 XML_Parse(XML_Parser parser, const char *s, int len, int isFinal) 第二个参数是用户指定的 Buffer 指针, 第三个是这块 Buffer中实际内容的字节数,最后 参数代表是否这块 Buffer已经结束。比如要解析的 XML 文件太大,但内存比较吃紧,Buffer 比较小,则可以循环读取文件,然后丢给 Parser, 在文件读取结束前,isFinal参数为 FALSE,反之为 TRUE。 这里的 Buffer如果太小则会造成上面提到那个隐晦的问题, XML_CharacterDataHandler一次返回的可能并不是完整的 CharData,比如这个 charData的Len大于你的 Buffer大小,那这是会连续调用 2次XML_CharacterDataHandler, 我们需要将 2次结果拼接起来,以得到正确结果,因此我们的状态机一定要考虑到这点。 顺 便说下 XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)函数,在某 些时候,如果你不确定前后 2次 XML是否一样的情况下,比如网络上投递的 XML,在一次解 析后最好调用一次本函数,否则会出现意料之外的结果。比如前后两次 XML完全一样,可这 你并不知情,那么 XML_Parse()会返回失败。 XML 解析-libxml库函数解释 libxml(一) 绪论 Libxml 是一个实现读、创建及操纵 XML 数据功能的 C语言库。这个指南提供例子代码 并给出它基本功能的解释。在这个项目的主页上有 Libxml及更多关于它可用的资料。包含 有完整的 API 文档。这个指南并不能替代这些完整的文档,但是阐明功能需要使用库来完成 基本操作。 这个指南基于一个简单的 XML应用,它使用我写的一篇文章生成,它包含有元数据和文 章的主体。 本指南中的例子代码示范如何做到: • 解析文档 • 取得指定元素的文本 • 添加一个元素及它的内容 • 添加一个属性 • 取得一个属性的值 例子的完整代码包含在附录中 数据类型 Libxml 定义了许多数据类型,我们将反复碰到它们,它隐藏了杂乱的来源以致你不必 处理它除非你有特定的需要。xmlChar 替代 char,使用 UTF-8编码的一字节字符串。如果你 的数据使用其它编码,它必须被转换到 UTF-8才能使用 libxml的函数。在 libxml编码支持 WEB 页面有更多关于编码的有用信息。 XmlDoc 包含由解析文档建立的树结构,xmlDocPtr 是指向这个结构的指针。 xmlNodePtr and xmlNode包含单一结点的结构 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编码信息包含在 XML 标准中。 ⑤取得文档根元素 ⑥检查确认当前文档中包含内容。 ⑦在这个例子中,我们需要确认文档是正确的类型。“Story”是在这个指南中使用文档的 根类型。 取得元素内容 你找到在文档树中你要查找的元素后可以取得它的内容。在这个例子中我们查找 “story”元素。进程将在冗长的树中查找我们感兴趣的元素。我们假定你已经有了一个名 为 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”。这是一个包含有我们将查找的 “keywords”的元素。它使用了 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,它有一个文档指针参数,在这个例子中,我们仅仅打印它。 注释 因为 xmlNodeListGetString为它返回的字符串分配内存,你必须使用 xmlFree释放它。 使用 XPath取得元素内容 除了一步步遍历文档树查找元素外,Libxml2包含支持使用 Xpath表达式取得指定结点 集。完整的 Xpath API文档在这里。Xpath允许通过路径文档搜索匹配指定条件的结点。在 下面的例子中,我们搜索文档中所有的“keyword”元素。 注释 下面是 Xpath 完整的讨论。它详细的使用资料,请查阅 Xpath规范。 这个例子完整的代码 参见附录 D,XPath例程代码。 Using XPath requires setting up an xmlXPathContext and then supplying the XPath expression and the context to the xmlXPathEvalExpression function. The function returns an xmlXPathObjectPtr, which includes the set of nodes satisfying the XPath expression. 使用 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)){ printf("No result\n"); return NULL; } xmlXPathFreeContext(context); return result; } ①首先定义变量 ②初始化变量 context ③应用 XPath 表达式 ④检查结果 由函数返回的 xmlPathObjectPtr包含一个结点集和其它需要被迭代及操作的信息。在这个 例子中我们的函数返回 xmlXPathObjectPtr,我们使用它打印我们文档中 keyword结点的内 容。这个结点集对象包含在集合(nodeNr)中的元素数目及一个结点(nodeTab)数组。 ①for (i=0; i < nodeset->nodeNr; i++) { ②keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, printf("keyword: %s\n", keyword); xmlFree(keyword); } ①变量 nodeset->Nr持有结点集中元素的数量。我们使用它遍历数组。 ②打印每个结点包含的内容。 注释 Note that we are printing the child node of the node that is returned, because the contents of the keyword element are a child text node.注意我们打印的是结点的子结 点的返回值,因为 keyword元素的内容是一个子文本结点。 写(插入)元素 写元素内容使用上面许多一样的步骤—解析文档并遍历树。我们先解析文档然后遍历树 查找我们想插入元素的位置。在这个例子中,我们再一次查找“storyinfo”元素并插入一 个 keyword。然后我们装文件写入磁盘。完整代码:附录 E,添加 keyword例程 本例中主要的不同在于 parseStory void parseStory (xmlDocPtr doc, xmlNodePtr cur, char *keyword) { ①xmlNewTextChild (cur, NULL, "keyword", keyword); return; } ①XmlNewTextChild函数添加一个当前结点的新的子元素到树中 一旦结点被添加,我们应当写文档到文件中。你是否想给元素指定一个命名空间?你能添加 它,在我们的例子中,命名空间是 NULL。 xmlSaveFormatFile (docname, doc, 1); 第一个参数是写入文件的名,你注意到和我们刚刚读入的文件名是一样的。在这个例子中, 我们仅仅覆盖原来的文件。第二个参数是一个 xmlDoc结构指针,第三个参数设定为 1,保 证在输出上写入。 libxml(二) 写属性 写属性类似于给一个新元素写文本。在这个例子中,我们将添加一个 reference结点 URI 属性到我们的文档中。完整代码:附录 F,添加属性例程代码。reference是 story元 素的一个子结点,所以找到并插入新元素及其属性是简单的。一旦我们在 parseDoc进行了 错误检查,我们将在正确的位置加放我们的新元素。但进行之前我们需要定义一个此前我们 不见过的数据类型。 xmlAttrPtr newattr; 我们也需要 xmlNodePtr: xmlNodePtr newnode; 剩下的 parseDoc则和前面一样,检查根结点是否为 story。如果是的,那我们知道我 们将在指定的位置添加我们的元素。 ① newnode = xmlNewTextChild (cur, NULL, "reference", NULL); ②newattr = xmlNewProp (newnode, "uri", uri); ①使用 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或特定 XML时最常见的困难。稍后的讨论来 思考 设计 领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计 你的应用程序将帮助你避免这个困难。实际上,libxml能以 UTF-8 格式 pdf格式笔记格式下载页码格式下载公文格式下载简报格式下载 保存和操 纵多种数据 你的程序使用其它的数据格式,比如常见的 ISO-8859-1编码,必须使用 libxml函数转 换到 UTF-8。如果你想你的程序以除 UTF-8外的其它编码方式输出也必须做转换。 如果能有效地转换数据 Libxml将使用转换器。无转换器时,仅仅 UTF-8、UTF-16和 ISO-8859-1能够被作为外部格式使用。有转换器时,它能将从其它格式与 UTF-8互换的任 何格式均可使用。当前转换器支持大约 150 种不同的编码格式之间的相互转换。实际支持的 格式数量正在被实现。每一个实现在的转换器尽可能的支持每一种格式。 警告:一个常见错误是在内部数据不同的部分使用不同的编码格式。最常见的情况是一个用 以 ISO-8859-1作为内部数据格式,结合 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。 ④The conversion function identified by handler requires as its arguments pointers to the input and output strings, along with the length of each. The lengths must be determined separately by the application. 由句柄指定的转换函数请求输入、输出字符中及它们的长度作为参数。这个长度必须由应用 程序分别指定。 ⑤用指定编码而不是 UTF-8输出,我们使用 xmlSaveFormatFileEnc指不定期编码方式。 libxml2 在 linux 下的使用 官网地址:http://xmlsoft.org 1.下载和安装 LIBXML2 Libxml2 是个 C语言的 XML 程式库,能够简单方便的提供对 XML文档的各种操作,并且 支持 XPATH查询,连同部分的支持 XSLT转换等功能。Libxml2的下载地址是 http://xmlsoft.org/,完全版的库是开源的,并且带有例子程式和说明文档。最好将这个 库先下载下来,因为这样能够查看其中的文档和例子。 由于我是在 linux 下用 C语言进行研发的,所以我下载的是 libxml2-2.6.20.tar.gz 版本的源码包。具体安装步骤: 1、解压:$tar zxvf libxml2-2.6.20.tar.gz 2、进入解压后的安装目录:$cd libxml2-2.6.20 3、安装三部曲:1)$./configure 2)$make 3)$make install(安装完毕) 2. Libxml2 中的数据类型和函数 一个函数库中可能有几百种数据类型连同几千个函数,但是记住大师的话,90%的功能 都是由 30%的内容提供的。对于 libxml2,我认为搞懂以下的数据类型和函数就足够了。 2.1 内部字符类型 xmlChar xmlChar 是 Libxml2中的字符类型,库中任何字符、字符串都是基于这个数据类型。事 实上他的定义是:xmlstring.h->typedef unsigned char xmlChar; 使用 unsigned char作为内部字符格式是考虑到他能很好适应 UTF-8编码,而 UTF-8编码正 是 libxml2的内部编码,其他格式的编码要转换为这个编码才能在 libxml2中使用。还经常 能够看到使用 xmlChar*作为字符串类型,很多函数会返回一个动态分配内存的 xmlChar*变 量,使用这样的函数时记得要手动删除内存。 2.2 xmlChar 相关函数 如同标准 c中的 char 类型相同,xmlChar也有动态内存分配、字符串操作等相关函数。 例如 xmlMalloc是动态分配内存的函数;xmlFree是配套的释放内存函数;xmlStrcmp是字 符串比较函数等等。 基本上 xmlChar字符串相关函数都在 xmlstring.h中定义;而动态内存分配函数在 xmlmemory.h中定义。 2.3 xmlChar*和其他类型之间的转换 另外要注意,因为总是要在 xmlChar*和 char*之间进行类型转换,所以定义了一个宏 BAD_CAST,其定义如下:xmlstring.h->#define BAD_CAST (xmlChar *)。原则上来说, unsigned char和 char之间进行强制类型转换是没有问题的。 2.4 文档类型 xmlDoc、指针 xmlDocPtr xmlDoc 是个 struct,保存了一个 xml的相关信息,例如文档名、文档类型、子节点等 等;xmlDocPtr等于 xmlDoc*,他搞成这个样子总让人以为是智能指针,其实不是,要手动 删除的。  xmlNewDoc函数创建一个新的文档指针。  xmlParseFile函数以默认方式读入一个 UTF-8格式的文档,并返回文档指针。  xmlReadFile函数读入一个带有某种编码的 xml 文档,并返回文档指针;细节见 libxml2 参考手册。  xmlFreeDoc释放文档指针。特别注意,当您调用 xmlFreeDoc时,该文档任何包含的节 点内存都被释放,所以一般来说无需手动调用 xmlFreeNode或 xmlFreeNodeList来释放 动态分配的节点内存,除非您把该节点从文档中移除了。一般来说,一个文档中任何节 点都应该动态分配,然后加入文档,最后调用 xmlFreeDoc一次释放任何节点申请的动 态内存,这也是为什么我们很少看见 xmlNodeFree的原因。  xmlSaveFile将文档以默认方式存入一个文档。  xmlSaveFormatFileEnc可将文档以某种编码/格式存入一个文档中。 2.5 节点类型 xmlNode、指针 xmlNodePtr 节点应该是 xml中最重要的元素了,xmlNode代表了 xml文档中的一个节点,实现为一 个 struct,内容很丰富: tree.h typedef struct _xmlNode xmlNode; typedef xmlNode *xmlNodePtr; struct _xmlNode { void *_private; /* application data */ xmlElementType type; /* type number, must be second ! */ const xmlChar *name; /* the name of the node, or the entity */ struct _xmlNode *children; /* parent->childs link */ struct _xmlNode *last; /* last child link */ struct _xmlNode *parent; /* child->parent link */ struct _xmlNode *next; /* next sibling link */ struct _xmlNode *prev; /* previous sibling link */ struct _xmlDoc *doc; /* the containing document */ /* End of common part */ xmlNs *ns; /* pointer to the associated namespace */ xmlChar *content; /* the content */ struct _xmlAttr *properties; /* properties list */ xmlNs *nsDef; /* namespace definitions on this node */ void *psvi; /* for type/PSVI informations */ unsigned short line; /* line number */ unsigned short extra; /* extra data for XPath/XSLT */ }; 能够看到,节点之间是以链表和树两种方式同时组织起来的,next和 prev指针能够组成链 表,而 parent和 children能够组织为树。同时更有以下重要元素:  节点中的文字内容:content;  节点所属文档:doc;  节点名字:name;  节点的 namespace:ns;  节点属性列表:properties; Xml文档的操作其根本原理就是在节点之间移动、查询节点的各项信息,并进行增加、 删除、修改的操作。 xmlDocSetRootElement 函数能够将一个节点配置为某个文档的根节点,这是将文档和 节点连接起来的重要手段,当有了根结点以后,任何子节点就能够依次连接上根节点,从而 组织成为一个 xml 树。 2.6 节点集合类型 xmlNodeSet、指针 xmlNodeSetPtr 节点集合代表一个由节点组成的变量,节点集合只作为 Xpath的查询结果而出现(XPATH 的介绍见后面),因此被定义在 xpath.h中,其定义如下: /* * A node-set (an unordered collection of nodes without duplicates). */ typedef struct _xmlNodeSet xmlNodeSet; typedef xmlNodeSet *xmlNodeSetPtr; struct _xmlNodeSet { int nodeNr; /* number of nodes in the set */ int nodeMax; /* size of the array as allocated */ xmlNodePtr *nodeTab; /* array of nodes in no particular order */ /* @@ with_ns to check wether namespace nodes should be looked at @@ */ }; 能够看出,节点集合有三个成员,分别是节点集合的节点数、最大可容纳的节点数,连 同节点数组头指针。对节点集合中各个节点的访问方式很简单,如下: xmlNodeSetPtr nodeset = XPATH查询结果; for (int i = 0; i nodeNr; i++) { nodeset->nodeTab; } 注意,libxml2是个 c函数库,因此其函数和数据类型都使用 c语言的方式来处理。假如是 c++,我想我宁愿用 STL 中的 vector来表示一个节点集合更好,而且没有内存泄漏或溢出的 担忧。 3. 简单 xml操作例子 了解以上基本知识之后,就能够进行一些简单的 xml操作了。当然,还没有涉及到内码转换 (使得 xml中能够处理中文)、xpath等较复杂的操作。 3.1 创建 xml文档 有了上面的基础,创建一个 xml文档显得很简单,其流程如下: l 用 xmlNewDoc函数创建一个文档指针 doc; l 用 xmlNewNode函数创建一个节点指针 root_node; l 用 xmlDocSetRootElement将 root_node配置为 doc的根结点; l 给 root_node添加一系列的子节点,并配置子节点的内容和属性; l 用 xmlSaveFile将 xml 文档存入文档; l 用 xmlFreeDoc函数关闭文档指针,并清除本文档中任何节点动态申请的内存。 注意,有多种方式能够添加子节点:第一是用 xmlNewTextChild直接添加一个文本子节点; 第二是先创建新节点,然后用 xmlAddChild将新节点加入上层节点。 源代码文档是 CreateXmlFile.cpp,如下: /******************************************************************** created: 2007/11/09 created: 9:11:2007 15:34 filename: CreateXmlFile.cpp author: Wang xuebin depend: libxml2.lib build: nmake TARGET_NAME=CreateXmlFile purpose: 创建一个 xml文档 *********************************************************************/ #include #include #include #include int main() { //定义文档和节点指针 xmlDocPtr doc = xmlNewDoc(BAD_CAST"1.0"); xmlNodePtr root_node = xmlNewNode(NULL,BAD_CAST"root"); //配置根节点 xmlDocSetRootElement(doc,root_node); //在根节点中直接创建节点 xmlNewTextChild(root_node, NULL, BAD_CAST "newNode1", BAD_CAST "newNode1 content"); xmlNewTextChild(root_node, NULL, BAD_CAST "newNode2", BAD_CAST "newNode2 content"); xmlNewTextChild(root_node, NULL, BAD_CAST "newNode3", BAD_CAST "newNode3 content"); //创建一个节点,配置其内容和属性,然后加入根结点 xmlNodePtr node = xmlNewNode(NULL,BAD_CAST"node2"); xmlNodePtr content = xmlNewText(BAD_CAST"NODE CONTENT"); xmlAddChild(root_node,node); xmlAddChild(node,content); xmlNewProp(node,BAD_CAST"attribute",BAD_CAST "yes"); //创建一个儿子和孙子节点 node = xmlNewNode(NULL, BAD_CAST "son"); xmlAddChild(root_node,node); xmlNodePtr grandson = xmlNewNode(NULL, BAD_CAST "grandson"); xmlAddChild(node,grandson); xmlAddChild(grandson, xmlNewText(BAD_CAST "This is a grandson node")); //存储 xml文档 int nRel = xmlSaveFile("CreatedXml.xml",doc); if (nRel != -1) { cout一个 xml 文档被创建,写入"个字节" } //释放文档内节点动态申请的内存 xmlFreeDoc(doc); return 1; } 编译链接命令如下: nmake TARGET_NAME=CreateXmlFile 然后执行可执行文档 CreateXmlFile.exe,会生成一个 xml文档 CreatedXml.xml,打开后如 下所示: root> newNode1>newNode1 contentnewNode1> newNode2>newNode2 contentnewNode2> newNode3>newNode3 contentnewNode3> node2 attribute="yes">NODE CONTENTnode2> son> grandson>This is a grandson nodegrandson> son> root> 最好使用类似 XMLSPY这样的工具打开,因为这些工具能够自动整理 xml文档的栅格,否则 很有可能是没有任何换行的一个 xml文档,可读性较差。 3.2 解析 xml文档 解析一个 xml 文档,从中取出想要的信息,例如节点中包含的文字,或某个节点的属性,其 流程如下: l 用 xmlReadFile函数读出一个文档指针 doc; l 用 xmlDocGetRootElement函数得到根节点 curNode; l curNode->xmlChildrenNode就是根节点的子节点集合; l 轮询子节点集合,找到所需的节点,用 xmlNodeGetContent取出其内容; l 用 xmlHasProp查找含有某个属性的节点; l 取出该节点的属性集合,用 xmlGetProp取出其属性值; l 用 xmlFreeDoc函数关闭文档指针,并清除本文档中任何节点动态申请的内存。 注意:节点列表的指针依然是 xmlNodePtr,属性列表的指针也是 xmlAttrPtr,并没有 xmlNodeList或 xmlAttrList这样的类型。看作列表的时候使用他们的 next和 prev链表指 针来进行轮询。只有在 Xpath 中有 xmlNodeSet这种类型,其使用方法前面已介绍了。 源代码如下:ParseXmlFile.cpp /******************************************************************** created: 2007/11/15 created: 15:11:2007 11:47 filename: ParseXmlFile.cpp author: Wang xuebin depend: libxml2.lib build: nmake TARGET_NAME=ParseXmlFile purpose: 解析 xml文档 *********************************************************************/ #include #include int main(int argc, char* argv[]) { xmlDocPtr doc; //定义解析文档指针 xmlNodePtr curNode; //定义结点指针(您需要他为了在各个结点间移动) xmlChar *szKey; //临时字符串变量 char *szDocName; if (argc { printf("Usage: %s docname"n", argv[0]); return(0); } szDocName = argv[1]; doc = xmlReadFile(szDocName,"GB2312",XML_PARSE_RECOVER); //解析文档 //检查解析文档是否成功,假如不成功,libxml将指一个注册的错误并停止。 //一个常见错误是不适当的编码。XML标准文档除了用 UTF-8或 UTF-16外还可用其他 编码保存。 //假如文档是这样,libx
本文档为【expat xml解析器】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_725386
暂无简介~
格式:pdf
大小:300KB
软件:PDF阅读器
页数:49
分类:互联网
上传时间:2012-03-29
浏览量:55