指定xpath相对路径,删除xml文件里所有指定node节点

利用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)

参考博客:

https://blog.csdn.net/infoworld/article/details/8223927

发布了21 篇原创文章 · 获赞 5 · 访问量 2257

猜你喜欢

转载自blog.csdn.net/PTA123/article/details/103136548