Files
gjm 164968b62e chore
把非utf8-bom编码的cpp/h文件改为 utf8 bom 编码, msvc识别utf8编码时,如果不是bom格式的,会使用当前cp_oem来解码.
2026-10-04 00:04:20 +08:00

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;
}