[libxml2]_[XML处理]_[使用libxml2的xpath特性修改xml文件内容]


场景:

1.在软件需要保存一些配置项时,使用数据库的话比较复杂,查看内容也不容易.纯文本文件对utf8字符支持也不好.

2.这时候使用xml是最佳选择,使用跨平台库libxml2。

3.基于xpath的保存方式对保存局部内容非常方便。

4.参考例子xpath2.c

5.实际耗时: 2小时.


文件1: Makefile

CP="cp"

build-post: test.exe
	${CP} E:/software/Lib/file/xml-libxml2-2.7.1/win32/release/share/libxml2-2.dll .

test.exe:test.o
	g++ -o test.exe test.o -LE:/software/Lib/file/xml-libxml2-2.7.1/win32/release/share -lxml2

test.o:test.cpp
	g++ -IE:/software/Lib/file/xml-libxml2-2.7.1/win32/release/share/include -c test.cpp -o test.o


文件2:test.cpp

#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;

static void _UpdateXpathNodes(xmlNodeSetPtr nodes, const xmlChar* value) 
{
    int size;
    int i;
    
    assert(value);
    size = (nodes) ? nodes->nodeNr : 0;
    for(i = size - 1; i >= 0; i--) 
	{
		assert(nodes->nodeTab[i]);
		xmlNodeSetContent(nodes->nodeTab[i], value);
		if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL)
		{
			nodes->nodeTab[i] = NULL;
		}
   }
}

static int _UpdateWithXpath(xmlXPathContextPtr xpathCtx,const char* key,const char* value)
{
	xmlXPathObjectPtr xpathObj;
    
	xpathObj = xmlXPathEvalExpression(BAD_CAST key, xpathCtx);
    if(!xpathObj)
	{
        fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", key);
        return -1;
    }
    _UpdateXpathNodes(xpathObj->nodesetval, BAD_CAST value);
    xmlXPathFreeObject(xpathObj);
	return 0;
}

static int _UpdateXml(const char* path,map<string,string>& keyValue)
{
	xmlDocPtr doc;
	xmlXPathContextPtr xpathCtx; 
	doc = xmlParseFile(path);
    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)
	{
        fprintf(stderr,"Error: unable to create new XPath context\n");
        xmlFreeDoc(doc); 
        return(-1);
    }
	//3.update
	map<string,string>::iterator iter;
	map<string,string>::iterator end = keyValue.end();
	for(iter = keyValue.begin();iter!= end;iter++)
	{
		cout << "word: " << iter->first << ", count: " << iter->second << endl;
		_UpdateWithXpath(xpathCtx,iter->first.c_str(),iter->second.c_str());
	}
	
	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,map<string,string>& keyValue)
{
	/* Init libxml */     
    xmlInitParser();
	int res  = _UpdateXml(path,keyValue);
	xmlCleanupParser();
	return res;
}

int main(int argc, char *argv[])
{
	printf("Hello, world\n");
	map<string,string> m;
	m["/doc/parent/discarded/@info"] = string("info attri");
	m["/doc/parent/discarded[2]"] = string("change second discarded text 中文");
	int ret = UpdateXml("xpath2.res",m);
	assert(!ret);
	ret = UpdateXml("xpath2.res",m);
	assert(!ret);
	ret = UpdateXml("xpath2.res",m);
	assert(!ret);
	return 0;
}


文件3: 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>


文件4:修改后的 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>





  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Peter(阿斯拉达)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值