如何在linux环境下使用libxmllinux2,查找xml文件存放的位置?

由于项目需要,这两天在用C++做XML文件解析的工作。在linux下有个很方便的操作xml文件的库——libxml2,它提供了一套创建和查询xml文件的C语言的接口。这篇博客主要介绍如何使用libxml2读取并解析xml文件。
下载并安装libxml2
下载地址:ftp://xmlsoft.org/libxml2/
下载最新的版本,我下载的是libxml2-2.9.1.tar.gz。下载后将文件解压到合适的位置,进入解压后的目录。
编译命令非常简单(注意:如果configure文件没有可执行权限,增加可执行权限):
./configure
make install
此时libxml2相关的头文件应该在/usr/local/include/libxml2目录下,libxml2相关的库文件应该在/usr/local/lib目录下。
解析XML文档的两种方式
在使用libxml2进行XML文档的解析时,非常推荐使用XPath语言实现,如果把XML文件看作数据库的话,那么XPath就可被视为sql,我们只要构造一定格式的语句就可查询到相关结果,而在在libxml2中使用Xpath是非常简单的。当然我们也可以直接通过libxml2相关接口从跟节点出发,根据整个xml的父子节点关系定位到相关节点进行查询。下面我将分别对这两种方式进行介绍。
我们使用下面的xml测试用例:
&?xml version="1.0" encoding="ISO-8859-1"?&
Harry Potter29.99Learning XML39.95
直接使用libxml2接口解析XML文档
int main (int argc , char **argv)
xmlDocPtr pdoc = NULL;
xmlNodePtr proot = NULL, pcur = NULL;
/*****************打开xml文档********************/
xmlKeepBlanksDefault(0);//必须加上,防止程序把元素前后的空白文本符号当作一个node
pdoc = xmlReadFile ("test.xml", "UTF-8", XML_PARSE_RECOVER);//libxml只能解析UTF-8格式数据
if (pdoc == NULL)
printf ("error:can't open file!\n");
/*****************获取xml文档对象的根节对象********************/
proot = xmlDocGetRootElement (pdoc);
if (proot == NULL)
printf("error: file is empty!\n");
/*****************查找书店中所有书籍的名称********************/
pcur = proot-&xmlChildrenN
while (pcur != NULL)
//如同标准C中的char类型一样,xmlChar也有动态内存分配,字符串操作等 相关函数。例如xmlMalloc是动态分配内存的函数;xmlFree是配套的释放内存函数;xmlStrcmp是字符串比较函数等。
//对于char* ch="book", xmlChar* xch=BAD_CAST(ch)或者xmlChar* xch=(const xmlChar *)(ch)
//对于xmlChar* xch=BAD_CAST("book"),char* ch=(char *)(xch)
if (!xmlStrcmp(pcur-&name, BAD_CAST("book")))
xmlNodePtr nptr=pcur-&xmlChildrenN
while (pcur != NULL)
if (!xmlStrcmp(nptr-&name, BAD_CAST("title")))
printf("title: %s\n",((char*)XML_GET_CONTENT(nptr-&xmlChildrenNode)));
pcur = pcur-&
/*****************释放资源********************/
xmlFreeDoc (pdoc);
xmlCleanupParser ();
xmlMemoryDump ();
具体流程我已经在代码中详细注释,这里就不单独拿出来解释。
使用XPath语言解析XML文档
关于XPath的基础知识,可以访问http://www.w3school.com.cn/xpath/index.asp
xmlXPathObjectPtr getNodeset(xmlDocPtr pdoc,const xmlChar *xpath)
xmlXPathContextPtr context=NULL;//XPath上下文指针
xmlXPathObjectPtr result=NULL;
//XPath结果指针
context = xmlXPathNewContext(pdoc);
if(pdoc==NULL){
printf("pdoc is NULL\n");
return NULL;
if(xpath){
if (context == NULL) {
printf("context is NULL\n");
return NULL;
result = xmlXPathEvalExpression(xpath, context);
xmlXPathFreeContext(context);
//释放上下文指针
if (result == NULL) {
printf("xmlXPathEvalExpression return NULL\n");
return NULL;
if (xmlXPathNodeSetIsEmpty(result-&nodesetval)) {
xmlXPathFreeObject(result);
printf("nodeset is empty\n");
return NULL;
int main (int argc , char **argv){
pdoc = NULL;
xmlNodePtr
proot = NULL;
/*****************打开xml文档********************/
xmlKeepBlanksDefault(0);//必须加上,防止程序把元素前后的空白文本符号当作一个node
pdoc = xmlReadFile ("test.xml", "UTF-8", XML_PARSE_RECOVER);//libxml只能解析UTF-8格式数据
if (pdoc == NULL)
printf ("error:can't open file!\n");
/*****************获取xml文档对象的根节对象********************/
proot = xmlDocGetRootElement (pdoc);
if (proot == NULL)
printf("error: file is empty!\n");
/*****************查找书店中所有书籍的名称********************/
xmlChar *xpath = BAD_CAST("//book"); //xpath语句
xmlXPathObjectPtr result = getNodeset(pdoc, xpath); //查询XPath表达式,得到一个查询结果
if (result == NULL)
printf("result is NULL\n");
if(result)
xmlNodeSetPtr nodeset = result-& //获取查询到的节点指针集合
//nodeset-&nodeNr是集合元素总数
for (int i=0; i & nodeset-&nodeNr; i++)
cur = nodeset-&nodeTab[i];
cur = cur-&xmlChildrenN
while (cur != NULL)
//如同标准C中的char类型一样,xmlChar也有动态内存分配,字符串操作等 相关函数。例如xmlMalloc是动态分配内存的函数;xmlFree是配套的释放内存函数;xmlStrcmp是字符串比较函数等。
//对于char* ch="book", xmlChar* xch=BAD_CAST(ch)或者xmlChar* xch=(const xmlChar *)(ch)
//对于xmlChar* xch=BAD_CAST("book"),char* ch=(char *)(xch)
if (!xmlStrcmp(cur-&name, BAD_CAST("title"))) {
printf("title: %s\n",((char*)XML_GET_CONTENT(cur-&xmlChildrenNode)));
cur = cur-&
xmlXPathFreeObject(result);//释放结果指针
/*****************释放资源********************/
xmlFreeDoc (pdoc);
xmlCleanupParser ();
xmlMemoryDump ();
具体流程我已经在代码中详细注释,这里就不单独拿出来解释。
更加详细的libxml2接口,可以访问http://xmlsoft.org/html/libxml-tree.html
编译程序并运行
编译上述程序
g++ search1.cpp -I/usr/local/include/libxml2 -L/usr/local/lib -lxml2 -o search1g++ search2.cpp -I/usr/local/include/libxml2 -L/usr/local/lib -lxml2 -o search2
运行程序及运行结果
运行./search1
显示如下结果:
title: Harry Potter
title: Learning XML
运行./search2
显示如下结果:
title: Harry Potter
title: Learning XML
Linux 下C/C++解析XML文件
在工程项目中我们的项目需要根据不同的环境配置不同的程序参数,而常用的两种文件分别是ini文件和XML文件,接下来我来分析下在Linux下解析XML文件过程。...
linux下的xml操作详解
1. 下载与安装LIBXML2
Libxml2是一个C语言的XML程序库,可以简单方便的提供对XML文档的各种操作,并且支持XPATH查询,以及部分的支持XSLT转换等功能。Libxml2的下载...
Linux下的xml文件的解析
解析一个xml文档,从中取出想要的信息,例如节点中包含的文字,或者某个节点的属性,其流程如下:
用xmlReadFile函数读出一个文档指针doc;
用xmlDocGetR...
libxml2用xpath进行查找
http://mp3.webradio.antenne.de:80
libxml2编译及API,XPath操作总结
手动编译的好处是可以获得最新的头文件及库,下载最新的源代码,以现在的2.7.6为例,windows xp+vc6 sp6环境,(vc7,vc8,vc9类似)进入libxml2-2.7.6/win32/...
linux 之xml 解析读取
原博文:https://www.cnblogs.com/catgatp/p/6505451.html下载地址:ftp://xmlsoft.org/libxml2/下载libxml2文件后,解压改文件,...
没有更多推荐了,
(window.slotbydup=window.slotbydup || []).push({
id: "5865575",
container: s,
size: "300,250",
display: "inlay-fix"  引言   要创建完善的、高度互操作性的应用程序,XML 是一个很好的选择,因为它正越来越广泛地应用于数据存储和配置文件管理。本文研究了一个使用 XML(可扩展标记语言)作为其配置文件格式的示例应用程序,并通过该示例向您介绍如何在自己的 UNIX 应用程序中使用 XML。该示例应用程序使用 Perl 编写,并且其中使用了基于 Gnome 项目的 LibXML2 库的 Perl 模块。   在给出 XML 的简单定义之后,本文介绍了一个使用 XML 编写的示例配置文件。然后,通过示例代码来介绍如何解析这个配置文件。系统管理员可以手动修改该配置文件,但通常在一定程度上,需要应用程序直接地修改该配置文件。然后,本文通过一个示例介绍如何以编程的方式向这个 XML 文档添加新的配置选项,以及如何修改当前条目的值。最后,本文介绍了将这个经过修改的配置文件写入到磁盘的代码。   关于 XML   在开始研究 LibXML2 库之前,让我们先来巩固一下 XML 的相关基础。XML 是一种基于文本的格式,它可用来创建能够通过各种语言和平台访问的结构化数据。它包括一系列类似 HTML 的标记,并以树型结构来对这些标记进行排列。   例如,可参见清单 1中介绍的简单文档。这是配置文件部分中研究的配置文件示例的简化版本。为了更清楚地显示 XML 的一般概念,所以对其进行了简化。   清单 1. 一个简单的 XML 文件 &?xml version="1.0" encoding="UTF-8"?&
&owner&root&/owner&
&action&delete&/action&
&age units="days"&10&/age&
&/files&  清单 1中的第一行是 XML 声明,它告诉负责处理 XML 的应用程序,即解析器,将要处理的 XML 的版本。大部分的文件使用版本 1.0 编写,但也有少量的版本 1.1 的文件。它还定义了所使用的编码。大部分文件使用 UTF-8,但是,XML 设计用来集成各种语言中的数据,包括那些不使用英语字母的语言。   接下来出现的是元素。一个元素以开始标记开始(如 ),并以结束标记结束(如 ),其中使用斜线 (/) 来区别于开始标记。   元素是 Node的一种类型。XML 文档对象模型 (DOM) 定义了几种不同的 Nodes类型,包括 Elements(如 files或者 age)、Attributes(如 units)和 Text(如 root或者 10)。元素可以具有子节点。例如,age 元素有一个子元素,即文本节点 10。而 files 元素有七个子元素。其中三个很明显。它们分别是三个子元素:owner、action和 age。其他四个分别是元素前后的空白文本符号。  XML 解析器可以利用这种父子结构来遍历文档,甚至修改文档的结构或内容。LibXML2 是这样的解析器中的其中一种,并且文中的示例应用程序正是使用这种结构来实现该目的。对于各种不同的环境,有许多不同的解析器和库。LibXML2 是用于 UNIX 环境的解析器和库中最好的一种,并且经过扩展,它提供了对几种脚本语言的支持,如 Perl 和 Python。   作为研究工作的第一步,让我们先来看一个示例配置文件。   配置文件   文中的示例应用程序读取了特定文件的操作列表。而配置文件定义了这些文件和操作。假设该配置文件是位于 UNIX 文件系统中某个位置的一个文件。例如,在 UNIX 系统 cron 中可能会使用这个配置文件。该 XML 文件定义了目录路径和根据条件要执行的操作,而这些条件则包括所有者和文件存在时间(请参见清单 2)。   清单 2. 配置文件 &?xml version="1.0" encoding="UTF-8"?&
&filesystem&
&dirname&/var&/dirname&
&owner&root&/owner&
&action&delete&/action&
&age units="days"&10&/age&
&owner&any&/owner&
&action&delete&/action&
&age units="hours"&96&/age&
&dirname&/tmp&/dirname&
&owner&any&/owner&
&action&delete&/action&
&age units="hours"&24&/age&
&/filesystem&  在本例中,根元素是 filesystem,它包含两个 path元素。每个 path元素包含相应的目录名和一个或多个 files元素。每个 files元素通过 age元素的 units属性中指定的存在时间单位,定义了当用户或用户文件达到特定的存在时间时,应用程序应采取的操作。请记住,空白符号是有意义的。从结构的观点来看,每个空白符号组成了独立的 Text节点。   在产品环境中,一个编写完善的 UNIX 应用程序不仅应该具有读取数据并对其进行操作的能力,而且还应具有根据用户输入对数据进行添加、删除和修改的能力。   现在让我们来研究使用该数据的应用程序。   示例程序   本文余下的内容通过示例代码介绍对 XML 配置文件的解析和管理。这些示例逐一地读取并修改配置文件,但在 UNIX 开发人员的日常工作中,您可以在任何类型的任务中使用这些概念。而且,因为使用了 LibXML2 库,所以您可以将这些概念插入到几乎任何的 UNIX 应用程序中。   我们将在本文中介绍使用 Perl 版本的 LibXML2 库的示例。Internet 上的大部分文档都在讨论如何使用 Java 或 Microsoft Visual Studio 工具进行编程,但对于 UNIX 用户或开发人员来说,Perl 则更有价值。清单 3显示了解析该 XML 文档所需的 Perl 模块。   清单 3. 需要的库   XML::LibXML   XML::LibXML::Common   XML::NamespaceSupport   XML::SAX      下面部分中介绍的代码仅仅只是一个框架。可分三个部分对其进行介绍:解析、操作和导出。   在加载和解析阶段中,可能会将数据加载到 Perl 变量中,如列表或哈希,但由于每个程序员都有他/她自己首选的方法来完成这项任务,所以我们把它留给读者作为一项练习。下面的代码只是简单地显示了数据,以此说明该脚本正确地找到了相应的数据。   在操作阶段中,该程序对 XML 文档中的元素进行添加、修改和删除的数据更新操作。通常地,这将按照用户的操作来进行。   最后在导出阶段中,将经过修改的最终的文档写回到磁盘。   加载和解析数据   对于应用程序来说,读取 XML 文件的第一步是加载该数据并将其解析为一个 Document对象。在此基础上,可以对 DOM 树进行遍历以获取特定的节点。让我们来看看清单 4中的代码是如何完成该任务的。   清单 4. 加载和解析 example.xml 的代码   my $parser = XML::LibXML-&new();   my $doc = $parser-&parse_file("example.xml");   $filesystem = $doc-&getDocumentElement();   @nodes=$filesystem-&childN   foreach $node (@nodes) {   if($node-&nodeType==ELEMENT_NODE) { # ignore text nodes   # just get the first match   @dirnames = $node-&getElementsByTagName("dirname")-&item(0);   foreach $dirname (@dirnames) {   print "dirname: ". $dirname-&textContent . "/n";   # push this into an array   }   # get all children   @files = $node-&getChildrenByTagName("files");   foreach $file (@files) {   foreach $values ($file-&childNodes) {   # ignore text nodes   if($values-&nodeType!=XML_TEXT_NODE) {   if($values-&nodeName() eq "age") {   # check for attribute, otherwise, use default of 'hours'   if($values-&hasAttributes()) {   print $values-&nodeName() . ": ". $values-&textC   print "". $values-&attributes-&item(0)-&value();   print "/n";   } else {   print $values-&nodeName() . ": ". $values-&textC   print "hours/n";   }   # calculate extended value from units and put in a   # hash linked with this dirname, etc.   } else {   print $values-&nodeName() . ": ". $values-&textC   print "/n";   # put this value into a hash linked with $dirname.   # We may have multiple entries for each $dirname, so   # perhaps use an array within a hash   }   }   }   }   }   }      首先,在清单 4中,创建了解析器并将 XML 从文件加载到 XML::LibXML::Document变量。这个对象包含了整个 XML 树,并且具有与之关联的各种方法可用来搜索节点、导出、验证和创建新的节点。本文将在后面的几个部分中对其中的一些方法进行介绍。从代码的起始处开始,您可以看到 getDocumentElement()方法,它用于返回文档的根节点。从这个根节点,就可以遍历整个 XML 树。   主 foreach循环对父 filesystem元素中的每个节点进行循环。当仅选择元素节点时,该循环将得到 path 元素。getElementsByTagName()方法根据相应的名称在节点中搜索对应的元素,并通过 NodeList对象返回它们。每个 path元素包含了一个 dirname元素,所以代码搜索名称为 dirname的元素,并获取其中的第一个条目。在代码中只能选择 ELEMENT 类型的节点,因为该方法不支持 TEXT 节点,并且会在 Perl 中产生一个不可恢复的错误。   在一个 path 元素中可能存在多个 files元素,所以代码对 getChildrenByTagName()方法的每一个元素进行循环,这个方法类似于 getElementsByTagName(),但仅搜索目标节点的直接子节点。这将返回所有的 files元素,但必须进行进一步的解析以获得 owner、action和 age元素。在得到了这些节点之后,可以调用 textContent以从相应的元素中获取实际的值。下面显示的是选择 ELEMENT 节点孩子的 TEXT 节点值的快捷方法:   print $values-&nodeName() . ": "   print $values-&firstChild()-&nodeValue();      在使用 age元素的情况下,还可以通过一个属性来指定时间单位。使用 hasAttributes()和 Attributes函数,该程序可以提取相应的属性,如果它存在话。如果它不存在,那么该程序使用缺省值 hours。   现在让我们来介绍对数据的操作,这样就能够以编程的方式来添加、删除和编辑操作。   对数据进行操作   现有的代码本身就是一个有用的程序。用户可以很容易地以手动地方式对该 XML 文件完成程序所做的修改。然而,有经验的 UNIX 开发人员还可以使用 XML 函数在程序中直接对文件进行修改。例如,可以包含用于添加新的操作或删除现有操作的菜单选项。要实现这个目的,让我们来看看在程序中对数据进行操作的代码。   清单 5. 向文档添加填充的 path 节点   $newnode = $doc-&createElement("path");   $newdirnode = $doc-&createElement("dirname");   $newdirnode-&appendText("/root");   $newfilesnode = $doc-&createElement("files");   $newownernode = $doc-&createElement("owner");   $newownernode-&appendText("any");   $newactionnode = $doc-&createElement("action");   $newactionnode-&appendText("archive");   $newagenode = $doc-&createElement("age");   $newagenode-&appendText("30");   $newagenode-&setAttribute("units","days");   $newfilesnode-&addChild($newownernode);   $newfilesnode-&addChild($newactionnode);   $newfilesnode-&addChild($newagenode);   $newnode-&addChild($newdirnode);   $newnode-&addChild($newfilesnode);   $filesystem-&addChild($newnode);   清单 5中的代码创建了一个 path元素,并为其填充了所有的元素。然后,将这个新创建的节点添加到根元素,即 filesystem。需要使用 XML::LibXML::Document类的 createElement()方法来创建每个元素。(正是 Document创建了您所需要的任何新的节点。)该方法返回一个尚未连接到文档树中任何位置的空节点。然后可以使用 XML::LibXML::Element 类的 appendText()方法为每个节点添加内容。此外,相对于创建一个新的 TEXT 节点,然后对其进行填充并将其添加到相应的元素,这是一种快捷的方法。可以使用 setAttribute()方法来添加属性,如果在目标元素中不存在给定名称的属性,该方法将自动创建一个新的 ATTRIBUTE节点。   在完成每个节点的创建并分别对它们进行了填充之后,可以使用要求的子节点作为参数,对父节点调用 addChild()方法。因此在上面的代码中,$newownernode成为了 $newfilesnode的子节点。文档中所有的节点保持其添加时的顺序。如果您希望指定其他的顺序,可以使用 insertAfter()或 insertBefore()函数。   将每个节点添加到相应的父节点,直到最后将主父节点添加到已经存在于文档中的一个节点。在上面的示例中,将该节点添加到了 filesystem根节点。(如果您是从头开始创建该文档,那么可以对 Document对象本身调用 addChild()来添加根元素,然后再向该元素添加任何其他的节点。)   正如前面所解释的,清单 2中的示例 XML 代码是一种可读的格式。换行和缩进使得文档更容易阅读。XML 解析器将读取所有这些字符,并将其作为一个 TEXT 类型的节点。清单 5中的示例没有添加任何这样的 TEXT 节点。因此,该示例的输出将不包含任何换行或缩进。如果您希望创建这种空白字符,那么需要使用 XML::LibXML::Text类来创建 TEXT 类型的节点,或者使用该文档对象的 createTextNode()函数。该构造函数的返回值是一个节点,可以使用与上面示例中相同的方式将其添加到树中。   要更改文件的内容,可以直接设置相关 TEXT 节点的 nodeValue(),或者替换整个元素:   $newnode = $doc-&createElement("owner");   $newnode-&appendText("toor");   $oldnode-&replaceNode($newnode);     要删除一个节点,有以下几种选择。一种方法是仅将其从结构中删除,代码如下所示:   $file-&unbindNode();     在找到需要删除的节点之后,通过一行命令即可将其从结构中删除,但并没有从文档中删除。这个函数调用直到程序结束时才真正销毁该数据结构。如果您需要将节点移动到树中的其他部分,那么可以使用相同的变量来调用 addNode()以将其重新添加到文档中新的位置。您还可以使用 removeChild()或 removeChildNodes()函数,这样可以从文档中彻底地释放相应的资源。   保存 XML 文件   在一些编程语言中,将 XML 文档保存到文件中可能比较烦琐,但幸运的是,LibXML 让这项任务变得非常简单:   $doc-&toFile("example.xml");     在对数据进行的所有的操作中,这是最简单的一种操作。在对内存中的 XML 文档完成了相应的修改之后,只需使用一个函数调用就可以将其写回到对应的配置文件中。还可以使用相关的 Perl 函数,如 toString()和 toFH(),这些函数分别将 XML 输出到一个字符串变量或者一个已打开的 Perl 文件句柄,而文件句柄将为您的应用程序的构建带来更大的灵活性。   结束语   通过提供 LibXML2 库以及对 Perl 模块的支持,Gnome 项目完成了一项很有价值的任务。本文对管理和使用 XML 配置文件所需要的三个重要的步骤进行了介绍。解析阶段可能是最复杂的,因为它需要一定程度的递归设计来解析 XML 树。尽管有些烦琐,但对内存中 XML 文档的操作却是非常简单明了的。使用 LibXML2 库导出经过修改的配置,也是非常容易的。   尽管相对于标准的UNIX 思维方式来说,需要进行一定的思维模式转移,但是 XML 可以为数据管理提供一种功能强大的方法。与简单的数据库格式相比,树型结构提供了更加灵活的数据视图。在开发新的应用程序或修改旧的应用程序时,可将其规范化为使用 XML 配置文件,在进行规范化的过程中可以很容易地使用 Gnome 项目所提供的免费的标准库,正如本文所介绍的。 本文转自
libxml2生成和解析配置树文件
之前的章节中介绍如何安装Ubuntu下libxml2的安装和使用以及如何使用CMake建立工程
CMake加入第三方库,这章将会更深入一步,讲述如何创建一个xml文件Create A Tree,如...
xml 解析,libxml2的使用
首先,从ftp://xmlsoft.org/libxml2/下载libxml2,依赖iconv、zlib1两个库。
1、读取文件,生成dom树
xmlNodePtr cu...
perl LibXML模块使用详解
关于perl中如何获取xml文件的指定内容,可以使用LibXML模块进行,该模块有强大的xpath匹配关系,可以很方便地获取想要的信息,整个模块使用说明,点击如下链接:
https://grantm...
在Linux是使用libxml2---从安装到使用
一、下载和安装LIBXML2
【方法一】
Libxml2是个C语言的XML程式库,能简单方便的提供对XML文件的各种操作,并且支持XPATH查询,及部分的支持XSLT转换等功能。Libxml2的下...
linux下的xml操作详解
1. 下载与安装LIBXML2
Libxml2是一个C语言的XML程序库,可以简单方便的提供对XML文档的各种操作,并且支持XPATH查询,以及部分的支持XSLT转换等功能。Libxml2的下载...
libxml2的安装及使用
本文着重介绍解析xml的libxml2库的安装及使用,举例说明创建和解析xml的过程。
一、libxml2的安装
  关于libxml2的介绍请参考官方网址http://xmlsoft.org/,...
1.实现功能:读取一个xml文件中的内容,节点等信息!
首先定义了一个test.xml文件,文件内容如下:
i still have lots t...
linux下,纯c++使用libxml2读取xml文件
下载libxml2
[url]ftp://ftp.xmlsoft.org/libxml2/libxml2-sources-2.7.1.tar...
没有更多推荐了,& & & &libxml是一个用于解析xml文件的库,在各个平台下都能使用,也支持多种语言,如c,等。这里是。上面有libxml的api和一些code examples,都是英文的。不过比较简单。
libxml的基础功能就是对xml的读和写。下面将简单介绍libxml的读的功能。(大部分内容是参照libxml tutorial 的文档)
0 编译程序
因为本人是在下用来介绍libxml的,所以使用了gcc编译器。其他的编译命令请参照官网。
我们知道,gcc 最简单的编译命令为gcc filename.c 。只要给这个命令添加头文件和链接库的地址就可以使用libxml。而libxml也提供了一个脚本xml2-config来配置这些地址。所以编译时将命令改为gcc filename.c `xml2-config --cflags --libs`即可。cflags在编译时提供头文件的地址,而libs在链接时提供库文件的地址。
1 分析文件--parse file
先简单介绍xml文件。
&?xml version="1.0" encoding="UTF-8"?&&root&&node1&content1&/node1&&node2 attribute="yes"&content2&/node2&&node3&&subnode&go&/subnode&&/node3&&/root&
上面是一个简单的xml文件。从文件中很容易就能看出整个文件的结构和要表达的意思。下面我会结合xml的基本类型介绍这个文件。
文件的第一行是xml文件的一些属性,可以看出编码方式是utf-8 。libxml只能处理uft-8 和 utf-16编码的文件,如果你的文件不是这两种编码,需要在使用前进行转换。
&root&&/root&是xml的一个节点,即xmlNode。而xmlNodePtr 表示指向xmlNode的指针--xmlNode*。&node1&&/node1&,&node2&&/node2&,&node3&&/node3&是这个node的子node,即xmlNodePtr-&children或xmlNodePtr-&xmlChildrenNode。所以&subnode&&/subnode&就是&node3&&/node3&的子node。
接下来就是解析文件了。
#include&&stdio.h&&&
#include&&string.h&&&
#include&&stdlib.h&&&
#include&&libxml/tree.h&&&
#include&&libxml/parser.h&&&
文件中需要包含这两个头文件。
xmlDocPtr&doc&=&NULL;&&
xmlNodePtr&node&=&NULL;&&
doc&=&xmlParseFile(filename);&&
if(NULL&&==&doc)&{&&
&&&&fprintf(stderr,&"parse&error\n");&&
&&&&exit(1);&&
xmlDocPtr 表示指向xmlDoc的指针。从tutorial中我们可以知道,xmlDoc是一个包含了已解析的文件生成的节点树的结构体。
node&=&xmlDocGetRootElement(doc);&&
if(NULL&==&node)&{&&
&&&&fprintf(stderr,&"doc&has&no&content\n");&&
&&&&xmlFreeDoc(doc);&&
&&&&exit(1);&&
xmlDocGetRootElement(doc)可以得到整个文件的根节点,所有的操作都是从根节点开始的。
现在我们已经有了一个包含这个节点树的结构体指针xmlDocPtr doc,有了一个可以操作节点的结构体指针xmlNodePtr node,我们就可以读取各个节点的信息了。
节点包含这么几个信息:
node-&name:节点的名字,如node1,node2,subnode等
node-&xmlChildrenNode:节点的子节点
node-&last:节点的最后一个子节点
node-&parent:节点的父节点
node-&next:节点的兄弟节点,对于node1来说,node2和node3都是其兄弟节点,node1的next指向node2
由于节点的内容是其子节点(对于node1,content1可以说是其子节点),所以我们需要使用xmlNodeGetContent来取出内容。
node&=&node-&xmlChildrenN&&
while(node&!=&NULL)&{&&
&&&&printf("name=%s&content=%s\n",&&
&&&&&&&&&&&&&&&node-&name,&&
&&&&&&&&&&&&&&&(char*)xmlNodeGetContent(node));&&
&&&&node=node-&&&
这是完整的源码。
#include&&stdio.h&&&
#include&&string.h&&&
#include&&stdlib.h&&&
#include&&libxml/parser.h&&&
static&int&&
parseDoc(char*&docname)&{&&
&&&&xmlDocPtr&&&
&&&&xmlNodePtr&&&
&&&&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;&&
&&&&if(xmlStrcmp(cur-&name,&(const&xmlChar*)"root"))&{&&
&&&&&&&&printf("end\n");&&
&&&&&&&&return&0;&&
&&&&cur&=&cur-&&&
&&&&while(cur&!=&NULL)&{&&
&&&&&&&&printf("name=%s&content=%s\n",cur-&name,&&&
&&&&&&&&&&&&&&&&(char*)xmlNodeGetContent(cur));&&
&&&&&&&&&&&&&&&&
&&&&&&&&cur&=&cur-&&&
&&&&xmlFreeDoc(doc);&&
&&&&return&0;&&
int&main()&{&&
&&&&char*&docname&=&"story.xml";&&
&&&&parseDoc(docname);&&
&&&&return&1;&&
编译链接后执行,会发现输出的结果如下:
name=text&content=&&
name=node1&content=content1&&
name=text&content=&&
name=node2&content=content2&&
name=text&content=&&
name=node3&content=&&
&&&&&&&&go&&
name=text&content=&&
这是因为libxml默认将各个节点间的空格当作一个节点,只要在调用xmlParseFile之前调用xmlKeepBlanksDefault(0)即可。
修改后结果如下:
name=node1&content=content1&&
name=node2&content=content2&&
name=node3&content=go&&
2 读取内存中的xml文档。
很多时候我们需要对内存中的xml文档进行操作。比如在网络编程的时候经常会从server那里接受一些客户端的配置信息,这些配置信息大部分都是使用xml语言描述的。在你将这些信息读入到buffer中后,你无需将他们写入文件当中再分析,直接可以调用xmlReadMemory函数就可以得到一个xmlDocPtr。这个函数接受五个参数,第一个参数为缓存区的指针,第二个参数为缓存区大小,其他参数具体看API文档。当然另外一个函数xmlReadDoc也能实现这样的功能。
static&char*&config&=&"&config&/&";&&
xmlDocPtr&doc&=&NULL;&&
xmlKeepBlanksDefault(0);&&
doc&=&xmlReadMemory(config,&strlen(config),&"in_memory.xml",&NULL,&0);&&
xmlFreeDoc(doc); &
阅读(...) 评论()

我要回帖

更多关于 xml编辑器汉化安卓版 的文章

 

随机推荐