549 lines
12 KiB
C++
549 lines
12 KiB
C++
#include "stdafx.h"
|
|
#include "XMLDocTree.h"
|
|
#include <stack>
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
typedef struct XMLItem
|
|
{
|
|
TCHAR szKeyword[32]; //关键字
|
|
TCHAR szXData[128]; //扩展数据
|
|
|
|
XMLItem* pNextSiblingItem;
|
|
XMLItem* pLastSiblingItem;
|
|
XMLItem* pChildItem;
|
|
XMLItem* pParentItem;
|
|
|
|
}XMLITEM;
|
|
|
|
CXMLDocTree::CXMLDocTree()
|
|
{
|
|
m_pRoot = NULL;
|
|
}
|
|
|
|
CXMLDocTree::~CXMLDocTree()
|
|
{
|
|
INT_PTR nSize = m_arBuffer.GetSize();
|
|
while(nSize > 0)
|
|
{
|
|
XMLItem* pItem = (XMLItem*)m_arBuffer.GetAt(0);
|
|
if (pItem != NULL)
|
|
{
|
|
delete pItem;
|
|
}
|
|
m_arBuffer.RemoveAt(0);
|
|
nSize = m_arBuffer.GetSize();
|
|
}
|
|
}
|
|
|
|
static void GetKeywordAndXData(CString& sText,CString& sKeyword,CString& sXData)
|
|
{
|
|
sKeyword = _T("");
|
|
sXData = _T("");
|
|
int nLen = sText.GetLength();
|
|
if (nLen > 0)
|
|
{
|
|
int nSpace = sText.Find(_T(' '),0);
|
|
if (nSpace != -1)
|
|
{
|
|
sKeyword = sText.Mid(0,nSpace);
|
|
if (nSpace < nLen - 1)
|
|
{
|
|
sXData = sText.Mid(nSpace + 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sKeyword = sText;
|
|
sXData = _T("");
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CXMLDocTree::SetXmlText(LPCTSTR pszXmlText)
|
|
{
|
|
if (pszXmlText == NULL)
|
|
return FALSE;
|
|
|
|
CString sXML = _T(""),sText = _T("");
|
|
CString sKeyword,sXData;
|
|
CString sLine = _T("");
|
|
|
|
CString sXMLNew = pszXmlText;
|
|
|
|
#ifdef UTF_8
|
|
sXML = pszXmlText;
|
|
//UTF-8码转换为一般的字符串
|
|
WCHAR* pStrA = NULL;
|
|
int nCount = MultiByteToWideChar(CP_UTF8 , 0 ,(char*)(LPCTSTR)sXML ,-1 ,NULL,0);
|
|
pStrA = new WCHAR[nCount];
|
|
MultiByteToWideChar(CP_UTF8 ,0 ,(char*)(LPCTSTR)sXML, -1, pStrA , nCount);
|
|
nCount = WideCharToMultiByte(CP_ACP,0,pStrA,-1,NULL,0,NULL,NULL);
|
|
char* pStrB = new char[nCount];
|
|
WideCharToMultiByte(CP_ACP,0,pStrA,-1,pStrB,nCount,NULL,NULL);
|
|
sXMLNew = pStrB;
|
|
delete []pStrA;
|
|
delete []pStrB;
|
|
#endif
|
|
|
|
int nFrL = sXMLNew.Find(_T('<'),0);
|
|
int nFrR = sXMLNew.Find(_T('>'),0);
|
|
int nToL = sXMLNew.ReverseFind(_T('<'));
|
|
int nToR = sXMLNew.ReverseFind(_T('>'));
|
|
|
|
if (nFrL != -1 && nFrR != -1 &&
|
|
nToL != -1 && nToR != -1)
|
|
{
|
|
sText = sXMLNew.Mid(nFrL + 1,nFrR - nFrL - 1);
|
|
GetKeywordAndXData(sText,sKeyword,sXData);
|
|
|
|
XMLItem* pRoot = new XMLItem;
|
|
_tcscpy(pRoot->szKeyword,sKeyword);
|
|
_tcscpy(pRoot->szXData,sXData);
|
|
pRoot->pChildItem = NULL;
|
|
pRoot->pNextSiblingItem = NULL;
|
|
pRoot->pLastSiblingItem = NULL;
|
|
pRoot->pParentItem = NULL;
|
|
m_arBuffer.Add(pRoot);
|
|
m_pRoot = (POSITION)pRoot;
|
|
|
|
if (nFrR + 1 < sXMLNew.GetLength() - 1 && (nToL - nFrR - 1) > 0)
|
|
{
|
|
sLine = sXMLNew.Mid(nFrR + 1,nToL - nFrR - 1);
|
|
MakeChildren(m_pRoot,sLine);
|
|
}
|
|
}
|
|
return m_arBuffer.GetSize() > 0;
|
|
}
|
|
|
|
BOOL CXMLDocTree::Read(LPCTSTR pszFile)
|
|
{
|
|
CStdioFile file;
|
|
if (!file.Open(pszFile,CFile::modeRead))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//1.读取xml;
|
|
CString sXML = _T(""),sText = _T("");
|
|
CString sLine = _T("");
|
|
CString sKeyword,sXData;
|
|
|
|
while(file.ReadString(sLine))
|
|
{
|
|
sLine.TrimRight();
|
|
sLine.TrimLeft();
|
|
sXML += sLine;
|
|
sLine = _T("");
|
|
}
|
|
file.Close();
|
|
return SetXmlText(sXML);
|
|
}
|
|
|
|
//</
|
|
static int FindNextEqualLevelEndtag(const CString& sXMLText)
|
|
{
|
|
BOOL bFirst = FALSE;
|
|
std::stack<int> levelStack;
|
|
|
|
TCHAR chX = 0;
|
|
CString sText = _T("");
|
|
int nSta = sXMLText.Find(_T('<'),0);
|
|
int nPos = 0,nNext = -1;
|
|
if (nSta != -1)
|
|
{
|
|
nNext = nSta + 1;
|
|
if (nNext < sXMLText.GetLength() - 1)
|
|
{
|
|
chX = sXMLText.GetAt(nNext);
|
|
if (chX != _T('/'))
|
|
{
|
|
levelStack.push(1);
|
|
nSta += 1;
|
|
}
|
|
}
|
|
}
|
|
if (levelStack.size() == 0) return -1;
|
|
|
|
while(TRUE)
|
|
{
|
|
nPos = sXMLText.Find(_T('<'),nSta);
|
|
if (nPos != -1)
|
|
{
|
|
//判断下一个是不是 /
|
|
nNext = nPos + 1;
|
|
if (nNext < sXMLText.GetLength() - 1)
|
|
{
|
|
chX = sXMLText.GetAt(nNext);
|
|
if (chX == _T('/')) //是 /
|
|
{
|
|
levelStack.pop();// 弹出1 个
|
|
if (levelStack.size() < 1)// 如果到等级为1,则认为找到开始的匹配 </
|
|
{
|
|
return nPos;
|
|
}
|
|
nSta = nNext; //否则继续向下找
|
|
}
|
|
else //不是 /
|
|
{
|
|
levelStack.push(1); //增加等级 1
|
|
nSta = nNext; //继续找
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/* xml实例
|
|
<Folder name="设计任务"> = 1 push <
|
|
<Folder name = "ADF"> = 2 push <
|
|
<Folder name = "cde"> = 3 push <
|
|
</Folder> = 2 pop <
|
|
<Folder name = "cde"> = 3 push <
|
|
</Folder> = 2 pop <
|
|
</Folder> = 1 pop <
|
|
<Folder name = "ADF"> = 2 push <
|
|
<Folder name = "cde"> = 3 push
|
|
</Folder> = 2 pop
|
|
</Folder> = 1 pop
|
|
</Folder> = 0 pop 正好为1
|
|
*/
|
|
|
|
BOOL CXMLDocTree::MakeChildren(POSITION pParent,const CString& sXMLText)
|
|
{
|
|
if (pParent == NULL) return FALSE;
|
|
if (sXMLText.GetLength() == 0) return FALSE;
|
|
CString sText,sKeyword,sXData;
|
|
XMLItem* pParentItem = (XMLItem*)pParent;
|
|
|
|
int nFrL = sXMLText.Find(_T('<'),0);
|
|
int nFrR = sXMLText.Find(_T('>'),0);
|
|
|
|
if (nFrL != -1 && nFrR != -1)
|
|
{
|
|
int nToL = sXMLText.Find(_T("</"),nFrR);
|
|
if (nToL != -1)
|
|
{
|
|
if (nToL - nFrR - 1 == 0) //没有内容,说明没有子
|
|
{
|
|
sText = sXMLText.Mid(nFrL + 1,nFrR - nFrL - 1);
|
|
GetKeywordAndXData(sText,sKeyword,sXData);
|
|
|
|
XMLItem* pChild = new XMLItem;
|
|
_tcscpy(pChild->szKeyword,sKeyword);
|
|
_tcscpy(pChild->szXData,sXData);
|
|
pChild->pChildItem = NULL;
|
|
pChild->pNextSiblingItem = NULL;
|
|
pChild->pLastSiblingItem = NULL;
|
|
pChild->pParentItem = pParentItem;
|
|
pParentItem->pChildItem = pChild;
|
|
m_arBuffer.Add(pChild);
|
|
|
|
//建立sibling 的 next;
|
|
int nToR = sXMLText.Find(_T('>'),nToL + 1);
|
|
if (nToR != -1)
|
|
{
|
|
sText = sXMLText.Mid(nToR + 1);
|
|
CString sNext = sText;
|
|
while(!sNext.IsEmpty())
|
|
{
|
|
sNext = _T("");
|
|
MakeNextSiblingItem((POSITION&)pChild,sText,sNext);
|
|
sText = sNext;
|
|
}
|
|
}
|
|
}
|
|
else //有内容,肯能有子[去掉空格有内容]
|
|
{
|
|
CString sText = sXMLText.Mid(nFrR + 1,nToL - nFrR - 1);
|
|
sText.TrimLeft();
|
|
sText.TrimRight();
|
|
|
|
if (sText.IsEmpty()) //没有内容,说明没有子
|
|
{
|
|
sText = sXMLText.Mid(nFrL + 1,nFrR - nFrL - 1);
|
|
GetKeywordAndXData(sText,sKeyword,sXData);
|
|
|
|
XMLItem* pChild = new XMLItem;
|
|
_tcscpy(pChild->szKeyword,sKeyword);
|
|
_tcscpy(pChild->szXData,sXData);
|
|
pChild->pChildItem = NULL;
|
|
pChild->pNextSiblingItem = NULL;
|
|
pChild->pLastSiblingItem = NULL;
|
|
pChild->pParentItem = pParentItem;
|
|
pParentItem->pChildItem = pChild;
|
|
m_arBuffer.Add(pChild);
|
|
|
|
//建立sibling 的 next;
|
|
int nToR = sXMLText.Find(_T('>'),nToL + 1);
|
|
if (nToR != -1)
|
|
{
|
|
sText = sXMLText.Mid(nToR + 1);
|
|
|
|
CString sNext = sText;
|
|
while(!sNext.IsEmpty())
|
|
{
|
|
sNext = _T("");
|
|
MakeNextSiblingItem((POSITION&)pChild,sText,sNext);
|
|
sText = sNext;
|
|
}
|
|
}
|
|
}
|
|
else //中间有子
|
|
{
|
|
//找到下一个平级的 </
|
|
int nToL = FindNextEqualLevelEndtag(sXMLText);
|
|
if (nToL == -1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//本级
|
|
sText = sXMLText.Mid(nFrL + 1,nFrR - nFrL - 1);
|
|
GetKeywordAndXData(sText,sKeyword,sXData);
|
|
|
|
XMLItem* pChild = new XMLItem;
|
|
_tcscpy(pChild->szKeyword,sKeyword);
|
|
_tcscpy(pChild->szXData,sXData);
|
|
pChild->pChildItem = NULL;
|
|
pChild->pNextSiblingItem = NULL;
|
|
pChild->pLastSiblingItem = NULL;
|
|
pChild->pParentItem = pParentItem;
|
|
pParentItem->pChildItem = pChild;
|
|
m_arBuffer.Add(pChild);
|
|
|
|
//继续建立子
|
|
if (nToL - nFrR - 1 > 0)
|
|
{
|
|
sText = sXMLText.Mid(nFrR + 1,nToL - nFrR - 1);
|
|
MakeChildren((POSITION)pChild,sText);
|
|
}
|
|
|
|
//继续建本级的sibling 级
|
|
int nToR = sXMLText.Find(_T('>'),nToL + 1);
|
|
if (nToR != -1 && nToR + 1 < sXMLText.GetLength() - 1)
|
|
{
|
|
sText = sXMLText.Mid(nToR + 1);
|
|
|
|
CString sNext = sText;
|
|
while(!sNext.IsEmpty())
|
|
{
|
|
sNext = _T("");
|
|
MakeNextSiblingItem((POSITION&)pChild,sText,sNext);
|
|
sText = sNext;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXMLDocTree::MakeNextSiblingItem(POSITION& pLast,const CString& sXMLText,CString& sNext)
|
|
{
|
|
sNext = _T("");
|
|
if (pLast == NULL) return FALSE;
|
|
if (sXMLText.IsEmpty()) return FALSE;
|
|
|
|
CString sText,sKeyword,sXData;
|
|
XMLItem* pLastItem = (XMLItem*)pLast;
|
|
|
|
int nFrL = sXMLText.Find(_T('<'),0);
|
|
int nFrR = sXMLText.Find(_T('>'),0);
|
|
|
|
if (nFrL != -1 && nFrR != -1)
|
|
{
|
|
int nToL = sXMLText.Find(_T("</"),nFrR);
|
|
if (nToL != -1)
|
|
{
|
|
if (nToL - nFrR - 1 == 0) //没有内容,说明没有子
|
|
{
|
|
sText = sXMLText.Mid(nFrL + 1,nFrR - nFrL - 1);
|
|
GetKeywordAndXData(sText,sKeyword,sXData);
|
|
|
|
XMLItem* pChild = new XMLItem;
|
|
_tcscpy(pChild->szKeyword,sKeyword);
|
|
_tcscpy(pChild->szXData,sXData);
|
|
pChild->pChildItem = NULL;
|
|
pChild->pNextSiblingItem = NULL;
|
|
|
|
pLastItem->pNextSiblingItem = pChild;
|
|
pChild->pLastSiblingItem = pLastItem;
|
|
pChild->pParentItem = pLastItem->pParentItem;
|
|
|
|
m_arBuffer.Add(pChild);
|
|
|
|
//建立sibling 的 next;
|
|
int nToR = sXMLText.Find(_T('>'),nToL + 1);
|
|
if (nToR != -1)
|
|
{
|
|
pLast = (POSITION)pChild;
|
|
sNext = sXMLText.Mid(nToR + 1);
|
|
return TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CString sText = sXMLText.Mid(nFrR + 1,nToL - nFrR - 1);
|
|
sText.TrimLeft();
|
|
sText.TrimRight();
|
|
|
|
if (sText.IsEmpty()) //没有内容,说明没有子
|
|
{
|
|
sText = sXMLText.Mid(nFrL + 1,nFrR - nFrL - 1);
|
|
GetKeywordAndXData(sText,sKeyword,sXData);
|
|
|
|
XMLItem* pChild = new XMLItem;
|
|
_tcscpy(pChild->szKeyword,sKeyword);
|
|
_tcscpy(pChild->szXData,sXData);
|
|
pChild->pChildItem = NULL;
|
|
pChild->pNextSiblingItem = NULL;
|
|
|
|
pLastItem->pNextSiblingItem = pChild;
|
|
pChild->pLastSiblingItem = pLastItem;
|
|
pChild->pParentItem = pLastItem->pParentItem;
|
|
|
|
m_arBuffer.Add(pChild);
|
|
|
|
//建立sibling 的 next;
|
|
int nToR = sXMLText.Find(_T('>'),nToL + 1);
|
|
if (nToR != -1)
|
|
{
|
|
pLast = (POSITION)pChild;
|
|
sNext = sXMLText.Mid(nToR + 1);
|
|
return TRUE;
|
|
}
|
|
}
|
|
else //中间有子
|
|
{
|
|
//找到下一个平级的 </
|
|
int nToL = FindNextEqualLevelEndtag(sXMLText);
|
|
if (nToL == -1)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
//本级
|
|
sText = sXMLText.Mid(nFrL + 1,nFrR - nFrL - 1);
|
|
GetKeywordAndXData(sText,sKeyword,sXData);
|
|
|
|
XMLItem* pChild = new XMLItem;
|
|
_tcscpy(pChild->szKeyword,sKeyword);
|
|
_tcscpy(pChild->szXData,sXData);
|
|
pChild->pChildItem = NULL;
|
|
pChild->pNextSiblingItem = NULL;
|
|
pLastItem->pNextSiblingItem = pChild;
|
|
pChild->pLastSiblingItem = pLastItem;
|
|
pChild->pParentItem = pLastItem->pParentItem;
|
|
|
|
m_arBuffer.Add(pChild);
|
|
|
|
if (nToL - nFrR - 1 > 0)
|
|
{
|
|
sText = sXMLText.Mid(nFrR + 1,nToL - nFrR - 1);
|
|
MakeChildren((POSITION)pChild,sText);
|
|
}
|
|
|
|
//继续建本级的sibling 级
|
|
int nToR = sXMLText.Find(_T('>'),nToL + 1);
|
|
if (nToR != -1 && nToR + 1 < sXMLText.GetLength())
|
|
{
|
|
pLast = (POSITION)pChild;
|
|
sNext = sXMLText.Mid(nToR + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
POSITION CXMLDocTree::GetRootItem()
|
|
{
|
|
return m_pRoot;
|
|
}
|
|
|
|
BOOL CXMLDocTree::GetKeyword(POSITION ps,CString& sKeyword)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
sKeyword = ((XMLItem*)ps)->szKeyword;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXMLDocTree::GetValueText(POSITION ps,CString& sText)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
sText = ((XMLItem*)ps)->szXData;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL CXMLDocTree::SetValueText(POSITION ps,CString& sText)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
_tcscpy(((XMLItem*)ps)->szXData, sText);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
POSITION CXMLDocTree::GetNextSiblingItem(POSITION ps)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
return (POSITION)((XMLItem*)ps)->pNextSiblingItem;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
POSITION CXMLDocTree::GetPrevSiblingItem(POSITION ps)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
return (POSITION)((XMLItem*)ps)->pLastSiblingItem;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
POSITION CXMLDocTree::GetChildItem(POSITION ps)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
return (POSITION)((XMLItem*)ps)->pChildItem;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
POSITION CXMLDocTree::GetParentItem(POSITION ps)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
return (POSITION)((XMLItem*)ps)->pParentItem;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
BOOL CXMLDocTree::ItemHasChildren(POSITION ps)
|
|
{
|
|
if (ps != NULL)
|
|
{
|
|
return (((XMLItem*)ps)->pChildItem != NULL);
|
|
}
|
|
return FALSE;
|
|
} |