#include <iostream>
#include "1.h"
int main(int argc, char *argv[])
{
try
{
SXmlDOM dom;
//dom.parse("<?xml?><书店><书本 书名="VC++" 价格="50" 折扣="1"/><书本 书名="VB" 价格="50" 折扣="0.8"/><书本 书名="C#" 价格="50" 折扣="0.7">有源程序光盘</书本><挂历><年份>2006</年份><价格>50</价格></挂历></书店>")
dom.parseFile("test.xml");
//查询
SXmlElement& root = dom.root();
cout << "有" << root.count("书本") << "本书!"<< endl;
cout << "VB的价格:" << (int)root.item("书本", 1)["价格"] * (float)root.item("书本", 1)["折扣"] << endl;
cout << root.at(0).xml();
SXmlElement& gl = root.item("挂历");
cout << gl.item("年份").text() << endl;
//遍历
SXmlNodeList::iterator iter;
for(iter = root.begin(); iter!=root.end(); iter++)
cout << (*iter)->xml();
//赋值
root.item("书本", 1)["价格"] = 60;
root.item("书本", 1)["折扣"] = 0.5;
cout << "VB的价格:" << (int)root.item("书本", 1)["价格"] * (float)root.item("书本", 1)["折扣"] << endl;
root.item("书本").text() = "有软盘";
//保存
dom.saveFile("else.xml");//属性列的顺序将自动排列, 采用了C++ map<>
}
catch(exception &e)
{
cout << e.what() << endl;
}
return 0;
}
#ifndef _SXML_H
#define _SXML_H
#pragma warning(disable: 4530)
#pragma warning(disable: 4786)
#include <map>
#include <iterator>
#include <fstream>
#include <vector>
#include <string>
#include <algorithm>
#include <sstream>
#include <exception>
#include <list>
using namespace std;
//
struct AttributeType //string
{
string _Text;
template<typename T>
T operator=(T val) //赋值给_Text
{
stringstream ss;
ss << val;
_Text = ss.str();
return val;
}
AttributeType& operator=(AttributeType& val) //赋值给_Text
{
_Text = val._Text;
return val;
}
operator const char*() { return _Text.c_str(); }
operator string() { return _Text; }
operator int() { return atoi(_Text.c_str()); }
operator long() { return atol(_Text.c_str()); }
operator float() { return atof(_Text.c_str()); }
operator double() { return atof(_Text.c_str()); }
};
//----------------------------------------------
inline ostream& operator<<(ostream &out, AttributeType x){ return out << x._Text;} //输出_Text
inline istream& operator>>(istream &in, AttributeType x) { return in >> x._Text; } //输入_Text
//----------------------------------------------
#ifdef _USE_STRING //如果用了string
typedef string ValueType;
#else
typedef AttributeType ValueType;
#endif
//----------------------------------------------
/// XML类型
enum SXML_Type
{
XML_UNKNOW, //其他节点
XML_ELEMENT, //元素节点
XML_PI,
XML_COMMENT,
XML_Text, //字符块节点
XML_CHAR_DATA,
XML_DOC_Type,
XML_DOCUMENT
};
///异常
class SXmlExecption : public exception
{
string _Src;
public:
SXmlExecption(string s) : _Src(s) { }
~SXmlExecption()throw() { }
const char* what() const throw() { return _Src.c_str(); }
};
//除去头尾空格
inline void trim_c_str(const char *&fptr, const char *&lptr)
{
while(fptr<lptr && isspace(*fptr)) fptr++;//检查参数c是否为空格字符,也就是判断是否为空格('')、定位字符
while(fptr<lptr && isspace(*(lptr-1))) lptr--;
}
//除去头尾空格
inline string& trim_string(string& str)
{
string::size_type pos;
for(pos=0; pos<str.length() && isspace(str.at(pos)); pos++);
str.erase(0, pos);
for(pos=str.length()-1; pos>=0 && isspace(str.at(pos)); pos--);
str.erase(pos + 1);
return str;
}
///将字符转换为实体引用 '<' --> "<"
inline string SXmlEntityXml(string str)
{
char *entity[] = {"lt", "quot", "gt", "amp", "apos"};
char *ref = "</">&/'", *f;
for(string::size_type pos=0; pos < str.length(); pos++)
if((f = strchr(ref, str[pos])))
str.replace(pos, 1, string("&") + entity[f-ref] + ";");
return str;
}
///将实体引用转换为字符 "<" --> '<'
inline string SXmlEntityParse(string str)
{
char *entity[] = {"lt", "quot", "gt", "amp", "apos"};
char *ref = "</">&/'", i;
string r;
for(string::size_type pos = 0, bpos, epos, rlen = 1;
(bpos=str.find('&', pos))!=string::npos; pos = bpos + rlen)
{
epos = str.find(';', bpos);
if(epos == string::npos)
throw SXmlExecption("找不到实体引用的右边界';'");
r.assign(str.begin()+bpos+1, str.begin()+epos);
for(i = 0; i < 5; i++)
if(r == entity[i])
{
str.replace(bpos, epos - bpos + 1, 1, ref[i]);
break;
}
if(i == 5)
throw SXmlExecption("不支持的实体引用!");
}
return str;
}
//属性列
struct SXmlAttribute
{
map<string, ValueType> _Map ;
//清空
void clear() { _Map.clear(); }
//返回大小
map<string, ValueType>::size_type size() { return _Map.size(); }
//返回string后的值
ValueType & value(string key) { return _Map[key]; }
//返回属性
string xml()
{
string str;
for(map<string, ValueType>::iterator iter=_Map.begin(); iter!=_Map.end(); iter++)
{
str += " " + (string)(iter->first) + "=/" "+ (string)(iter->second) + "/"";
///属性列处理: key1="val_1" key2="val_2" key3="&#XXX;"
}
return str;
}
//解析 属性
void parse(const char *first, const char *last)
{
trim_c_str(first, last); //除去头尾空格
for(const char *ptr=first, *fptr, *L, *R ; ptr < last; ptr=R+1)
{
if((fptr = find(ptr, last, '='))==last)
break;
trim_c_str(ptr, fptr); //除去头尾空格
//书本 书名="VC++" 价格="50" 折扣="1"/
if((L = find(fptr+1, last, ' /" ')) != last)//如果L找到 "
R = find(L+1, last, ' /" '); //则R找后面那个
if(L==last || R==last) //如果到达结尾
break;
_Map[string(ptr, fptr)] = string(L+1, R); // (prt,fprt)为属性名 (L+1,R)为属性值
}
}
};
///节点基类
struct SXmlNode
{
SXML_Type _Type; //XML格式
SXmlNode* _pParent; //自己类指针
string _Text; // 数据
SXmlNode(SXmlNode *parent=NULL) : _pParent(parent) { }
virtual ~SXmlNode(){}
SXmlNode* get_parent() { return _pParent; }
SXML_Type& type() { return _Type; }//获得XML格式
//赋值
string& operator=(const char *s) { _Text=s;return _Text; }
string& operator=(string& s) { _Text=s;return _Text; }
virtual string xml() { return _Text; } // >内存数据转换为XML
operator string&() { return _Text; }
void parse(const char *p) { parse(p, p+strlen(p)); } //>解析XML
void parse(const char *f, const char *l) { _Text.assign(f, l); }// 截取存储
};
///字符块节点, 用途是临时储存 数据。
struct SXmlText : SXmlNode
{
SXmlText(SXmlNode *parent=NULL) : SXmlNode(parent) { _Type = XML_Text; }
};
///其他节点
struct SXmlUnknow : SXmlNode
{
SXmlUnknow(SXmlNode *parent=NULL) : SXmlNode(parent) { _Type = XML_UNKNOW; }
};
//有用链表则用 不然用
#ifdef _USE_LIST
typedef list<SXmlNode*> SXmlNodeList ;
#else
typedef vector<SXmlNode*> SXmlNodeList ;
#endif
///元素节点
struct SXmlElement : public SXmlNode
{
SXmlNodeList _pNodes; //节点链表
SXmlAttribute _Attributes; //string
typedef SXmlNodeList::iterator iterator; //迭代器
SXmlElement(SXmlNode *parent=NULL) : SXmlNode(parent) { _Type = XML_ELEMENT; } //构造函数
virtual ~SXmlElement() { clear(); }//析构
string& tag() { return _Text; } //返回节点基类内容
SXmlNodeList::size_type size() { return _pNodes.size(); }//返回元素节点大小
SXmlNodeList& nodes() { return _pNodes; } //返回元素节点
iterator begin() { return _pNodes.begin(); } //返回元素节点开头
iterator end() { return _pNodes.end(); } //返回元素节点末尾
ValueType& value(string key) { return _Attributes.value(key); } //返回属性 后面的值
ValueType& operator[](string key) { return _Attributes.value(key); } //返回属性 后面的值
SXmlElement& operator =(const SXmlElement& x) //赋值
{
_Text = x._Text;
_pNodes = x._pNodes;
return *this; //
}
SXmlNode& at(SXmlNodeList::size_type n = 0) //返回第几个子元素节点
{
if(n<0 || n>=size())
throw SXmlExecption("子节点编号超出范围!");
SXmlNodeList::iterator iter = _pNodes.begin();
advance(iter, n);//功能等于 iter+=n;
return *(*iter); //返回 具体的SXmlNode
}
SXmlNodeList::size_type count()//返回总共多少个元素节点
{
return size();//多此一举?
}
SXmlNodeList::size_type count(string tag_name)//返回 元素名 = tag_name 的元素节点
{
SXmlNodeList::iterator iter;
SXmlNodeList::size_type i;
for(iter = _pNodes.begin(), i = 0; iter != _pNodes.end(); iter++)
if((*iter)->_Type==XML_ELEMENT&& (*iter)->_Text==tag_name )
i++;
return i;
}
SXmlElement& newItem(string tag_name) // 添加新元素节点
{
string &str = trim_string(tag_name); //去除头尾空格
if(!str.length())
throw SXmlExecption("元素节点标签不应为空字符串!");
SXmlElement* p = new SXmlElement(this);
p->tag() = str;
_pNodes.push_back((SXmlNode*)p);//这里用的十分巧妙, 感觉像递归的 把自己存进去 很好!
return (*p);
}
SXmlElement& item(string name, SXmlNodeList::size_type n = 0)//name 节点名。n代表第几个相同的节点
{
SXmlNodeList::iterator iter; //节点 迭代器
SXmlNodeList::size_type i;
for(iter = _pNodes.begin(), i = 0; iter != _pNodes.end(); iter++)
if((*iter)->_Type==XML_ELEMENT&& (*iter)->_Text==name && i++==n) //XML_ELEMENT, 元素节点
return *((SXmlElement*)(*iter)); //返回找到的点
throw SXmlExecption("找不到/"" + name +"/"子节点!");
}
string& text()
{
for(SXmlNodeList::iterator iter = _pNodes.begin(); iter != _pNodes.end(); iter++)
{
if((*iter)->_Type == XML_Text) // XML_Text, //字符块节点
return (string&)(*((SXmlText*)(*iter)));
}
SXmlNode* p = (SXmlNode*)new SXmlText(this);
_pNodes.insert(_pNodes.begin(),1, p);//插入 insert的参数应该是一个迭代器和一个要插入的值 、
return (string&)(*p);
}
///清除所有节点
void clear()
{
_Attributes.clear();//清除属性 map 类型
for(SXmlNodeList::iterator iter=_pNodes.begin(); iter!=_pNodes.end(); iter++)
delete (*iter);
_pNodes.clear(); //清除元素节点
}
virtual string xml()
{
string str;
if(type() == XML_ELEMENT) //XML_ELEMENT, 元素节点
{
str = string("<") + _Text; //
if(_Attributes.size()) //
str += _Attributes.xml(); // _Attributes 属性行
if(_pNodes.size()) // 如果 不为空
{
SXmlNodeList::iterator iter;
for(iter=_pNodes.begin(), str += '>'; iter!=_pNodes.end(); iter++)
str += (*iter)->xml();
str += "</" + _Text + ">";
}
else
str += "/>";
}
else
if(_pNodes.size())
{
SXmlNodeList::iterator iter;
for(iter=_pNodes.begin(); iter!=_pNodes.end(); iter++)
str += (*iter)->xml();
}
return str;
}
//解析
void parse(const char *str)
{
parse(str, str + strlen(str));
}
void parse(const char *first, const char *last)
{
const char *ptr = first;//ptr:base pointer
const char *fptr, *nptr, *tptr; //fptr:find pointer nptr:next pointer tptr : temp pointer 寻找指针,下一个指针,当前指针
SXmlNode *newptr; //create SXmlNode //节点基类
while(ptr < last)
{
fptr = find(ptr, last, '<'); //寻找 <
//去除前面空格
if(ptr != fptr) //第一个元素不是 <的话
{
newptr = new SXmlText(this);
newptr->_Text.assign(ptr, fptr);//把_text的ptr fptr中间的部分给 newptr(自动去除空格)
_pNodes.push_back(newptr); //再将newptr 赋给 p_Nodes
}
if(fptr == last) //如果此时就是末尾 这结束
break;
nptr = find(fptr, last, '>'); //寻找>
if(nptr == last)
throw SXmlExecption(string(fptr, nptr+1) + "找不到标签的右边界'>'"); //报错
switch( *(fptr + 1) )//现在在 <> 里 下一个<? >
{
case '?':
newptr = new SXmlUnknow(this); //最上面的 <?xml version="1.0" encoding="gb2312"?>
newptr->parse(fptr, nptr + 1); //则
_pNodes.push_back(newptr); //将<?xml?>存进去
ptr = nptr + 1; //此时ptr从下一个<开始
break;
case '!':
if(!(*(fptr + 2)=='-' && *(fptr + 3)=='-'))//不是寻常的注释
//<![CDATA[ ]]> 特殊
//<DOCTYPE ]> DTD
{
const char *cdata_L = "CDATA", *cdata_R = "]]>",*doc_Type_L = "DOCTYPE", *doc_Type_R = "]>";
if((tptr = search(fptr, nptr, cdata_L, cdata_L+4)) != nptr) //找到了CDATA
if((tptr = search(tptr, last, cdata_R, cdata_R+3)) != last)//找到了 ]]>
nptr = tptr + 2; //则跳到下一列表
else
throw SXmlExecption("CDataSection can not find /"]]>/""); //找不到匹配
else
if((tptr = search(fptr, nptr, doc_Type_L, doc_Type_L+7)) != nptr)
{
if((tptr = search(tptr, last, doc_Type_R, doc_Type_R+2)) != last)
nptr = tptr + 1;
else
throw SXmlExecption("DOCTYPE can not find /"]>/"");//找不到匹配
}
}
newptr = new SXmlUnknow(this);
newptr->parse(fptr, nptr + 1);
_pNodes.push_back(newptr); //存进去
ptr = nptr + 1; //此时ptr从下一个<开始
break;
default:
char find_str[] = "/n/r/t/x20/>"; //如果都不是 则 />
SXmlElement *new_elem = new SXmlElement(this);
tptr = find_first_of(fptr, nptr, find_str, find_str + 6);//寻找第一个 / 或者 >
new_elem->_Text = string(fptr+1, tptr-fptr-1); // < />里元素赋值给 new_elem 如 书店
_pNodes.push_back(new_elem); //将new_elem扔进去
if(*(nptr-1) == '/')// <elemet .../>
{
new_elem->_Attributes.parse(tptr, nptr-1); //将 element赋值给new_elem
// <书本 书名="VC++" 价格="50" 折扣="1"/>
ptr = nptr + 1; //下一个
}
else //</elemet> </书本>
{
new_elem->_Attributes.parse(tptr, nptr); //将 element赋值给new_elem
string str = string("</") + new_elem->_Text; //
tptr = search(nptr+1, last, str.begin(), str.end()); // </书本
if(tptr == last)
throw SXmlExecption(string(fptr, nptr+1) + "找不到结束标签</element>");
new_elem->parse(nptr+1, tptr);//这个很犀利 <书店> </书店> 里面的 继续解析
nptr = find(tptr, last, '>');
if(nptr == last)
throw SXmlExecption(string(fptr, nptr+1) + "找不到标签的右边界'>'");
ptr = nptr + 1; //下一个
}
} //switch(*(fptr + 1)) mean: <X
}//while(ptr < last)
}
};
///DOM解析
class SXmlDOM : public SXmlElement
{
public:
SXmlDOM()
{
_Type = XML_DOCUMENT;
}
void parseFile(string file_name) //打开文件
{
vector<char> buf;
ifstream rf(file_name.c_str()); //文件变量
if(rf) //如果不为空
{
rf >> noskipws;
//noskipws //不忽略空白
copy(istream_iterator<char>(rf),istream_iterator<char>(), back_inserter(buf));//把值赋给 buf
clear();
parse(&*buf.begin(), &*buf.end()); //干吗来着?
}
else
throw SXmlExecption("无法打开读入文件!");
}
void saveFile(string file_name) //保存文件
{
ofstream rf(file_name.c_str());
if(rf)
rf << xml();
else
throw SXmlExecption("无法打开写入文件!");
}
SXmlElement& root() //
{
for(SXmlNodeList::iterator iter = _pNodes.begin(); iter != _pNodes.end(); iter++)
if((*iter)->_Type == XML_ELEMENT) //元素
return *((SXmlElement*)(*iter));
throw SXmlExecption("找不到根元素!");
}
};
#endif //_SXML_H