547 lines
11 KiB
C++
547 lines
11 KiB
C++
//-----------------------------------------------------------------------------+
|
|
// Copyright (C), 1998-2007, Beijing Tangent Software Co. Ltd.
|
|
// = FileName : TXmlTree.cpp
|
|
// = Version : ver1.0
|
|
// = Author : xlc
|
|
// = CreateDate :
|
|
// = Description:
|
|
// = Maintainers:
|
|
//
|
|
//-----------------------------------------------------------------------------+
|
|
#include "StdAfx.h"
|
|
#include "TXmlTree.h"
|
|
|
|
//内部类
|
|
class TXmlNode
|
|
{
|
|
friend class TXmlTree;
|
|
public:
|
|
|
|
TXmlNode();
|
|
virtual ~TXmlNode();
|
|
|
|
void SetName(LPCTSTR pszName);
|
|
CString GetName() const;
|
|
|
|
void SetText(LPCTSTR pszText);
|
|
CString GetText() const;
|
|
|
|
//属性操作
|
|
void SetAt(LPCTSTR pszKey,LPCTSTR pszVal);
|
|
BOOL Lookup(LPCTSTR key, CString& rValue) const;
|
|
|
|
BOOL RemoveKey(LPCTSTR key);
|
|
void RemoveAll();
|
|
|
|
POSITION GetStartPosition() const;
|
|
void GetNextAssoc(POSITION& rNextPosition, CString& rKey, CString& rValue) const;
|
|
|
|
CString GetXml() const;
|
|
|
|
protected:
|
|
|
|
//数据
|
|
CMapStringToString m_mapKeyToVal; //属性
|
|
CString m_sName; //标签
|
|
CString m_sText; //文本
|
|
|
|
//前后关系
|
|
POSITION m_posPrevious;
|
|
POSITION m_posNext;
|
|
|
|
//上下关系
|
|
POSITION m_posParent;
|
|
POSITION m_posChild;
|
|
};
|
|
|
|
TXmlNode::TXmlNode()
|
|
{
|
|
m_sName = _T("");
|
|
m_sText = _T("");
|
|
m_posChild = NULL;
|
|
m_posParent = NULL;
|
|
m_posPrevious = NULL;
|
|
m_posNext = NULL;
|
|
}
|
|
|
|
TXmlNode::~TXmlNode()
|
|
{
|
|
|
|
}
|
|
|
|
void TXmlNode::SetName(LPCTSTR pszName)
|
|
{
|
|
m_sName = pszName;
|
|
}
|
|
|
|
CString TXmlNode::GetName() const
|
|
{
|
|
return m_sName;
|
|
}
|
|
|
|
void TXmlNode::SetText(LPCTSTR pszText)
|
|
{
|
|
m_sText = pszText;
|
|
}
|
|
|
|
CString TXmlNode::GetText() const
|
|
{
|
|
return m_sText;
|
|
}
|
|
|
|
//属性操作
|
|
void TXmlNode::SetAt(LPCTSTR pszKey,LPCTSTR pszVal)
|
|
{
|
|
m_mapKeyToVal.SetAt(pszKey, pszVal);
|
|
}
|
|
|
|
BOOL TXmlNode::Lookup(LPCTSTR key, CString& rValue) const
|
|
{
|
|
return m_mapKeyToVal.Lookup(key, rValue);
|
|
}
|
|
|
|
BOOL TXmlNode::RemoveKey(LPCTSTR key)
|
|
{
|
|
return m_mapKeyToVal.RemoveKey(key);
|
|
}
|
|
|
|
void TXmlNode::RemoveAll()
|
|
{
|
|
m_mapKeyToVal.RemoveAll();
|
|
}
|
|
|
|
POSITION TXmlNode::GetStartPosition() const
|
|
{
|
|
return m_mapKeyToVal.GetStartPosition();
|
|
}
|
|
|
|
void TXmlNode::GetNextAssoc(POSITION& rNextPosition, CString& rKey, CString& rValue) const
|
|
{
|
|
m_mapKeyToVal.GetNextAssoc(rNextPosition, rKey, rValue);
|
|
}
|
|
|
|
CString TXmlNode::GetXml() const
|
|
{
|
|
if (m_sName.IsEmpty())
|
|
{
|
|
return _T("");
|
|
}
|
|
|
|
CString strXML;
|
|
strXML += _T("\n<") +m_sName;
|
|
|
|
CString strKey;
|
|
CString strVal;
|
|
POSITION pos = GetStartPosition();
|
|
while (pos != NULL)
|
|
{
|
|
GetNextAssoc(pos, strKey, strVal);
|
|
strXML += _T(" ") + strKey + _T(" = \"") + strVal + _T("\"");
|
|
}
|
|
|
|
strXML += _T(">") + m_sText;
|
|
if(m_posChild != NULL)
|
|
{
|
|
TXmlNode* pNodeChild = (TXmlNode*)m_posChild;
|
|
|
|
// 遍历前节点
|
|
POSITION posPre = pNodeChild->m_posPrevious;
|
|
CString strNode;
|
|
CStringArray strArray;
|
|
while (posPre != NULL)
|
|
{
|
|
strNode = ((TXmlNode*)posPre)->GetXml();
|
|
strArray.Add(strNode);
|
|
|
|
posPre = ((TXmlNode*)posPre)->m_posPrevious;
|
|
}
|
|
|
|
for (int i = strArray.GetSize() - 1; i >= 0; i--)
|
|
{
|
|
strXML += strArray[i];
|
|
}
|
|
|
|
// 当前节点
|
|
strXML += pNodeChild->GetXml();
|
|
|
|
// 遍历后节点
|
|
POSITION posNext = pNodeChild->m_posNext;
|
|
while (posNext != NULL)
|
|
{
|
|
strXML += ((TXmlNode*)posNext)->GetXml();
|
|
posNext = ((TXmlNode*)posNext)->m_posNext;
|
|
}
|
|
|
|
strXML += _T("\n");
|
|
}
|
|
|
|
strXML += _T("</") + m_sName + _T(">");
|
|
return strXML;
|
|
}
|
|
|
|
TXmlTree::TXmlTree()
|
|
{
|
|
m_sDeclaration = _T("");
|
|
m_sComment = _T("");
|
|
DeleteAllItems();
|
|
}
|
|
|
|
TXmlTree::~TXmlTree()
|
|
{
|
|
DeleteAllItems();
|
|
}
|
|
|
|
CString TXmlTree::GetXml()
|
|
{
|
|
if (GetCount() <= 0)
|
|
{
|
|
return _T("");
|
|
}
|
|
|
|
POSITION posItem = GetRootItem();
|
|
if (posItem != NULL)
|
|
{
|
|
CString strXML;
|
|
if (!m_sDeclaration.IsEmpty())
|
|
{
|
|
strXML += m_sDeclaration;
|
|
}
|
|
|
|
if (!m_sComment.IsEmpty())
|
|
{
|
|
strXML += _T("\n<!-- ") + m_sComment + _T(" -->");
|
|
}
|
|
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
strXML += pNode->GetXml();
|
|
return strXML;
|
|
}
|
|
|
|
return _T("");
|
|
}
|
|
|
|
POSITION TXmlTree::GetRootItem()
|
|
{
|
|
if (GetCount() <= 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
POSITION rootItem=NULL;
|
|
POSITION posItem = (POSITION)m_lstItemPtrs.GetHead();
|
|
while(posItem != NULL)
|
|
{
|
|
rootItem = posItem;
|
|
posItem = GetParentItem(rootItem);
|
|
}
|
|
return rootItem;
|
|
}
|
|
|
|
//<?xml version="1.0" encoding="UTF-8"?>
|
|
void TXmlTree::SetDeclaration(LPCTSTR pszVer, LPCTSTR pszEncoding)
|
|
{
|
|
if (pszVer == NULL || pszEncoding == NULL)
|
|
{
|
|
m_sDeclaration = _T("");
|
|
}
|
|
else
|
|
{
|
|
m_sDeclaration.Format(_T("<?xml version=\"%s\" encoding=\"%s\"?>"), pszVer, pszEncoding);
|
|
}
|
|
}
|
|
|
|
CString TXmlTree::GetDeclaration() const
|
|
{
|
|
return m_sDeclaration;
|
|
}
|
|
|
|
//<!-- Copy text, comments and processing instructions. -->
|
|
void TXmlTree::SetComment(LPCTSTR pszComment)
|
|
{
|
|
m_sComment = pszComment;
|
|
}
|
|
|
|
CString TXmlTree::GetCommnet() const
|
|
{
|
|
return m_sComment;
|
|
}
|
|
|
|
BOOL TXmlTree::SetItemText(POSITION posItem,LPCTSTR pszText)
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL)
|
|
{
|
|
pNode->SetText(pszText);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
CString TXmlTree::GetItemText(POSITION posItem) const
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL)
|
|
{
|
|
return pNode->GetText();
|
|
}
|
|
|
|
return CString(_T(""));
|
|
}
|
|
|
|
BOOL TXmlTree::SetAttribute(POSITION posItem,LPCTSTR pszKey,LPCTSTR pszVal)
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL)
|
|
{
|
|
pNode->SetAt(pszKey, pszVal);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
CString TXmlTree::GetAttribute(POSITION posItem,LPCTSTR pszKey) const
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL)
|
|
{
|
|
CString strVal;
|
|
pNode->Lookup(pszKey, strVal);
|
|
return strVal;
|
|
}
|
|
|
|
return CString(_T(""));
|
|
}
|
|
|
|
POSITION TXmlTree::Insert(LPCTSTR pszItem,POSITION posParent,POSITION posInsertAfter)
|
|
{
|
|
TXmlNode* pNodeParent = (TXmlNode*)posParent;
|
|
TXmlNode* pNodeInsertAfter = (TXmlNode*)posInsertAfter;
|
|
|
|
if (pNodeParent != NULL)
|
|
{
|
|
// 新节点与插入节点的父节点不一致时不插入
|
|
if (pNodeInsertAfter && pNodeInsertAfter->m_posParent != posParent)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
TXmlNode* pNodeNew = new TXmlNode();
|
|
pNodeNew->SetName(pszItem);
|
|
pNodeNew->m_posParent = posParent;
|
|
|
|
if (pNodeParent->m_posChild != NULL) //有孩子节点
|
|
{
|
|
if (pNodeInsertAfter == NULL) //没有插入节点
|
|
{
|
|
POSITION posNextItem = pNodeParent->m_posChild;
|
|
POSITION posInsertItem = NULL;
|
|
while(posNextItem != NULL)
|
|
{
|
|
posInsertItem = posNextItem;
|
|
posNextItem = ((TXmlNode*)posNextItem)->m_posNext;
|
|
}
|
|
|
|
pNodeNew->m_posPrevious = posInsertItem;
|
|
((TXmlNode*)posInsertItem)->m_posNext = (POSITION)pNodeNew;
|
|
}
|
|
else
|
|
{
|
|
POSITION posNextItem = pNodeInsertAfter->m_posNext;
|
|
if (posNextItem == NULL) //节点末尾
|
|
{
|
|
pNodeNew->m_posPrevious = posInsertAfter;
|
|
pNodeInsertAfter->m_posNext = (POSITION)pNodeNew;
|
|
}
|
|
else
|
|
{
|
|
((TXmlNode*)posNextItem)->m_posPrevious = (POSITION)pNodeNew;
|
|
pNodeInsertAfter->m_posNext = (POSITION)pNodeNew;
|
|
pNodeNew->m_posPrevious = posInsertAfter;
|
|
pNodeNew->m_posNext = posNextItem;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pNodeParent->m_posChild = (POSITION)pNodeNew;
|
|
}
|
|
|
|
m_lstItemPtrs.AddTail(pNodeNew);
|
|
return (POSITION)pNodeNew;
|
|
}
|
|
else
|
|
{
|
|
if (GetCount() == 0) //插入根节点
|
|
{
|
|
TXmlNode* pNodeNew = new TXmlNode();
|
|
pNodeNew->SetName(pszItem);
|
|
|
|
m_lstItemPtrs.AddTail(pNodeNew);
|
|
return (POSITION)pNodeNew;
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL TXmlTree::ItemHasChildren(POSITION posItem) const
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL && pNode->m_posChild != NULL)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
POSITION TXmlTree::GetChildItem(POSITION posParent) const
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posParent;
|
|
if (pNode != NULL && pNode->m_posChild != NULL)
|
|
{
|
|
return pNode->m_posChild;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
POSITION TXmlTree::GetParentItem(POSITION posItem) const
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL && pNode->m_posParent != NULL)
|
|
{
|
|
return pNode->m_posParent;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
POSITION TXmlTree::GetNextSiblingItem(POSITION posItem) const
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL && pNode->m_posNext != NULL)
|
|
{
|
|
return pNode->m_posNext;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
POSITION TXmlTree::GetPrevSiblingItem(POSITION posItem) const
|
|
{
|
|
TXmlNode* pNode = (TXmlNode*)posItem;
|
|
if (pNode != NULL && pNode->m_posPrevious != NULL)
|
|
{
|
|
return pNode->m_posPrevious;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
BOOL TXmlTree::DeleteItem(POSITION posItem)
|
|
{
|
|
if (posItem == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
TXmlNode* pNodeItem = (TXmlNode*)posItem;
|
|
POSITION posPreItem = GetPrevSiblingItem(posItem);
|
|
POSITION posNextItem = GetNextSiblingItem(posItem);
|
|
POSITION posParent = GetParentItem(posItem);
|
|
|
|
if (posParent == NULL) //删除根节点时全部删除
|
|
{
|
|
DeleteAllItems();
|
|
return TRUE;
|
|
}
|
|
else if (((TXmlNode*)posParent)->m_posChild == posItem) //孩子节点为当前节点
|
|
{
|
|
// 修改节点上下连接关系
|
|
if (posPreItem != NULL)
|
|
{
|
|
((TXmlNode*)posParent)->m_posChild = posPreItem;
|
|
}
|
|
else
|
|
{
|
|
((TXmlNode*)posParent)->m_posChild = posNextItem;
|
|
}
|
|
}
|
|
|
|
//修改节点前后连接关系
|
|
if (posPreItem == NULL && posNextItem == NULL) //删除唯一孩子结点
|
|
{
|
|
|
|
}
|
|
else if (posPreItem == NULL) //删除头节点
|
|
{
|
|
((TXmlNode*)posNextItem)->m_posPrevious = NULL;
|
|
}
|
|
else if (posNextItem == NULL) //删除尾节点
|
|
{
|
|
((TXmlNode*)posPreItem)->m_posNext = NULL;
|
|
}
|
|
else //删除头节点
|
|
{
|
|
((TXmlNode*)posPreItem)->m_posNext = posNextItem;
|
|
((TXmlNode*)posNextItem)->m_posPrevious = posPreItem;
|
|
}
|
|
|
|
//遍历孩子节点
|
|
if (pNodeItem->m_posChild != NULL)
|
|
{
|
|
POSITION posChild = GetChildItem(posItem);
|
|
posPreItem = GetPrevSiblingItem(posChild);
|
|
posNextItem = GetNextSiblingItem(posChild);
|
|
POSITION pos = NULL;
|
|
while (posPreItem != NULL) //删除孩子节点前的兄弟节点
|
|
{
|
|
pos = posPreItem;
|
|
posPreItem = GetPrevSiblingItem(pos);
|
|
DeleteItem(pos);
|
|
}
|
|
DeleteItem(posChild); //删除孩子节点
|
|
|
|
while (posNextItem != NULL) //删除孩子节点后的兄弟节点
|
|
{
|
|
pos = posNextItem;
|
|
posNextItem = GetNextSiblingItem(pos);
|
|
DeleteItem(pos);
|
|
}
|
|
pNodeItem->m_posChild = NULL;
|
|
}
|
|
|
|
POSITION pos = m_lstItemPtrs.Find(pNodeItem);
|
|
TXmlNode* pNode = (TXmlNode*)m_lstItemPtrs.GetAt(pos);
|
|
if (pNode)
|
|
{
|
|
delete pNode;
|
|
}
|
|
m_lstItemPtrs.RemoveAt(pos);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL TXmlTree::DeleteAllItems()
|
|
{
|
|
POSITION posItem = NULL;
|
|
for (int i = 0; i < m_lstItemPtrs.GetCount(); i++)
|
|
{
|
|
posItem = m_lstItemPtrs.FindIndex(i);
|
|
TXmlNode* pNode = (TXmlNode*)m_lstItemPtrs.GetAt(posItem);
|
|
if (pNode)
|
|
{
|
|
delete pNode;
|
|
}
|
|
}
|
|
m_lstItemPtrs.RemoveAll();
|
|
return TRUE;
|
|
}
|
|
|
|
UINT TXmlTree::GetCount() const
|
|
{
|
|
return m_lstItemPtrs.GetCount();
|
|
} |