1. 简介
Libxml是一个轻量级的XML解析库,广泛应用于Linux中。它在多种语言中都有可用的接口,例如C、C++、Python、Perl、Ruby等。Libxml是基于SAX和DOM两种模型设计的,用户可以根据自己的需求进行选择使用。下面将会重点讲解Libxml在C语言中的使用方法。
2. 安装
在Linux中,我们可以使用apt-get工具来安装libxml库:
sudo apt-get install libxml2-dev
安装完成后,我们就可以在C程序中使用libxml库了。
3. 基本用法
3.1 解析XML文件
解析XML文件是libxml的重要功能,下面是一个简单的XML文件:
<?xml version="1.0" encoding="UTF-8"?>
<book>
<title>Harry Potter</title>
<author>J.K. Rowling</author>
<year>1997</year>
</book>
接下来的代码展示了如何使用libxml解析上述XML文件:
#include <libxml/parser.h>
#include <libxml/tree.h>
int main() {
xmlDocPtr doc;
xmlNodePtr cur;
doc = xmlParseFile("example.xml");
if (doc == NULL) {
fprintf(stderr, "Failed to parse XML file");
return -1;
}
cur = xmlDocGetRootElement(doc);
if (cur == NULL) {
fprintf(stderr, "Failed to get root element");
xmlFreeDoc(doc);
return -1;
}
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if (xmlStrcmp(cur->name, (const xmlChar *) "title") == 0) {
char *title = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
printf("Title: %s\n", title);
xmlFree(title);
} else if (xmlStrcmp(cur->name, (const xmlChar *) "author") == 0) {
char *author = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
printf("Author: %s\n", author);
xmlFree(author);
} else if (xmlStrcmp(cur->name, (const xmlChar *) "year") == 0) {
char *year = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
printf("Year: %s\n", year);
xmlFree(year);
}
cur = cur->next;
}
xmlFreeDoc(doc);
return 0;
}
代码分析:
我们首先定义了一个xmlDocPtr类型的指针,表示XML文件的文档类型,以及xmlNodePtr类型的指针,表示XML文件的结构。
接下来,我们使用xmlParseFile函数从文件中解析XML文档。如果解析失败,会返回NULL。
使用xmlDocGetRootElement函数可以获取XML文档的根节点。如果获取失败,会返回NULL。
使用xmlChildrenNode遍历根节点的子节点。使用xmlStrcmp函数判断节点的标签名称是否为title、author或year。
使用xmlNodeListGetString函数获取节点的值,并打印输出。
最后,释放内存。
3.2 创建XML文件
使用libxml,我们也可以创建XML文件。下面是一个简单的例子:
#include <libxml/parser.h>
#include <libxml/tree.h>
int main() {
xmlDocPtr doc;
xmlNodePtr root, node, child;
doc = xmlNewDoc(BAD_CAST "1.0");
root = xmlNewNode(NULL, BAD_CAST "root");
xmlDocSetRootElement(doc, root);
node = xmlNewNode(NULL, BAD_CAST"node");
xmlNewProp(node, BAD_CAST "attribute", BAD_CAST "value");
xmlAddChild(root, node);
child = xmlNewText(BAD_CAST "content");
xmlAddChild(node, child);
xmlSaveFormatFileEnc("example.xml", doc, "UTF-8", 1);
xmlFreeDoc(doc);
return 0;
}
代码分析:
使用xmlNewDoc函数创建XML文档。
使用xmlNewNode函数创建根节点,并使用xmlDocSetRootElement函数将其设置为文档的根节点。
使用xmlNewNode创建子节点,并使用xmlNewProp函数添加属性。
使用xmlNewText创建子节点的值,并使用xmlAddChild将其作为子节点添加到父节点中。
最后,使用xmlSaveFormatFileEnc将文档保存为文件,并释放内存。
4. 高级用法
4.1 XPath
XPath是XML的一种查询语言,可以用来查找XML文档中的节点。在libxml中,我们可以使用xmlXPathEval函数来执行XPath查询。
下面的例子展示了如何使用XPath查询上述XML文件中的title节点的值:
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
int main() {
xmlDocPtr doc;
xmlXPathContextPtr xpathCtx;
xmlXPathObjectPtr xpathObj;
xmlChar *xpathExpr;
doc = xmlParseFile("example.xml");
if (doc == NULL) {
fprintf(stderr, "Failed to parse XML file");
return -1;
}
xpathCtx = xmlXPathNewContext(doc);
if (xpathCtx == NULL) {
fprintf(stderr, "Failed to create XPath context");
xmlFreeDoc(doc);
return -1;
}
xpathExpr = xmlCharStrdup("/book/title");
xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
if (xpathObj == NULL) {
fprintf(stderr, "Failed to evaluate XPath expression");
xmlXPathFreeContext(xpathCtx);
xmlFreeDoc(doc);
return -1;
}
xmlNodeSetPtr nodeset = xpathObj->nodesetval;
if (nodeset->nodeNr == 0) {
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
xmlFreeDoc(doc);
return -1;
}
xmlChar *title = xmlNodeListGetString(doc, nodeset->nodeTab[0]->xmlChildrenNode, 1);
printf("Title: %s\n", title);
xmlFree(title);
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
xmlFreeDoc(doc);
return 0;
}
代码分析:
使用xmlParseFile函数解析XML文件。
使用xmlXPathNewContext函数创建XPath上下文。可以在此上下文中执行XPath查询。
使用xmlCharStrdup函数创建XPath表达式,并使用xmlXPathEvalExpression函数执行查询。查询结果将保存在xmlXPathObjectPtr类型的指针中。
使用xmlNodeListGetString函数获取查询结果中节点的值,并打印输出。
最后,释放内存。
4.2 DOM
DOM(文档对象模型)是另一种XML模型,它将XML文档解析为一个具有层级结构的树形结构。在libxml中,我们可以使用xmlNode型指针代表这个树状结构中的一个节点。下面的例子展示了如何创建一个包含子节点的XML文档:
#include <libxml/parser.h>
#include <libxml/tree.h>
int main() {
xmlDocPtr doc;
xmlNodePtr root, node, child;
doc = xmlNewDoc(BAD_CAST "1.0");
root = xmlNewNode(NULL, BAD_CAST "root");
xmlDocSetRootElement(doc, root);
node = xmlNewNode(NULL, BAD_CAST"node");
xmlNewProp(node, BAD_CAST "attribute", BAD_CAST "value");
xmlAddChild(root, node);
child = xmlNewText(BAD_CAST "content");
xmlAddChild(node, child);
xmlSaveFormatFileEnc("example.xml", doc, "UTF-8", 1);
xmlFreeDoc(doc);
return 0;
}
代码分析:
使用xmlNewDoc函数创建XML文档。
使用xmlNewNode函数创建根节点,并使用xmlDocSetRootElement函数将其设置为文档的根节点。
使用xmlNewNode创建子节点,并使用xmlNewProp函数添加属性。
使用xmlNewText创建子节点的值,并使用xmlAddChild将其作为子节点添加到父节点中。
最后,使用xmlSaveFormatFileEnc将文档保存为文件,并释放内存。
4.3 SAX
SAX(简单API for XML)是另一种XML模型,它采用事件驱动的方式解析XML文档。在libxml中,我们可以使用xmlSAXHandler结构体来定义SAX事件的处理程序。下面是一个简单的例子,展示了如何使用SAX模型解析XML文件:
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xmlmemory.h>
#include <libxml/xmlsax.h>
void startElement(void *ctx, const xmlChar *name, const xmlChar **atts) {
for (int i = 0; atts[i]; i += 2) {
printf("%s=%s ", atts[i], atts[i+1]);
}
printf("<%s>", name);
}
void endElement(void *ctx, const xmlChar *name) {
printf("</%s>", name);
}
void characters(void *ctx, const xmlChar *ch, int len) {
printf("%.*s", len, ch);
}
xmlSAXHandler saxHandlerStruct =
{
NULL, /* internalSubset */
NULL, /* isStandalone */
NULL, /* hasInternalSubset */
NULL, /* hasExternalSubset */
NULL, /* resolveEntity */
NULL, /* getEntity */
NULL, /* entityDecl */
NULL, /* notationDecl */
NULL, /* attributeDecl */
NULL, /* elementDecl */
NULL, /* unparsedEntityDecl */
NULL, /* setDocumentLocator */
NULL, /* startDocument */
NULL, /* endDocument */
(void *) &startElement, /* startElement */
(void *) &endElement, /* endElement */
NULL, /* reference */
(void *) &characters, /* characters */
NULL, /* ignorableWhitespace */
NULL, /* processingInstruction */
NULL, /* comment */
NULL, /* warning */
NULL, /* error */
NULL, /* fatalError (errors raised during parsing) */
NULL, /* getParameterEntity */
NULL, /* cdataBlock */
NULL, /* externalSubset */
XML_SAX2_MAGIC, /* initialized */
NULL, /* private */
NULL, /* startElementNs */
NULL, /* endElementNs */
NULL /* xmlStructuredErrorFunc */
};
int main() {
xmlSAXHandlerPtr saxHandler = &saxHandlerStruct;
xmlParseFileWithSAX(saxHandler, NULL, "example.xml");
return 0;
}
代码分析:
定义了三个SAX事件的处理程序:startElement、endElement和characters。
定义了一个xmlSAXHandler结构体,包含了针对所有SAX事件的处理程序。
使用xmlSAXHandlerPtr类型的变量指向xmlSAXHandler结构体。
使用xmlParseFileWithSAX函数解析XML文件。
该函数将调用xmlSAXHandler结构体中的相关事件处理程序。
最后,释放内存。
5. 总结
本文介绍了libxml在Linux中的应用,包括基本用法和高级用法,涵盖了解析XML文件、创建XML文件、XPath、DOM和SAX等方面。这些技术都是XML的重要组成部分,掌握它们将使工作更加高效。