利用C libxml2的库。需要删除掉xml中某些节点,但我又不想从根节点开始去找。想到了用xpath来找xml的节点,然后参考官方的XPath example(xpath2.c)附上链接http://www.xmlsoft.org/examples/index.html。官方例子只有set node的,没有delete的。改了一下发现能用,用valgrind工具检查内存也通过了。
#include <stdio.h>
#include <assert.h>
#include <string>
#include <iostream>
#include <map>
#include "libxml/tree.h"
#include "libxml/parser.h"
#include "libxml/xpath.h"
#include "libxml/xpathInternals.h"
#include "libxml/xmlsave.h"
using namespace std;
map<int, xmlNodePtr> m;//用来存放要删除的节点
static void deleteXpathNodes(xmlNodeSetPtr nodes)
{
int size;
int i;
size = (nodes) ? nodes->nodeNr : 0;
for(i = size - 1; i >= 0; i--)
{
assert(nodes->nodeTab[i]);
m[i]=nodes->nodeTab[i];
//这里先把node节点的路径先存起来。不能直接在这里把节点删除释放掉,要在释放完xmlXPathObjectPtr xpathObj
//才能调用xmlUnlinkNode(); xmlFreeNode();
//如果直接在这里释放掉节点,用valgrind工具检查内存,会报错。
}
}
static int updateWithXpath(xmlXPathContextPtr xpathCtx, const char* key)
{
xmlXPathObjectPtr xpathObj;
xpathObj = xmlXPathEvalExpression(BAD_CAST key, xpathCtx);//计算xpath表达式
if(!xpathObj)
{
fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", key);
return -1;
}
deleteXpathNodes(xpathObj->nodesetval);
if(xpathObj != NULL)
{
xmlXPathFreeObject(xpathObj);
}
map<int,xmlNodePtr>::iterator iter;
for(iter = m.begin();iter!= m.end();iter++)//在这里释放节点
{
xmlUnlinkNode(iter->second);
xmlFreeNode(iter->second);
}
return 0;
}
static int _updateXml(const char* path, const char* key)
{
xmlDocPtr doc;
xmlXPathContextPtr xpathCtx;
//读取xml文件,删除空格行
doc = xmlReadFile(path, NULL, XML_PARSE_NOBLANKS);
if (!doc)
{
fprintf(stderr, "Error: unable to parse file \"%s\"\n", path);
return(-1);
}
/* Create xpath evaluation context */
xpathCtx = xmlXPathNewContext(doc);
//1.注意,这里根Node有声明xmlns,那么必须加下边这句,相应的xpath要加前缀 /c:container/c:rootfiles
//xmlXPathRegisterNs(xpathCtx,BAD_CAST"c",BAD_CAST"urn:oasis:names:tc:opendocument:xmlns:container");
if(xpathCtx==NULL)
{
fprintf(stderr,"Error: unable to create new XPath context\n");
xmlFreeDoc(doc);
return(-1);
}
//3.update
updateWithXpath(xpathCtx, key);
xmlXPathFreeContext(xpathCtx);
//4.save
xmlSaveCtxtPtr saveCtxtPtx = xmlSaveToFilename(path,"UTF-8",XML_SAVE_FORMAT);
if(!saveCtxtPtx)
{
xmlFreeDoc(doc);
return -1;
}
if(-1 == xmlSaveDoc(saveCtxtPtx,doc))
{
xmlFreeDoc(doc);
return -1;
}
xmlSaveClose(saveCtxtPtx);
//xmlDocDump(stdout, doc);
//5.free
xmlFreeDoc(doc);
return 0;
}
int updateXml(const char* path,const char* key)
{
/* Init libxml */
xmlInitParser();
int res = _updateXml(path, key);
xmlCleanupParser();
return res;
}
int main(int argc, char *argv[])
{
printf("Hello, world\n");
int ret = updateXml(argv[1], "//child2");//argv[1]是xml文件路径,"//child2"是xpath相对路径,这里可以删除所有child2节点。
assert(!ret);
return 0;
}
以下是xml文件test.xml
我要删除所有的child2节点包括它的子节点
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<parent>
<discarded info="info attri">discarded</discarded>
<discarded>change second discarded text</discarded>
<preserved>
<child2 id="1">
<qq>11</qq>
</child2>
<preserved2>too</preserved2>
<child2 id="2">
<qq>11</qq>
</child2>
<child2 id="3">
<qq>11</qq>
</child2>
<child2 id="4">
<qq>11</qq>
</child2>
<child2 id="5">
<qq>11</qq>
</child2>
<child2 id="6">
<qq>11</qq>
</child2>
</preserved>
</parent>
</doc>
运行后的xml文件
删除了child2节点以及它们的子节点
<?xml version="1.0" encoding="UTF-8"?>
<doc>
<parent>
<discarded info="info attri">discarded</discarded>
<discarded>change second discarded text</discarded>
<preserved>
<preserved2>too</preserved2>
</preserved>
</parent>
</doc>
通过valgrind检测内存泄漏情况,0 error
==5342== Memcheck, a memory error detector
==5342== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5342== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==5342== Command: ./xmldemo /localdisk/view_store/cmakedemo/src/test.xml
==5342== Parent PID: 3024
==5342==
==5342==
==5342== HEAP SUMMARY:
==5342== in use at exit: 0 bytes in 0 blocks
==5342== total heap usage: 173 allocs, 173 frees, 79,143 bytes allocated
==5342==
==5342== All heap blocks were freed -- no leaks are possible
==5342==
==5342== For lists of detected and suppressed errors, rerun with: -s
==5342== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
参考博客: