XML文件作为最常使用的存储层次结构数据的文件类型,被广泛应用于三维模型的存储表示。其文件一般是层次化的,用于描述层次化数据,如图1所示。一般地,可以将其结构理解为一颗树,最开始的树根,如图1中的<story>,被称为“根节点”,找到树根之后,继续找到第一个根节点,...,依次能够找到XML文件中所有的数据。

c语言读取xml文件数据(如何使用C语言解析xml文件)(1)

图1 XML的层次结构示例

所以,我们要想在程序中读取和处理XML文件,就需要根据XML文件的结构,解析XML文件的所有信息,从而能够处理XML文件中的信息。

由于C语言比较底层,从最基本的文件读写开始写解析XML文件的程序极其困难,并且存在操作不方便,难以扩展和缺乏鲁棒性等问题,所以,在实际开发领域,工程师们一般会找成熟的XML解析库来使用,如本文所要讲的libxml库,使用这些成熟的代码库,能够基本保证程序的稳定性和鲁棒性,并且由于libxml有公开的文档,团队协作就有标准可依。

libxml库需要下载,你可以从官网和github下载,也可以从微云下载,下载地址:https://share.weiyun.com/omPVXlss

下载下来之后,我们需要分别编译三个文件,三个文件分别解压,分别编译。编译之后将生成的lib文件配置到你的工程文件中(这里我们的工程文件使用Visual Studio创建的项目)。

c语言读取xml文件数据(如何使用C语言解析xml文件)(2)

图2 需编译的三个文件

环境配置成功之后,那么如何解析XML文件呢?

解析文档时只需要文档名和一个函数调用,再加上错误处理。下面代码查找keyword节点并打印节点下的文本内容,如下:

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <libxml/xmlmemory.h> #include <libxml/parser.h> static int parseXMLDoc(const char* docname) { xmlDocPtr doc;//XML文件指针 xmlNodePtr cur;//当前节点 xmlNodePtr subcur;//子节点 xmlKeepBlanksDefault(0); doc = xmlParseFile(docname); if (doc == NULL) { fprintf(stderr, "doc error!\n"); return 0; } cur = xmlDocGetRootElement(doc);//获取根节点 if (cur == NULL) { fprintf(stderr, "root error!\n"); xmlFreeDoc(doc); return 0; } //根节点如果不是“xml”,则返回 if (xmlStrcmp(cur->name, (const xmlChar*)"xml")) { printf("end\n"); return 0; } //获取子节点,获取名称为"coefs"的子节点,xml->Geometry->coefs cur = cur->children; while (cur != NULL) { subcur= cur->xmlChildrenNode; while (subcur != NULL) { if (strcmp(subcur->name, "coefs") == 0){//查找名称为coefs的子节点 char* str = (char*)xmlNodeGetContent(subcur); } subcur = subcur->next; } cur = cur->next; } xmlFreeDoc(doc); return 0; } int main(int argc, char **argv){ char *docname; if(argc <= 1){ printf("Usage: %s docname\n", argv[0]); return 0; } docname=argv[1]; parseXMLDoc(docname); return 1; }

解析XML文档的基本流程如下:

(1)定义文档指针、节点和子节点指针。子节点是指节点的节点。这里有个父子关系。

(2)调用xmlParseFile()解析文档。如果不成功,返回一个错误提示“"doc error!\n"”并停止。

(3)调用xmlDocGetRootElement()获取文档根节点,若无根节点则输出错误提示“root error!\n”,释放文档,停止。

(4)确认文档是否正确的类型,通过检查根节点名称来判断。

(5)检索节点的内容,这需要遍历文档树。对每个节点,遍历其子节点都需要一个循环。先用cur = cur->xmlChildrenNode获取第一个子节点,然后通过cur = cur->next不断向前遍历,直到cur==NULL。查找找指定节点时使用xmlStrcmp()函数,如果你指定的名称相同,就找到了你要的节点。通常把查找某个子节点的过程封装成函数。

(6)获取节点中的内容。查找到指定节点后,调用xmlNodeListGetString()获取节点下的文本。注意在XML中,包含在节点中的文本是这个节点的子节点,因此获取的是cur->xmlChildrenNode中的字符串。xmlNodeListGetString()会为返回的字符串分配内存,因此记得要用xmlFree()来释放它。

(7)调用xmlFreeDoc()释放文档指针。

,