XML语言解析类(内含查询功能)

 //下载:https://8004937974480085586-a-1802744773732722657-s-sites.googlegroups.com/site/lauodewangzhan/wo-de-zhu-ye/wo-de-zui-xin-dong-tai/xmlyuyanjiexileineihanchaxungongneng/xml%E8%A7%A3%E6%9E%90%E5%99%A8.rar?attredirects=0&auth=ANoY7cq3HuKxEYd_hv0bmPQfKtdti9OjHRQgPG47_g6h9cIhjx7O8lrcLavRg8rr7gK9DibOtjXTW2Sw0UFRt47MxNd51Hf4U62B6D7jdH7Vj-Zfuh0fwzURxb0i-P5B_RjhLBWNnMQIG5rHXiSrKu9jIUCKf7_xDzlMOCDxVuFpASkguW1L6j065_tkKSheyFdSdZEqvGnuyLKcl36h0XHJgA-ZfP-2Xq6AcEtr_-xFkboVSFbuFKe19_GswRQoeBzx8_bUz7e32TpOZOQvQW9HNt5z8UGZ6qG9oNGZw-Ic3vQmh5gViQLi0Dxmr55aR1op-I_inCjueXyVJMhE6eIGrEAKOJUA7g%3D%3D

/**********************************************************************

**程序名称: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);  //兄弟优先搜索

    

};

/**********************************************************************

**程序名称:XML语言解析器

**程序功能:完成了对基础的XML语言的解析功能,并提供了一些查询函数

**作者:   BUG_lauo

**完成日期:2009-6-8

***********************************************************************/

/***********************************************************************

**文件名: xml.cpp

**文件内容:实现xml.h里定义的Xml类的所有成员函数,包括解析函数及查询函数

************************************************************************/

 

#include"xml.h"

/********************Xml解析功能所需的内部服务函数**********************/

bool Xml::moveto(char ch)//移动到指定的字符处

{

    int mlen=xml_str.length();

    while(current!=mlen)

    {

        if(xml_str[current]==ch)

            break;

        current++;

    }

    if(current==mlen)//已经到达xml_str尾

        return 0;

    return 1;

}

bool Xml::filter()//类空格字符过滤

{

    int mlen=xml_str.length();

    while(current<mlen && is_space_char(xml_str[current]))//将类空格的字符过滤掉

        current++;

    return current<mlen;

}

bool Xml::get_name(string &str)//得到一个标识符名字

{

    int mlen=xml_str.length();

    while(current<mlen&& is_id_letter( xml_str[current]))

        str+=xml_str[current++];//先赋值后自增

    if(str.length()==0||str[0]<='9'&&str[0]>='0')//如果得到了空名或者首字符为数字,则返回为

        return 0;

    return 1;

}

bool Xml::get_value(string &value)//得到标签的值

{

    int mlen=xml_str.length();

    while(current<mlen && xml_str[current]!='<')

    {

        if(is_space_char(xml_str[current])&&filter())

            value+=' ';

        else if(current<mlen)

            value+=xml_str[current++];

    }

    return current<mlen;

}

bool Xml::get_attri_value(string &value)//得到属性值,如果出错则返回

