xmlparser.cpp

来自「可移植的xml库。已经在windows和linux上测试通过。只使用C++ Ru」· C++ 代码 · 共 353 行

CPP
353
字号
//xmlparser.cpp

#include "xml.h"

CXMLParser::CXMLParser()
{
	init();
}

CXMLParser::~CXMLParser()
{
	reset();
}

void CXMLParser::init()
{
	m_x = 0;
	m_c = 0;
	m_ln = 0;
	m_last = 0;
	m_navi = 0;
	m_char = 0;
	m_depth = 0;
	m_ecode = 0;
	m_naviexp = 0;
	m_stopLevel = 0;
	m_flags = F_SAX;
	m_chunkLevel = 0;
	m_bufsize = 4096;
	memset(m_estr,0,sizeof(m_estr));
}

void CXMLParser::reset()
{
	if(m_last) m_last->free();
	m_pb.clear();
	init();
}

CXMLNode* CXMLParser::clearTree()
{
	CXMLNode *p = m_last;
	m_last = 0;
	if(p)
	{
		if(p->getParent() && !m_ecode) setupErrCtx(p->getParent()->getNod(),E_XML_NO_CLOSE);
		CXMLNode *x;
		for(;(x=p->getParent())!=0;p=x);
		for(;(x=p->getPrev())!=0;p=x);
	}
	return p;
}

bool CXMLParser::isClosedOn(const CXMLNode *x)
{
	assert(x);
	if(!m_last)
	{
		if((m_flags & F_SAX)
			&& (x->getType()==XNT_META
			|| x->getFlags(XNF_INDEP_TAG|XNF_CLOSE_TAG)))
		{
			return true;
		}
		assert((m_flags & F_SAX) || !x->getFlags(XNF_CLOSE_TAG) && x->getType()==XNT_TAG);
		return false;
	}
	if(!m_last->getFlags(XNF_FULL_NODE)
		&& m_last->getType()==XNT_TAG
		&& !m_last->getFlags(XNF_INDEP_TAG)
		&& m_last->isNodOfExact(x->getNod(),x->getLen()))
	{
		return true;
	}
	CXMLNode *p = m_last->getParent();
	if(!p) return false;
	if(!p->getFlags(XNF_FULL_NODE)
		&& p->getType()==XNT_TAG
		&& !p->getFlags(XNF_INDEP_TAG)
		&& p->isNodOfExact(x->getNod(),x->getLen()))
	{
		m_last = p;
		return true;
	}
	return false;
}

int CXMLParser::saxParse(CXMLClient *c,FILE *fp)
{
	m_c = c;
	size_t n;
	int e = 0;
	assert(m_bufsize);
	char *buf = new char[m_bufsize];
	for(;;)
	{
		n = fread(buf,1,m_bufsize,fp);
		if(ferror(fp)){delete []buf;return E_XML_LOAD_READ;}
		if(n)
		{
			if((e=saxAppend(buf,n))!=0 && e!=E_XML_PARTIAL){delete []buf;return e;}
		}
		else break;
	}
	delete []buf;
	return 0;
}

int CXMLParser::saxParseFile(CXMLClient *c,const char *path)
{
	assert(path);
	FILE *fp = fopen(path,"r");
	if(!fp) return E_XML_LOAD_FILE;
	int e = saxParse(c,fp);
	fclose(fp);
	return e;
}

int CXMLParser::saxParse(CXMLClient *c,const char *buf,unsigned bytes)
{
	m_c = c;
	return saxAppend(buf,bytes);
}

int CXMLParser::domParse(CXMLNode **root,FILE *fp)
{
	m_c = 0;
	assert(root);
	m_flags &= ~F_SAX;
	int e = saxParse(0,fp);
	*root = clearTree();
	if(!e && m_ecode) e = m_ecode;
	return e;
}

int CXMLParser::domParseFile(CXMLNode **root,const char *path)
{
	m_c = 0;
	assert(root);
	m_flags &= ~F_SAX;
	int e = saxParseFile((CXMLClient *)0,path);
	*root = clearTree();
	if(!e && m_ecode) e = m_ecode;
	return e;
}

int CXMLParser::domParse(CXMLNode **root,const char *buf,unsigned bytes)
{
	m_c = 0;
	assert(root);
	m_flags &= ~F_SAX;
	int e = saxParse(0,buf,bytes);
	*root = clearTree();
	if(!e && m_ecode) e = m_ecode;
	return e;
}

int CXMLParser::setupErrCtx(const char *p,int e)
{
	strncpy(m_estr,p,sizeof(m_estr));
	m_estr[sizeof(m_estr)-1] = 0;
	m_ecode = e;
	return e;
}

