/**********************************************************************
**程序名称:XML语言解析器
**程序功能:完成了对基础的XML语言的解析功能,并提供了一些查询函数
**作者: BUG_lauo
**完成日期:2009-6-8
***********************************************************************/
#include<iostream>
#include"xml.h"
using namespace std;
int main()
{
Xml xml;
//xml.Xml_Analysis(string("<?xml version='1.0' ?><body body='adfasd '> 125 dfasd 8888 <data ad=/"ajfhsd/" >sadjfhas</data> /
<time id='year'> hello <date> </date> <month></month> </time></body>"));
xml.Xml_Analysis("a.xml");
if(xml.Out_Error_Num()!=0)
{
cout<<"Xml解析过程中发现有"<<xml.Out_Error_Num()<<"个错误:"<<endl;
xml.Out_Error_To_Cmd();
}
xml.Out_To_Cmd();
xml.Out_To_File("xml.txt");
/////////以下将是查询测试
int a=Xml::BROTHER_ALL;
if(xml.Xml_Query("date",Xml::CHILD_ALL))
{
cout<<xml.get_cursor()->name<<" value:"+xml.get_cursor()->value<<endl;;
if(xml.moveto(Xml::CHILD_ALL,1))
cout<<"ok!"<<endl;
xml.begin();
cout<<xml.get_cursor()->name<<" value:"+xml.get_cursor()->value<<endl;;
if(xml.moveto(Xml::CHILD_ALL,0))
cout<<xml.get_cursor()->name<<" value:"+xml.get_cursor()->value<<endl;
}
xml.begin();//将光标移为根目录下
if(xml.Xml_Query("time",Xml::CHILD_ALL))
cout<<xml.get_cursor()->name<<" value:"+xml.get_cursor()->value<<endl;
//system("notepad.exe xml.txt");
return 1;
}
/**********************************************************************
**程序名称:XML语言解析器
**程序功能:完成了对基础的XML语言的解析功能,并提供了一些查询函数
**作者: BUG_lauo
**完成日期:2009-6-8
***********************************************************************/
/***********************************************************************
**文件名: xml.h
**文件内容:定义了Xml语言解析类(包含查询功能)及其所需的基本数据结构
************************************************************************/
#include<iostream>
#include<string>
#include<list>
#include<stack>
using namespace std;
struct xml_attribute//标签属性结构体
{
string attri_name;//属性名
string attri_value;//属性值
};
struct xml_node
{
string name;//标签名称
list<xml_attribute> attribute;//标签对应的属性列表
string value; //用字符串来保存其值
xml_node* brother,*child;//儿子节点及兄弟结点
xml_node():brother(0),child(0){}
~xml_node(){if(brother) delete brother;if(child) delete child;}//析构函数
};
//Xml解析类,从一个字符串中解析得到对应的内容,并形成一个树的结构
//并且提供查询定位功能
class Xml
{
private:
xml_node* root;//Xml树的根结点
xml_node* cursor;//用于定位用的“光标”
string xml_str;
int current;//解析时正在分析的字符
int err_num;//解析的错误数
list<string> ErrorList;//解析出错暂存列表
stack<string*> value_stack;//标签名对应的值,压栈以便在中间时仍然可对其正确赋值
public:
enum Direct{CHILD_ONLY,CHILD_ALL,BROTHER_ONLY,BROTHER_ALL};//遍历的方向
private:///////////////////////////////////////Xml解析常用内部服务函数
bool moveto(char ch);//移动到对应的字符处,返回值为空,表明已经到达xml_str尾
bool filter();//将空格过滤掉,找到最起始的非空字符,如果返回值为空,表明已经到达宽以xml_str的结束处
bool get_name(string &str);//得到一个标识符名字
bool get_value(string &value);//得到标签的值
bool get_attri_value(string &value);//得到属性值,如果出错则返回
bool is_id_letter(char ch);//是合法的标签名组成字符,包括字符、数字和下划线
bool is_space_char(char ch);//是否是类空格的字符
bool error(string err_str);//出错处理函数,返回值必为
string error_skim_str(int len);//出错时对出错位图提供一个查看的缩略的字串
string SpaceFormat(const string str,int level,int len=10);//允许的显示的字符串最大长度为个字符
void Out_To_Cmd(xml_node* ptr,int level);//用于递归输出
void Out_To_File(FILE* file,xml_node* ptr,int level);//解析结果(XML树)输出到文件
private:///Xml解析功能函数
bool Xml_head();//Xml文件头
bool Xml_body(xml_node*&);//Xml语法单元:头标签、尾标签及其间的部分
xml_node* front_label();//头标签
bool rear_label(string label_name);//结尾标签
bool get_attribute(xml_node* ptr);//得到标签的属性
public://///Xml解析常用接口函数
Xml(string str=""):xml_str(str),root(0),current(0),
err_num(0),cursor(0){};
~Xml(){if(root) delete root;}
bool Xml_Analysis();
bool Xml_Analysis(string str);//对str进行分析,得到Xml树
bool Xml_Analysis(const char* filename);//对一个xml文件进行分析,到得相应的内容
int Out_Error_Num(){return err_num;}
void Out_Error_To_Cmd();
void Out_To_Cmd();//输出主程序
bool Out_To_File(FILE* file);//解析得到的结果(XML树)输出到屏幕
bool Out_To_File(const char* filename);//解析得到的结果(XML树)输出到文件
public://///////////////////////////////////////////查询部分对外接口函数
bool Xml_Query(string key,Direct flag);//flag标识是往什么方向遍历的,使用了enum Direct
void begin(){cursor=root;}//将光标移回到根结点下
xml_node* get_cursor(){return cursor;}//得到光标所在位置
bool moveto(Direct flag,int n);//向儿子树杈移动n步,如果移动失败,则返回为,并且保持当前值不变
private:///////Xml查询内部常用服务函数
bool SearchBrotherFirst(string key,Direct flag);//儿子优先搜索
bool SearchChildFirst(string key,Direct flag); //兄弟优先搜索
////////////////////////////////////////////////////////////////////////////////
};