{

    int mlen=xml_str.length();

    if(xml_str[current]=='/'')

    {

        current++;

        while(current<mlen&&xml_str[current]!='/'')

            value+=xml_str[current++];

        current++;

        return current<mlen;//如果未到达xml_str尾,则表明属性正确

    }

    else if(xml_str[current]=='"')

    {

        current++;

        while(current<mlen&&xml_str[current]!='"')

            value+=xml_str[current++];

        current++;

        return current<mlen;//如果未到达xml_str尾,则表明属性正确

    }

    else

        return 0;//属性出错

}

inline bool Xml::is_id_letter(char ch)//是合法的标签名组成字符,包括字符、数字和下划线

{

    return (ch>='0'&& ch<='9'|| ch>='a'&& ch<='z'|| ch=='_' ||

        ch>='A'&& ch<='Z');

}

inline bool Xml::is_space_char(char ch)//是否是类空格的字符

{

    if(ch==' '||ch=='/n'||ch=='/r'||ch=='/t'||ch==EOF)

        return 1;

    return 0;

}

inline bool Xml::error(string err_str)

{

    err_num++;

    char buf[256];

    itoa(err_num,buf,10);

    ErrorList.insert(ErrorList.end(),string("Error ")+buf+":"+err_str+"  At: "+error_skim_str(15));

    return 0;

}

string Xml::error_skim_str(int len)//出错时对出错位图提供一个查看的缩略的字串

{

    string str;

    int begin=(current - len/2 >=0 ) ? current - len/2:0,

        mlen=xml_str.length();

    for(;begin<len&&begin<mlen;begin++)

        str+=xml_str[begin];

    return str;

}

/******************************************************************************/

/**************************Xml语言解析类输出函数如下***************************/

void Xml::Out_Error_To_Cmd()

{

    for(list<string>::iterator i=ErrorList.begin();i!=ErrorList.end();i++)

        cout<<*i<<endl;

}

string Xml::SpaceFormat(const string str,int level,int len)//允许的显示的字符串最大长度为个字符

{

    string space,encode;

    for(int i=0;i<len;space+=' ',i++);//得到标准空格的长度

    space[0]='.';

    for(int i=0;i<level;i++) encode+=space;//得到在特定层数下的标准空格行

    for(int i=0,len=str.length();i<10&&i<len;i++) encode+=str[i];//得到要输出的字串

    return encode;

}

void Xml::Out_To_Cmd()

{

    if(root)

        Out_To_Cmd(root,0);

}

void Xml::Out_To_Cmd(xml_node* ptr,int level)//用于递归输出

{

    cout<<SpaceFormat(ptr->name,level)<<(ptr->value.length()!=0?" value:"+ptr->value:"");

    list<xml_attribute>::iterator i=ptr->attribute.begin();

    if(i!=ptr->attribute.end())

    {

        cout<<"( ";

        for(;i!=ptr->attribute.end();i++)

            cout<<i->attri_name+"=/""+i->attri_value+"/" ";

        cout<<")";//换行

    }

    cout<<"/n";

    if(ptr->child)//如果儿子节点存在

        Out_To_Cmd(ptr->child,level+1);//不换行

    if(ptr->brother)//如果brother结点存在

        Out_To_Cmd(ptr->brother,level);//换行

}

void Xml::Out_To_File(FILE* file,xml_node *ptr,int level)

{

    fprintf(file,"%s",(SpaceFormat(ptr->name,level)+(ptr->value.length()!=0?" value:"+ptr->value:"")).c_str());

    list<xml_attribute>::iterator i=ptr->attribute.begin();

    if(i!=ptr->attribute.end())

    {

        fprintf(file,"( ");

        for(;i!=ptr->attribute.end();i++)

            fprintf(file,"%s",(i->attri_name+"=/""+i->attri_value+"/" ").c_str());

        fprintf(file,")");//换行

    }

    fprintf(file,"/n");

    if(ptr->child)//如果儿子节点存在

        Out_To_File(file,ptr->child,level+1);//不换行

    if(ptr->brother)//如果brother结点存在

        Out_To_File(file,ptr->brother,level);//换行

}

bool Xml::Out_To_File(FILE* file)

{

    if(root) Out_To_File(file,root,0);

    else return 0;

    return 1;

}

bool Xml::Out_To_File(const char* filename)

{

    FILE* file=fopen(filename,"w");

    if(file)

    {

        if(Out_To_File(file))//假如分析成功

        {

            fclose(file);

            return 1;

        }

        else

        {

            fclose(file);

            return 0;

        }

    }

    return 0;

}

/**********************************************************************/

/*******************Xml解析类解析功能函数如下*************************/

bool Xml::Xml_Analysis(string str)//对str进行分析,得到Xml树

{

    if(str=="")//要分析的字串为空

        return 0;

    xml_str=str;

    return Xml_Analysis();

}

bool Xml::Xml_Analysis()//对xml_str进行分析

{

    this->err_num=0;//错误数置为零

    ErrorList.clear();//将错误列表清空

    if(xml_str=="")//要分析的字串为空

        return 0;

    if(Xml_head())//如何Xml头正确,则继续分析body

        return Xml_body(root);

    return 0;//Xml头出错,返回值为

}

bool Xml::Xml_Analysis(const char* filename)//对一个xml文件进行分析,到得相应的内容

{

    FILE* file=fopen(filename,"r");

    if(file==0)

        return 0;

    char buf[256]={0};

    while(fread(buf,1,256,file))

    {

        xml_str+=buf;

        memset(buf,0,256);

    }

    fclose(file);

    return Xml_Analysis();

}

bool Xml::Xml_head()

{

    if(moveto('<'))

    {

        if(xml_str.length()-current>5)//当字符数不够个的时候,显然不全,故出错

        {

            if(!(xml_str[++current]=='?'&&xml_str[++current]=='x'&&

                xml_str[++current]=='m'&&xml_str[++current]=='l'&&moveto('?')&&xml_str[++current]=='>'))

                return error("Xml头出错!");

        }

        else//字符长度不足例如"<?xml"

            return error("Xml头出错!");

    }

    return 1;

}

bool Xml::Xml_body(xml_node*& ptr)

{

    ptr=NULL;

    if(moveto('<'))//已经内含了filter()功能

    {

        ptr=front_label();//得到了首标

        if(ptr&&filter())//正确获取标签,且有可能找到结束标签

        {

            value_stack.push(&(ptr->value));//将要找到的value压栈,以便中途赋值

            if(xml_str[current]!='<')//得到其值

            {

                if(!get_value(ptr->value))

                    return error("Xml意外结束!");

            }

            if(moveto('<')&&xml_str[current+1]!='/')//如果标签未结束,则表明为新的标签要开始!

                if(!Xml_body(ptr->child))

                    return error("Xml子标签出错!");

            if(moveto('<')&&xml_str[current+1]=='/')//如果是结束标签

            {

                current+=2;

                if(!rear_label(ptr->name))

                    return error("标签"+ptr->name+"未配对!");

                moveto('>');

                current++;

            }

        }

        else

            return error("Xml未包含体部分!");

    }

    value_stack.pop();

    if(filter())

    {

        if(xml_str[current]!='<')

        {

            if(value_stack.empty())

                return error("意外的标签值出现!");

            string* value=value_stack.top();

            if(value&&!get_value(*value))

                return error("Xml获取标签值时意外结束!");

        }

        if(filter()&&xml_str[current]=='<'&&xml_str[current+1]!='/')//如果不是结束标签,而是开始标签

        {

            if(root==ptr)

                return error("Xml体只允许出现一个根标签!");

            if(is_space_char(xml_str[current+1]))

                return error("Xml标签'<'后首字符为非法字符!");

            if(!Xml_body(ptr->brother))

                return 0;//生成brother部分

        }

    }

    return 1;

}

xml_node* Xml::front_label()

{

    xml_node* ptr=new xml_node;

    current++;//原来指向'<',故移到下一个字符,此时name开始

    if(!is_id_letter(xml_str[current]))

        return (xml_node*)error("'<'与标签名之间包含有非法字符!");

    if(get_name(ptr->name))

    {

        if(filter())

        {

 

            if(xml_str[current]!='>'&&!get_attribute(ptr))

                    return (xml_node*)error("错误的属性值!");

            if(filter() && xml_str[current]=='>')//已经标签结束

                current++;//指向下一个未处理字符

            return ptr;//将得到的标签返回

        }

        else

            return (xml_node*)error("标签意外中止(标签不完整)!");

    }

    else

    {

        delete ptr;//释放已经申请的空间

        return (xml_node*)error("未包含标签名或者标签名非法!");

    }

}

bool Xml::get_attribute(xml_node* ptr)

{

    string name;

    int mlen=xml_str.length();

    while(current<mlen && xml_str[current]!='>')

    {

        if(filter() && is_id_letter(xml_str[current]) && get_name(name))

        {

            xml_attribute attri;

            attri.attri_name=name;//属性名

            if(filter()&&xml_str[current++]=='='&&filter())

                if(!get_attri_value(attri.attri_value))//得到了正确的属性值

                    return error("错误的属性值!");

            ptr->attribute.insert(ptr->attribute.end(),attri);

        }

        else

            return error("属性名错误!");

        filter();//注意这里最后将其移动到下一个未为类空字符,以保证能正确判断

    }

    return 1;

}

bool Xml::rear_label(string name)

{

    string id;

    if(!get_name(id))

        return 0;

    if(id!=name)

        return 0;

    if(moveto('>'))

        return 1;

    return 0;

}

/********************************************************************************/

/*******************************Xml查询函数如下**********************************/

bool Xml::Xml_Query(string key,Direct flag)

{

    if(cursor==NULL)//如果cursor为,表明空置了光标,应将其置为root

        cursor=root;

    if(root==NULL)//树根为空,返回

        return 0;

    xml_node* ptr=cursor;//如果查询失败,应将光标恢复到此处

    bool bflag=0;

    if(flag==CHILD_ONLY||flag==CHILD_ALL)

        bflag=SearchChildFirst(key,flag);

    else

        bflag=SearchBrotherFirst(key,flag);

    cursor=bflag?cursor:ptr;//如果查询失败,则cursor恢复为原值

    return bflag;

}

bool Xml::SearchChildFirst(string key,Direct flag)

{

    if(cursor==NULL)

        return 0;

    xml_node* ptr;

    if(cursor->name==key)//找到,返回为

        return 1;

    else

    {

        ptr=cursor->brother;

        cursor=cursor->child;

        if(SearchChildFirst(key,flag))//从儿子结点开始继续查找

            return 1;

        if(flag==CHILD_ALL)

        {

            cursor=ptr;//向兄弟结点方向继续找

            return SearchChildFirst(key,flag);

        }

        return 0;

    }

}

bool Xml::SearchBrotherFirst(string key,Direct flag)

{

    xml_node* ptr;

    if(cursor->name==key)//找到,返回为

        return 1;

    else

    {

        ptr=cursor->child;

        cursor=cursor->brother;

        if(SearchBrotherFirst(key,flag))//从兄弟结点开始继续查找

            return 1;

        if(flag==BROTHER_ALL)//向儿子结点方向继续找

        {

            cursor=ptr;

            return SearchBrotherFirst(key,flag);

        }

        return 0;

    }

}

bool Xml::moveto(Direct flag,int n)//向儿子树杈移动n步,如果移动失败,则返回为,并且保持当前值不变

{

    if(cursor==NULL)//如果当前光标已经指向空,则让它从根结点开始

        cursor=root;

    xml_node* ptr=cursor;//以便恢复当前值

    if(flag==CHILD_ALL||flag==CHILD_ONLY)

        while(n>0&&cursor!=NULL)

            cursor=cursor->child,n--;

    else

        while(n>0&&cursor!=NULL)

            cursor=cursor->child,n--;

    if(cursor==NULL)//表明移动失败

    {

        cursor=ptr;

        return 0;

    }

    return 1;//移动成功

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值