[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"
", 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"
", 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
");  
 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
");  
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>  
View Code
原文地址:https://www.cnblogs.com/catgatp/p/8012740.html