最近,在工作中需要分析XML,并对XML内容作出一定的修改。
在网上找到一个XML解析的类,CMarkup(来自http://www.firstobject.com/)。开始用来感觉不错,但是随着开发的深入,CMarkup的免费版本已经不能满足我的要求了。(老外真是有版权意识啊,CMarkup的Developer 版本要收¥249)没办法,只能自己来写了。
于是写了一个类,继承自CMarkup,在其中实现了我所需要的功能(还比较粗糙,就不放上来了)。通过研究,对CMarkup的存储结构有了一定的了解。如果有误,请大牛些指正。
在CMarkup中,xml文档数据存储在 protected 成员变量MCD_STR m_strDoc中,可通过Load()或者SetDoc()函数来对其进行设定。在操作的时候,CMarkup将m_strDoc当做一棵树来处理。结点的信息存储在protected 成员变量ElemPosTree* m_pElemPosTree中。ElemPosTree是一个结构体,它的内容如下:
ElemPosTree结构体
{
ElemPosTree() { Clear(); };
~ElemPosTree() { Release(); };
enum { PA_SEGBITS = 16, PA_SEGMASK = 0xffff };
void ReleaseElemPosTree() { Release(); Clear(); };
void Release() { for (int n=0;n<SegsUsed();++n) delete[] (char*)m_pSegs[n]; if (m_pSegs) delete[] (char*)m_pSegs; };
void Clear() { m_nSegs=0; m_nSize=0; m_pSegs=NULL; };
int GetSize() const { return m_nSize; };
int SegsUsed() const { return ((m_nSize-1)>>PA_SEGBITS) + 1; };
ElemPos& GetRefElemPosAt(int i) const { return m_pSegs[i>>PA_SEGBITS][i&PA_SEGMASK]; };
void CopyElemPosTree( ElemPosTree* pOtherTree, int n );
void GrowElemPosTree( int nNewSize );
private:
ElemPos** m_pSegs; //这就是树的存储结构了
int m_nSize;
int m_nSegs;
};
其中ElemPos是一个结构体,它存储了结点的信息:
ElemPos结构体
{
ElemPos() {};
ElemPos( const ElemPos& pos ) { *this = pos; };
int StartTagLen() const { return nStartTagLen; };
void SetStartTagLen( int n ) { nStartTagLen = n; };
void AdjustStartTagLen( int n ) { nStartTagLen += n; };
int EndTagLen() const { return nEndTagLen; };
void SetEndTagLen( int n ) { nEndTagLen = n; };
bool IsEmptyElement() { return (StartTagLen()==nLength)?true:false; };
int StartContent() const { return nStart + StartTagLen(); };
int ContentLen() const { return nLength - StartTagLen() - EndTagLen(); };
int StartAfter() const { return nStart + nLength; };
int Level() const { return nFlags & 0xffff; };
void SetLevel( int nLev ) { nFlags = (nFlags & ~0xffff) | nLev; };
void ClearVirtualParent() { memset(this,0,sizeof(ElemPos)); };
void SetEndTagLenUnparsed() { SetEndTagLen(1); };
bool IsUnparsed() { return EndTagLen() == 1; };
// Memory size: 8 32-bit integers == 32 bytes
int nStart;
int nLength;
unsigned int nStartTagLen : 22; // 4MB limit for start tag
unsigned int nEndTagLen : 10; // 1K limit for end tag
int nFlags; // 16 bits flags, 16 bits level 65536 depth limit
int iElemParent;
int iElemChild; // first child
int iElemNext; // next sibling
int iElemPrev; // if this is first, iElemPrev points to last
};
结构体ElemPos很关键,对它的成员变量说明如下:
nStart 代表标签在m_strDoc中的起始位置;
nLength 代表标签的长度(以"/>"结束或者以"</xxx>"结束)
nStartTagLen 代表标签的开始部分的长度(以byte计)
nEndTagLen 代表标签结束部分的长度(以byte计)
其它成员有待研究
举例说明如下:
假设上面的内容就是我们的XML,即m_strDoc="<root><tag1>value</tag1></root>"
则root标签编号为0,tag1标签编号为1。
对存储tag1标签的结点来说,nStart为6,nLength为18("<tag1>value</tag1>"的长度),nStartTagLen为6("<tag1>"的长度),nEndTagLen为7("</tag1>"的长度)。
现在清晰了,其实 CMarkup的内部结构就是虚拟的一棵树,内容是存储在m_strDoc中的,标签的位置信息存储在ElemPosTree结构体中。知道了它的存储结构,以后想扩展CMarkup就容易多了。

浙公网安备 33010602011771号