关于 使用rapidxml 开源库解析 XML 的使用,可以参考 http://blog.csdn.net/tangyin025/article/details/6175720,下面是我在解析XML之后,对满足条件的节点进行删除的实现。
程序很简单也很粗糙,请勿深究:
1.在QT中建立一个console工程,并新建头文件,在里面包含 rapidxml ,并声明一些必要的变量,如下所以:
#ifndef MAIN_H
#define MAIN_H
#include <QtCore/QCoreApplication>
#include <iostream> //系统输入输出
#include <QDebug> //调试输出
#include <QTextStream> //输入输出
#include <QTextCodec> //中文
#include <QByteArray>
#include <QFile>
#include <QVector>
#include "rapidxml/rapidxml.hpp"
//#include "rapidxml/rapidxml_iterators.hpp"
#include "rapidxml/rapidxml_print.hpp"
#include "rapidxml/rapidxml_utils.hpp"
QTextStream in(stdin);
QTextStream out(stdout);
enum { Delete_enum = 0, Filename_enum, Node_enum, Attribute_enum};
typedef struct nodeattribute
{
QString node;
QString attribute;
}NodeAttribute;
NodeAttribute Node_Attribute;
QVector<NodeAttribute> QV_Node_Attribute;
rapidxml::xml_node<>* root; //根节点
rapidxml::xml_node<>* node_Now; //当前节点
rapidxml::xml_node<>* node_Parent; //父节点 必定存在
rapidxml::xml_node<>* node_Previous ; //可能存在的前节点
rapidxml::xml_node<>* node_Next; //可能存在的后节点
void Parse_file(QString & filename);
bool ReadConfig(QString & Patch);
void Cycle_Check(QVector<NodeAttribute>::iterator it_node_, rapidxml::xml_node<>* node_Now_);
void Find_Next_Node(rapidxml::xml_node<>* node_Parent_);
bool Node_Wildcard_Flag;
bool Attribute_Wildcard_Flag;
bool Parse_Flag;
bool Find_Flag;
QString FileData;
#endif // MAIN_H
2.在main函数中,先用 bool ReadConfig(QString & Patch) 函数对配置文件进行读取,并解析配置文件, bool ReadConfig(QString & Patch) 实现如下所示:
bool ReadConfig(QString & Patch)
{
QFile file(Patch);
if(!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
qDebug()<<"Can't open the file!"<<endl;
return false;
}
FileData = file.readAll();
qDebug()<<"Config is :";
qDebug()<< FileData;
return true;
}
3.解析配置文件后,根据配置进行处理,具体实现如下main函数所示:
int main(int argc, char *argv[])
{
// QCoreApplication a(argc, argv);
QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); //允许使用中文
QString Patch_ = "./XML_D_Config";
if(!ReadConfig(Patch_))
{
return 0;
}
else
{
unsigned char times = (FileData.count(','))/2 + 1; //确定配置中的删除组数
//enum { Delete_enum = 0, Filename_enum, Node_enum, Attribute_enum};
//----------------------------------------------------------//
QString Delete = FileData.section(';', Delete_enum, Delete_enum);
Delete = Delete.section(':', -1); //判断是否启用本软件
bool ok;
int Delete_number = Delete.toInt(&ok, 10);
if(ok == true && Delete_number == 0)
{
qDebug()<<"Disable XML_Delete!"<<endl;
return 0;
}
//----------------------------------------------------------//
QString FileName = FileData.section(';', Filename_enum, Filename_enum);
QString Line_Node = FileData.section(';', Node_enum, Node_enum);
QString Line_Attribute = FileData.section(';', Attribute_enum, Attribute_enum);
FileName = FileName.section(':', -1); //文件名
Line_Node = Line_Node.section(':', -1); //节点名
Line_Attribute = Line_Attribute.section(':', -1); //属性名
QV_Node_Attribute.clear();
for(unsigned char i = 0; i<times;i++)
{
Node_Attribute.node = (Line_Node.section(',', i, i)).trimmed();
Node_Attribute.attribute = (Line_Attribute.section(',', i, i)).trimmed();
QV_Node_Attribute.push_back(Node_Attribute);
}
if(times == 1 && QV_Node_Attribute.at(times - 1).node == "")
{
qDebug()<<"Can't find the node!"<<endl;
return 0;
}
Parse_Flag = false;
Find_Flag = false;
Parse_file(FileName);
if(Parse_Flag == true)
{
Parse_Flag = false;
out<<"Success!"<<endl;
}
else
{
out<<"Failure!"<<endl;
}
}
return 0;
//return a.exec();
}
4.void Parse_file(QString &filename)函数的功能则是解析XML文件,并根据配置文件进行处理,具体实现如下所示:
void Parse_file(QString &filename)
{
QByteArray c_str = filename.toLatin1();
const char * file_name = c_str.data();
rapidxml::file <> fdoc(file_name);
rapidxml::xml_document<> doc;
doc.parse<0x20>(fdoc.data()); //解析后,doc中有XML的头信息
//! 获取根节点
//root = doc.first_node(); //空 因为前面解析了申明,所以第一个节点名是空,值是申明内容
root = doc.last_node(); //SCL
if(root == 0)
{
qDebug()<<"No node!"<<endl;
return ;
}
for(QVector<NodeAttribute>::iterator it_node = QV_Node_Attribute.begin(); it_node != QV_Node_Attribute.end(); it_node++)
{
node_Now = root->first_node(); //目标节点
node_Parent = node_Now->parent(); //父节点 必定存在
node_Previous = node_Now->previous_sibling(); //可能存在的前节点
node_Next = node_Now->next_sibling(); //可能存在的后节点
if((QString)root->name() == it_node->node) //如果存在与根节点匹配项,则全部删除并返回成功
{
root->remove_all_nodes();
break ;
}
//===================判断目标节点和属性是否带通配符=========================//
Node_Wildcard_Flag = false;
Attribute_Wildcard_Flag = false;
int leng_node = (it_node->node).size();
int leng_attribute = (it_node->attribute).size();
if(leng_node == 1 && (it_node->node)[leng_node - 1] == '*') //节点名称是通配符,则全部删除
{
root->remove_all_nodes();
break ;
}
else if(leng_node > 1 && (it_node->node).data()[leng_node - 1] == '*') //节点名称带通配符
{
Node_Wildcard_Flag = true;
(it_node->node).remove(leng_node - 1, 1); //删除通配符
}
if(leng_attribute >1 && (it_node->attribute).data()[leng_attribute - 1] == '*') //属性值带通配符
{
Attribute_Wildcard_Flag = true;
(it_node->attribute).remove(leng_attribute - 1, 1); //删除通配符
}
//======================================================================//
while(node_Now != 0)
{
Cycle_Check(it_node, node_Now);
}
}
//! 修改之后再次保存
std::ofstream out(file_name);
out << doc;
out.close();
Parse_Flag = true;
}
5.void Cycle_Check(QVector<NodeAttribute>::iterator it_node_, rapidxml::xml_node<>* node_Now_)则是具体的比较和删除操作,其实现为:
void Cycle_Check(QVector<NodeAttribute>::iterator it_node_, rapidxml::xml_node<>* node_Now_)
{
if((QString)node_Now_->name() == it_node_->node || //如果当前节点等于目标节点
(Node_Wildcard_Flag == true && ((QString)node_Now_->name()).startsWith(it_node_->node) == true)) //目标节点带通配符且当前节点是以目标节点给定的值相等
{
if(it_node_->attribute == "" || (QString)node_Now_->first_attribute()->value() == it_node_->attribute ||
(Attribute_Wildcard_Flag == true && ((QString)node_Now_->first_attribute()->value()).startsWith(it_node_->attribute) == true)) //目标节点的属性带通配符且当前节点的属性是以目标节点的属性给定的值相等
{
qDebug() << "Delete: node.name = " << (QString)node_Now_->name() << "、first attribute.value = " << (QString)node_Now_->first_attribute()->value() <<endl;
node_Parent->remove_node(node_Now_);
}
else //直接下一个节点
{
}
if(node_Next == 0) //递归找到下一个不为空的节点
{
Find_Next_Node(node_Parent);
if(Find_Flag == true)
{
Find_Flag = false;
node_Now = 0;
return ;
}
}
node_Now_ = node_Next; //判断同级的下一个节点
node_Now = node_Now_;
//当前节点更新后,其相关的节点也都必须更新
node_Parent = node_Now_->parent(); //父节点 必定存在
node_Previous = node_Now_->previous_sibling(); //可能存在的前节点
node_Next = node_Now_->next_sibling(); //可能存在的后节点
}
else //递归判断其子节点是否等于目标节点
{
node_Now_ = node_Now_->first_node();
if(node_Now_ != 0) //存在子节点则继续递归
{
//当前节点更新后,其相关的节点也都必须更新
node_Parent = node_Now_->parent(); //父节点 必定存在
node_Previous = node_Now_->previous_sibling(); //可能存在的前节点
node_Next = node_Now_->next_sibling(); //可能存在的后节点
Cycle_Check(it_node_, node_Now_);
}
else
{
if(node_Next == 0) //递归找到下一个不为空的节点
{
Find_Next_Node(node_Parent);
if(Find_Flag == true)
{
Find_Flag = false;
node_Now = 0;
return ;
}
}
node_Now_ = node_Next; //判断同级的下一个节点
node_Now = node_Now_;
//当前节点更新后,其相关的节点也都必须更新
node_Parent = node_Now_->parent(); //父节点 必定存在
node_Previous = node_Now_->previous_sibling(); //可能存在的前节点
node_Next = node_Now_->next_sibling(); //可能存在的后节点
}
}
}
6.void Find_Next_Node(rapidxml::xml_node<>* node_Parent_)的功能是需找下一个需要处理的节点,其实现是:
void Find_Next_Node(rapidxml::xml_node<>* node_Parent_)
{
node_Next = node_Parent_;
node_Parent = node_Next->parent();
node_Previous = node_Next->previous_sibling();
node_Next = node_Next->next_sibling();
if(node_Next == 0)
{
if(node_Parent == root) //当下一个节点为空,且父节点已经是根节点,则说明已经全部判断完成
{
Find_Flag = true;
}
else
{
Find_Next_Node(node_Parent);
}
}
}
7.建立一个配置文件,示例如下所示:
Delete:1;
Filename:abcd.icd;
Node.name: ReportControl, ReportControl ;
First attribute.value: brcbAlarm*, urcbAin* ;
注意 (1)在首行配置是否启用该软件,即: 0 禁用 1 启用;
(2)节点与(节点的第一个)属性值一一对应,多个则以逗号‘,’间隔,每行以分号‘;’结束;
(3)如果只有节点,但是属性为空,则删除与节点对应的所有节点;
(4)如果节点为空,则无论是否有属性,都不会删除节点;
(5)提供“*”通配符的功能,但是只支持右侧通配,比如 Report* 或 brcb*。
使用时, 将 生成的软件 和 配置文件 拷贝到需要处理的文件的同级目录,运行软件即可。