[libxml2]_[XML处理]_[使用libxml2的xpath特性修改xml文件内容]
场景:
1.在软件需要保存一些配置项时,使用数据库的话比较复杂,查看内容也不容易.纯文本文件对utf8字符支持也不好.
2.这时候使用xml是最佳选择,使用跨平台库libxml2。
3.基于xpath的保存方式对保存局部内容非常方便。
4.参考例子xpath2.c
1 #include <stdio.h> 2 #include <assert.h> 3 #include <string> 4 #include <iostream> 5 #include <map> 6 7 #include "libxml/tree.h" 8 #include "libxml/parser.h" 9 #include "libxml/xpath.h" 10 #include "libxml/xpathInternals.h" 11 #include "libxml/xmlsave.h" 12 13 using namespace std; 14 15 static void _UpdateXpathNodes(xmlNodeSetPtr nodes, const xmlChar* value) 16 { 17 int size; 18 int i; 19 20 assert(value); 21 size = (nodes) ? nodes->nodeNr : 0; 22 for(i = size - 1; i >= 0; i--) 23 { 24 assert(nodes->nodeTab[i]); 25 xmlNodeSetContent(nodes->nodeTab[i], value); 26 if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) 27 { 28 nodes->nodeTab[i] = NULL; 29 } 30 } 31 } 32 33 static int _UpdateWithXpath(xmlXPathContextPtr xpathCtx,const char* key,const char* value) 34 { 35 xmlXPathObjectPtr xpathObj; 36 37 xpathObj = xmlXPathEvalExpression(BAD_CAST key, xpathCtx); 38 if(!xpathObj) 39 { 40 fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", key); 41 return -1; 42 } 43 _UpdateXpathNodes(xpathObj->nodesetval, BAD_CAST value); 44 xmlXPathFreeObject(xpathObj); 45 return 0; 46 } 47 48 static int _UpdateXml(const char* path,map<string,string>& keyValue) 49 { 50 xmlDocPtr doc; 51 xmlXPathContextPtr xpathCtx; 52 doc = xmlParseFile(path); 53 if (!doc) 54 { 55 fprintf(stderr, "Error: unable to parse file \"%s\"\n", path); 56 return(-1); 57 } 58 59 /* Create xpath evaluation context */ 60 xpathCtx = xmlXPathNewContext(doc); 61 //1.注意,这里根Node有声明xmlns,那么必须加下边这句,相应的xpath要加前缀 /c:container/c:rootfiles 62 //xmlXPathRegisterNs(xpathCtx,BAD_CAST"c",BAD_CAST"urn:oasis:names:tc:opendocument:xmlns:container"); 63 if(!xpathCtx) 64 { 65 fprintf(stderr,"Error: unable to create new XPath context\n"); 66 xmlFreeDoc(doc); 67 return(-1); 68 } 69 //3.update 70 map<string,string>::iterator iter; 71 map<string,string>::iterator end = keyValue.end(); 72 for(iter = keyValue.begin();iter!= end;iter++) 73 { 74 cout << "word: " << iter->first << ", count: " << iter->second << endl; 75 _UpdateWithXpath(xpathCtx,iter->first.c_str(),iter->second.c_str()); 76 } 77 78 xmlXPathFreeContext(xpathCtx); 79 //4.save 80 xmlSaveCtxtPtr saveCtxtPtx = xmlSaveToFilename(path,"UTF-8",XML_SAVE_FORMAT); 81 if(!saveCtxtPtx) 82 { 83 xmlFreeDoc(doc); 84 return -1; 85 } 86 87 if(-1 == xmlSaveDoc(saveCtxtPtx,doc)) 88 { 89 xmlFreeDoc(doc); 90 return -1; 91 } 92 xmlSaveClose(saveCtxtPtx); 93 //xmlDocDump(stdout, doc); 94 //5.free 95 xmlFreeDoc(doc); 96 return 0; 97 } 98 99 int UpdateXml(const char* path,map<string,string>& keyValue) 100 { 101 /* Init libxml */ 102 xmlInitParser(); 103 int res = _UpdateXml(path,keyValue); 104 xmlCleanupParser(); 105 return res; 106 } 107 108 int main(int argc, char *argv[]) 109 { 110 printf("Hello, world\n"); 111 map<string,string> m; 112 m["/doc/parent/discarded/@info"] = string("info attri"); 113 m["/doc/parent/discarded[2]"] = string("change second discarded text 中文"); 114 int ret = UpdateXml("xpath2.res",m); 115 assert(!ret); 116 ret = UpdateXml("xpath2.res",m); 117 assert(!ret); 118 ret = UpdateXml("xpath2.res",m); 119 assert(!ret); 120 return 0; 121 }
xpath2.res
<?xml version="1.0" encoding="UTF-8"?> <doc> <parent> <discarded info="test">discarded</discarded> <preserved/> This text node must be discarded <discarded>test</discarded> <preserved> content1 <child1/> <child2>content2</child2> <preserved>too</preserved> <child2>content3</child2> <preserved/> <child2>content4</child2> <preserved/> <child2>content5</child2> content6 </preserved> </parent> </doc>
xpath2.res
<?xml version="1.0" encoding="UTF-8"?> <doc> <parent> <discarded info="info attri">discarded</discarded> <preserved/> This text node must be discarded <discarded>change second discarded text 中文</discarded> <preserved> content1 <child1/> <child2>content2</child2> <preserved>too</preserved> <child2>content3</child2> <preserved/> <child2>content4</child2> <preserved/> <child2>content5</child2> content6 </preserved> </parent> </doc>