int CXMLParser::saxAppend(const char *buf,unsigned bytes)
{
	assert(buf);
	if(!bytes && !(bytes=strlen(buf))) return 0;
	int err = 0;
	if((err=m_pb.append(buf,bytes))!=0) return err;
	m_pb[m_pb.getUsed()] = 0;
	const char *t,*b,*e;
	const char *p = m_pb;
	CXMLNode *x;
	char c;
	bool ctag;
	unsigned type;
	b = p;
	for(;!err && *p && m_navi!=XPS_STOP;)
	{
		b = p;
		err = CXMLNode::findClosePos(p,&e);
		if(!e && !err) break;
		for(;b<p;++b,++m_char) if(*b=='\n'){++m_ln;m_char=0;}
		if(err) return setupErrCtx(b,err);
		if(*b!='<' && !m_depth) return setupErrCtx(b,E_XML_BAD_CDATA);//no C data allowed in root
		t = p = b;
		if(p[0]=='<' && p[1]=='!' && p[2]=='-' && p[3]=='-')
		{
			if(!(m_flags & F_LOAD_COMMENT))
			{
				for(;b<e;++b,++m_char) if(*b=='\n'){++m_ln;m_char=0;}
				m_char += 3;
				p = e + 3;
				continue;
			}
		}
		t = b;
		x = CXMLNode::load(&m_xnc,b,e,&err,m_x);
		if(err)
		{
			x->free();
			for(;t<b;++t,++m_char) if(*t=='\n'){++m_ln;m_char=0;}
			if(err==E_XML_EMPTY_COMMENT) continue;
			return setupErrCtx(b,err);
		}
		if((type=x->getType())==XNT_META || type==XNT_COMMENT || type==XNT_CDATA || x->getFlags(XNF_INDEP_TAG)) x->setDepth(m_depth);
		else if(x->getFlags(XNF_CLOSE_TAG)) x->setDepth(m_depth--);
		else x->setDepth(m_depth++);
		if(t<b)
		{
			for(;t<b;++t,++m_char) if(*t=='\n'){++m_ln;m_char=0;}
		}
		ctag = false;
		if(type==XNT_META) c = (char)x->getFlags(0xff);
		if(m_stopLevel>0 && x->getDepth()>m_stopLevel) x->free();
		else if(m_navi && m_naviexp<x->getDepth()) x->free();
		else if(x->getDepth()<m_chunkLevel) m_navi = m_c->handleNode(*this,x);
		else
		{
			ctag = ((type!=XNT_META) && x->getFlags(XNF_CLOSE_TAG)) || x->getFlags(XNF_INDEP_TAG)!=0;
			if((m_flags & F_SAX) && ctag && m_depth<m_chunkLevel)
			{
				assert(!m_last);
				if(m_last)
				{
					m_navi = XPS_STOP;
					return setupErrCtx(m_last->getNod(),E_XML_NO_CLOSE);
				}
				m_navi = m_c->handleNode(*this,x);
			}
			else
			{
				if(type==XNT_TAG && x->getFlags(XNF_CLOSE_TAG)) m_ecode = appendTermNode(x);
				else m_ecode = appendNTNode(x);
				if(m_ecode) return setupErrCtx(b,m_ecode);
				if((m_flags & F_SAX) && ctag && m_depth==m_chunkLevel) m_navi = m_c->handleNode(*this,clearTree());
			}
		}
		if(m_navi>0)
		{
			if(m_navi==1 && ctag) --m_navi;
			if(m_navi)
			{
				m_naviexp = m_depth - m_navi;
				if(m_naviexp<=0) m_navi = XPS_STOP;
			}
		}
		t = b;
		xmlSkipBlanks(b);
		for(;t<b;++t,++m_char) if(*t=='\n'){++m_ln;m_char=0;}
		if(type==XNT_TAG || type==XNT_META)
		{
			if(type==XNT_META)
			{
				assert(b[0]==c);
				++b;++m_char;
			}
			assert(*b=='>' || *b=='/');
			if(*b=='/')
			{
				++b;++m_char;
				assert(*b=='>');
			}
			++b;++m_char;
		}
		else if(type==XNT_COMMENT)
		{
			assert(b[0]=='-' && b[1]=='-' && b[2]=='>');
			b += 3;
			m_char += 3;
		}
		t = b;
		xmlSkipBlanks(b);
		for(;t<b;++t,++m_char) if(*t=='\n'){++m_ln;m_char=0;}
		if(!*b) break;
		p = b;
	}
	p = b;
	if(!err)
	{
		if(m_depth>0 || *p) err = E_XML_PARTIAL;
		else if(m_depth<0) err = E_XML_BAD_TILE;
		if(err) setupErrCtx(p,err);
	}
	m_pb.trimLeft((unsigned)(p-(const char *)m_pb));
	m_pb[m_pb.getUsed()] = 0;
	return err;
}

int CXMLParser::appendNTNode(CXMLNode *x)
{
	if(!m_last)
	{
		if(!(m_flags & F_SAX) && x->getDepth()!=0){x->free();return E_XML_BAD_TILE;}
		else{m_last=x;return 0;}
	}
	if(x->getDepth()>m_last->getDepth())
	{
		m_last->appendChild(x);
		m_last = x;
		return 0;
	}
	for(;x->getDepth()<m_last->getDepth();m_last=m_last->getParent())
	{
		if(!m_last->getParent())
		{
			x->free();
			return E_XML_BAD_TILE;
		}
	}
	assert(x->getDepth()==m_last->getDepth());
	m_last->appendSibling(x);
	m_last = x;
	return 0;
}

int CXMLParser::appendTermNode(CXMLNode *x)
{
	if(!m_last)
	{
		if(x->getType()!=XNT_META && (!(m_flags & F_SAX) || (x->getFlags(XNF_CLOSE_TAG))))
		{
			x->free();
			return E_XML_BAD_TILE;
		}
		else{m_last=x;return 0;}
	}
	for(;x->getDepth()<=m_last->getDepth();m_last=m_last->getParent())
	{
		if(!m_last->getParent())
		{
			x->free();
			return E_XML_BAD_TILE;
		}
	}
	if(x->getDepth()-m_last->getDepth()!=1)
	{
		x->free();
		return E_XML_BAD_TILE;
	}
	if(!isClosedOn(x))
	{
		x->free();
		return E_XML_BAD_CLOSE;
	}
	m_last->setFlags(XNF_FULL_NODE);
	if(!m_last->getChildren()) m_last->setFlags(XNF_INDEP_TAG);
	x->free();
	return 0;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?