参考文献:Libxml Tutorial
数据类型:
Libxml声明了很多数据类型:
xmlChar:是对char类型的替代,其为一个字节的UTF-8编码字符。如果你的数据使用其他的编码,必须转换为UTF-8才能提供给libxml的函数使用。
xmlDoc:包含由解析的doc创建的树的结构体。xmlDocPtr是指向该结构的指针。
xmlNodePtr 和 xmlNode:包含单个结点的结构。xmlNodePtr是指向该结构的指针,用来遍历文档树。
解析文件:
只需要文件名和单一的函数调用就可以解析文件并实现错误检测。完整代码参见:Code for Keyword Example
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;
}
查询元素内容:
查询元素的内容涉及到遍历文档树知道找到需要的内容。在这个例子中,我们将需找在"story"元素中名称为"keyword"的元素。假设已经有称为doc的xmlDocPtr,和称为cur的xmlNodePtr。
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。
xmlChar *key;
cur = cur->xmlChildrenNode;
while (cur!=NULL){
if((!xmlStrcmp(cur->name, (const xmlChar *)"keyboard"))){
key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
printf("keyword: %s\n", key);
xmlFree(key);
}
cur = cur->mext;
}
首先得到第一个孩子结点。
迭代所有结点,寻找匹配元素,在本例中是"keyword"
找到keyword元素后,打印出他的内容。谨记,在XML中,元素中包含的文本是该元素的孩子结点,所有我们使用cur->xmlChildrenNode.为了查询它,我们使用函数xmlNodeListGetString,该函数把doc作为一个参数。
提示:由于xmlNodeListGetString为返回的字符串分配内存,所有必须使用xmlFree释放它。
使用XPath来查询元素内容:
除了遍历文档树来寻找元素外,Libxml2包含XPath表达式支持来查询匹配指定匹配的一些列结点。
XPath允许查询整个文档来寻找指定文本的匹配。在下面的例子中,我们查询整个文档来寻找keyword元素的内容。
使用XPath需要建立一个xmlXPathContext然后提供XPath表达式和内容给xmlXPathEvalExpression函数。这个函数返回一个XPathObjectPtr,其中包含满足XPath表达式的结点集合。
xmlXPathObjectPtr
getnodeset (xmlDocPtr doc, xmlChar *xpath){
xmlXPathContextPtr context;
xmlXPathObjectPtr result;
context = xmlXPathNewContext(doc);
result = xmlXPathEvalExpression(xpath, context);
if(xmlXPathNdeSetIsEmpty(result->nodesetval)){
xmlXPathFreeObject(result);
printf("No result\n");
return NULL;
首先定义变量context;
然后初始化context变量;
使用XPath表达式;
检查result并且释放内存。
函数返回的xmlPathObjectPtr包含结点集合和用来迭代结合的其他的信息。对于本例,返回xmlXPathObjectPtr。我们使用它来打印keyword结点的内容。结点集合对象包括该集合中元素数目(nodeNr)和结点数组(nodeTab);
for(i = 0; i < nodeset->nodeNr; i++){
keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i]->xmlChildrenNode, 1);
printf("keyword: %s\n", keyword);
xmlFree(keyword);
}
写元素内容:
写元素内容采用和上面类似的步骤:解析文档、遍历树。解析文档,遍历树找到我们要插入文档的点。在下面的例子中,我们寻找”storyinfo“元素,并且插入一个keyword。然后将文件写入到磁盘。
void parseStory(xmlDocPtr doc, xmlNodePtr cur, char *keyword){
xmlNewTextChild(cur, NULL, "keyword", keyword);
return;
}
xmlNewTextChild函数增加新的孩子元素。
添加完元素,我们希望将文档写入文件。你是否想添加命名空间,你可以在这里添加它。在我们的例子中,命名空间是NULL。
xmlSaveFormatFile(docname, doc, 1);
第一个参数是文件的名字。
写入属性:
写入属性类似于写入文本。在下面例子中,我们添加一个引用URI 到我们的文档。
一个引用是story元素的孩子,所以查找防止新元素和属性的地方很简单。
xmlAttrPtr newattr;
我们另外需要一个额外的xmlNodePtr:
xmlNodePtr newnode;
newnode = xmlNewTextChild(cur, NULL, "reference", NULL);
newattr = xmlNewProp(newnode, "uri",uri);
使用xmlNewTextChild函数我们添加一个新节点。
查询属性:
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;
}
编码转换:
libxml存储和操作的数据用UTF-8格式编码。使用其他编码格式的数据需要转换到UTF-8,然后传入libxml函数。如果你想要将程序输出为其他格式,而不是UTF-8,你必须转换它。
libxml使用iconv转换数据。如果没有iconv,只有UTF-8, UTF-16和ISO-8859-1可以作为外部格式使用。使用iconv,任何格式可以被转化为UTF-8,或从UTF-8转化为任何格式。目前iconv支持超过150种不同的字符格式。
本例创建一个简单的文档,然后添加内容,内容由命令行提供到文档根元素,然后使用适当的编码输出结构到stdout。在这个例子中,我们使用ISO-8859-1编码。
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)
简单的例子:
1 <?xml version="1.0"?>
2 <story>
3 <storyinfo>
4 <author>John Fleck</author>
5 <datewritten>June 2, 2002</datewritten>
6 <keyword>example keyword</keyword>
7 </storyinfo>
8 <body>
9 <headline>This is the headline</headline>
10 <para>This is the body text.</para>
11 </body>
12 </story>
Code for Keyword Example:
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <libxml/xmlmemory.h>
5 #include <libxml/parser.h>
6
7 void
8 parseStory(xmlDocPtr doc, xmlNodePtr cur){
9 xmlChar *key;
10 cur = cur->xmlChildrenNode;
11 while(cur != NULL){
12 if((!xmlStrcmp(cur->name, (const xmlChar *)"keyword"))){
13 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
14 printf("keyword: %s\n", key);
15 xmlFree(key);
16 }
17 cur = cur->next;
18 }
19 return;
20 }
21
22 static void
23 parseDoc(char *docname){
24 xmlDocPtr doc;
25 xmlNodePtr cur;
26
27 doc = xmlParseFile(docname);
28
29 if(doc == NULL){
30 fprintf(stderr, "Document not parsed successfully.\n");
31 return;
32 }
33
34 cur = xmlDocGetRootElement(doc);
35
36 if(cur == NULL){
37 fprintf(stderr, "empty document\n");
38 xmlFreeDoc(doc);
39 return;
40 }
41
42 if(xmlStrcmp(cur->name, (const xmlChar *)"story")){
43 fprintf(stderr, "document of the wrong type, root node != story\n");
44 xmlFreeDoc(doc);
45 return;
46 }
47
48 cur = cur->xmlChildrenNode;
49 while(cur != NULL){
50 if((!xmlStrcmp(cur->name, (const xmlChar *)"storyinfo"))){
51 parseStory(doc, cur);
52 }
53 cur = cur->next;
54 }
55 xmlFreeDoc(doc);
56 return;
57 }
58
59 int
60 main(int argc, char **argv){
61 char *docname;
62 if(argc <= 1){
63 printf("Usage: %s docname\n", argv[0]);
64 return 0;
65 }
66 docname = argv[1];
67 parseDoc(docname);
68 return 1;
69 }
Code for XPath Example:
1 #include <libxml/parser.h>
2 #include <libxml/xpath.h>
3
4 xmlDocPtr
5 getdoc(char *docname){
6 xmlDocPtr doc;
7 doc = xmlParseFile(docname);
8 if(doc == NULL){
9 fprintf(stderr, "Document not parsed successfully.\n");
10 return NULL;
11 }
12 return doc;
13 }
14
15 xmlXPathObjectPtr
16 getnodeset(xmlDocPtr doc, xmlChar *xpath){
17 xmlXPathContextPtr context;
18 xmlXpathObjectPtr result;
19
20 context = xmlXPathNewContext(doc);
21 if(context == NULL){
22 printf("Error in xmlXPathNewContext\n");
23 return NULL;
24 }
25 result = xmlXPathEvalExpression(xpath, context);
26 xmlXPathFreeContext(context);
27 if(result == NULL){
28 printf("Error in xmlXPathEvalExpression\n");
29 return NULL;
30 }
31 if(xmlXPathNodeSetIsEmpty(result->nodesetval)){
32 xmlXPathFreeObject(result);
33 printf("No result\n");
34 return NULL;
35 }
36 return result;
37 }
38 int
39 main(int argc, char **argv){
40 char *docname;
41 xmlDocPtr doc;
42 xmlChar *xpath = (xmlChar *) "//keyword";
43 xmlNodeSetPtr nodeset;
44 xmlXPathObjectPtr result;
45 int i;
46 xmlChar *keyword;
47 if(argc <= 1){
48 printf("Usage: %s docname\n", argv[0]);
49 return 0;
50 }
51 docname = argv[1];
52 doc = getdoc(docname);
53 result = getnodeset(doc, xpath);
54 if(result){
55 nodeset = result->nodesetval;
56 for(i = 0; i < nodeset->nodeNr; i++){
57 keyword = xmlNodeListGetString(doc, nodeset->nodeTab[i], 1);
58 printf("keyword: %s\n", keyword);
59 xmlFree(keyword);
60 }
61 xmlXPathFreeObject(result);
62 }
63 xmlFreeDoc(doc);
64 xmlCleanupParser();
65 return 1;
66 }
Code for Add Keyword Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
void
parseStory (xmlDocPtr doc, xmlNodePtr cur, char *keyword) {
xmlNewTextChild (cur, NULL, "keyword", keyword);
return;
}
xmlDocPtr
parseDoc(char *docname, char *keyword) {
xmlDocPtr doc;
xmlNodePtr cur;
doc = xmlParseFile(docname);
if (doc == NULL ) {
fprintf(stderr,"Document not parsed successfully. \n");
return (NULL);
}
cur = xmlDocGetRootElement(doc);
if (cur == NULL) {
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return (NULL);
}
if (xmlStrcmp(cur->name, (const xmlChar *) "story")) {
fprintf(stderr,"document of the wrong type, root node != story");
xmlFreeDoc(doc);
return (NULL);
}
cur = cur->xmlChildrenNode;
while (cur != NULL) {
if ((!xmlStrcmp(cur->name, (const xmlChar *)"storyinfo"))){
parseStory (doc, cur, keyword);
}
cur = cur->next;
}
return(doc);
}
int
main(int argc, char **argv) {
char *docname;
char *keyword;
xmlDocPtr doc;
if (argc <= 2) {
printf("Usage: %s docname, keyword\n", argv[0]);
return(0);
}
docname = argv[1];
keyword = argv[2];
doc = parseDoc (docname, keyword);
if (doc != NULL) {
xmlSaveFormatFile (docname, doc, 0);
xmlFreeDoc(doc);
}
return (1);
}
Code for Add Attribute Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
xmlDocPtr
parseDoc(char *docname, char *uri) {
xmlDocPtr doc;
xmlNodePtr cur;
xmlNodePtr newnode;
xmlAttrPtr newattr;
doc = xmlParseFile(docname);
if (doc == NULL ) {
fprintf(stderr,"Document not parsed successfully. \n");
return (NULL);
}
cur = xmlDocGetRootElement(doc);
if (cur == NULL) {
fprintf(stderr,"empty document\n");
xmlFreeDoc(doc);
return (NULL);
}
if (xmlStrcmp(cur->name, (const xmlChar *) "story")) {
fprintf(stderr,"document of the wrong type, root node != story");
xmlFreeDoc(doc);
return (NULL);
}
newnode = xmlNewTextChild (cur, NULL, "reference", NULL);
newattr = xmlNewProp (newnode, "uri", uri);
return(doc);
}
int
main(int argc, char **argv) {
char *docname;
char *uri;
xmlDocPtr doc;
if (argc <= 2) {
printf("Usage: %s docname, uri\n", argv[0]);
return(0);
}
docname = argv[1];
uri = argv[2];
doc = parseDoc (docname, uri);
if (doc != NULL) {
xmlSaveFormatFile (docname, doc, 1);
xmlFreeDoc(doc);
}
return (1);
}
Code for Retrieving Attribute Value Example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
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;
}
void
parseDoc(char *docname) {
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;
}
getReference (doc, cur);
xmlFreeDoc(doc);
return;
}
int
main(int argc, char **argv) {
char *docname;
if (argc <= 1) {
printf("Usage: %s docname\n", argv[0]);
return(0);
}
docname = argv[1];
parseDoc (docname);
return (1);
}
Code for Encoding Conversion Example:
#include <string.h>
#include <libxml/parser.h>
unsigned char*
convert (unsigned char *in, char *encoding)
{
unsigned char *out;
int ret,size,out_size,temp;
xmlCharEncodingHandlerPtr handler;
size = (int)strlen(in)+1;
out_size = size*2-1;
out = malloc((size_t)out_size);
if (out) {
handler = xmlFindCharEncodingHandler(encoding);
if (!handler) {
free(out);
out = NULL;
}
}
if (out) {
temp=size-1;
ret = handler->input(out, &out_size, in, &temp);
if (ret || temp-size+1) {
if (ret) {
printf("conversion wasn't successful.\n");
} else {
printf("conversion wasn't successful. converted: }
free(out);
out = NULL;
} else {
out = realloc(out,out_size+1);
out[out_size]=0; /*null terminating out*/
}
} else {
printf("no mem\n");
}
return (out);
}
int
main(int argc, char **argv) {
unsigned char *content, *out;
xmlDocPtr doc;
xmlNodePtr rootnode;
char *encoding = "ISO-8859-1";
if (argc <= 1) {
printf("Usage: %s content\n", argv[0]);
return(0);
}
content = argv[1];
out = convert(content, encoding);
doc = xmlNewDoc ("1.0");
rootnode = xmlNewDocNode(doc, NULL, (const xmlChar*)"root", out);
xmlDocSetRootElement(doc, rootnode);
xmlSaveFormatFileEnc("-", doc, encoding, 1);
return (1);
}