xmlfile.cpp
来自「管理项目进度工具的原代码」· C++ 代码 · 共 1,413 行 · 第 1/3 页
CPP
1,413 行
// XmlFile.cpp: implementation of the CXmlFile class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "XmlFile.h"
#include "misc.h"
#include "filemisc.h"
#include "..\3rdparty\xmlnodewrapper.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
#include "xmlcharmap.h"
#include "htmlcharmap.h"
#define TOBSTRING(szValue) CXmlNodeWrapper::ConvertStringToBSTR(szValue)
CString& XML2TXT(CString& xml) { return CHtmlCharMap::ConvertFromRep(xml); } // we use the html map for backwards compatibility
CString& TXT2XML(CString& txt) { return CXmlCharMap::ConvertToRep(txt); }
CString& TXT2HTML(CString& txt) { return CHtmlCharMap::ConvertToRep(txt); }
BOOL CXmlFile::s_bFormatOutput = FALSE;
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
IMPLEMENT_FIXED_ALLOC(CXmlItem, 1024);
CXmlItem::CXmlItem(CXmlItem* pParent, LPCTSTR szName, LPCTSTR szValue, BOOL bCDATA) :
m_pParent(pParent), m_pSibling(NULL), m_sName(szName), m_sValue(szValue), m_bCData(bCDATA)
{
ValidateString(m_sValue);
}
CXmlItem::CXmlItem(const CXmlItem& xi, CXmlItem* pParent) :
m_pParent(pParent), m_pSibling(NULL), m_sName(xi.m_sName), m_sValue(xi.m_sValue), m_bCData(xi.m_bCData)
{
Copy(xi, TRUE);
}
CXmlItem::~CXmlItem()
{
Reset();
}
void CXmlItem::Copy(const CXmlItem& xi, BOOL bCopySiblings)
{
Reset();
// copy own name and value
m_sName = xi.GetName();
m_sValue = xi.GetValue();
// copy siblings
if (bCopySiblings)
{
const CXmlItem* pXISibling = xi.GetSibling();
if (pXISibling)
m_pSibling = new CXmlItem(*pXISibling, m_pParent);
}
// copy children
POSITION pos = xi.GetFirstItemPos();
while (pos)
{
const CXmlItem* pXIChild = xi.GetNextItem(pos);
ASSERT (pXIChild);
AddItem(*pXIChild, TRUE);
}
}
void CXmlItem::Reset()
{
// delete children
POSITION pos = m_mapItems.GetStartPosition();
while (pos)
{
CXmlItem* pXI = NULL;
CString sItem;
m_mapItems.GetNextAssoc(pos, sItem, pXI);
delete pXI;
}
m_mapItems.RemoveAll();
// and siblings
// note: because sibling ~tor calls its own Reset() the chain
// of siblings will be correctly cleaned up
delete m_pSibling;
m_pSibling = NULL;
m_bCData = FALSE;
}
const CXmlItem* CXmlItem::GetItem(LPCTSTR szItemName, LPCTSTR szSubItem) const
{
return GetItemEx(szItemName, szSubItem);
}
CXmlItem* CXmlItem::GetItem(LPCTSTR szItemName, LPCTSTR szSubItem)
{
// cast away constness
return (CXmlItem*)GetItemEx(szItemName, szSubItem);
}
// special internal version
const CXmlItem* CXmlItem::GetItemEx(LPCTSTR szItemName, LPCTSTR szSubItem) const
{
CXmlItem* pXI = NULL;
m_mapItems.Lookup(szItemName, pXI);
if (pXI && szSubItem && *szSubItem)
return pXI->GetItem(szSubItem);
return pXI;
}
const CXmlItem* CXmlItem::FindItem(LPCTSTR szItemName, LPCTSTR szItemValue, BOOL bSearchChildren) const
{
return FindItemEx(szItemName, szItemValue, bSearchChildren);
}
CXmlItem* CXmlItem::FindItem(LPCTSTR szItemName, LPCTSTR szItemValue, BOOL bSearchChildren)
{
// cast away constness
return (CXmlItem*)FindItemEx(szItemName, szItemValue, bSearchChildren);
}
const CXmlItem* CXmlItem::FindItem(LPCTSTR szItemName, int nItemValue, BOOL bSearchChildren) const
{
return FindItemEx(szItemName, ToString(nItemValue), bSearchChildren);
}
const CXmlItem* CXmlItem::FindItem(LPCTSTR szItemName, double dItemValue, BOOL bSearchChildren) const
{
return FindItemEx(szItemName, ToString(dItemValue), bSearchChildren);
}
CXmlItem* CXmlItem::FindItem(LPCTSTR szItemName, int nItemValue, BOOL bSearchChildren)
{
// cast away constness
return (CXmlItem*)FindItemEx(szItemName, ToString(nItemValue), bSearchChildren);
}
CXmlItem* CXmlItem::FindItem(LPCTSTR szItemName, double dItemValue, BOOL bSearchChildren)
{
// cast away constness
return (CXmlItem*)FindItemEx(szItemName, ToString(dItemValue), bSearchChildren);
}
// special internal version
const CXmlItem* CXmlItem::FindItemEx(LPCTSTR szItemName, LPCTSTR szItemValue, BOOL bSearchChildren) const
{
// check our name and value
if (m_sName.CompareNoCase(szItemName) == 0 && m_sValue.Compare(szItemValue) == 0)
return this;
const CXmlItem* pFound = NULL;
// search all our children
if (bSearchChildren)
{
POSITION pos = GetFirstItemPos();
while (pos && !pFound)
{
const CXmlItem* pXIChild = GetNextItem(pos);
ASSERT (pXIChild);
pFound = pXIChild->FindItemEx(szItemName, szItemValue, TRUE); // child will search its own siblings
}
}
// then our siblings
if (!pFound)
{
// only get first sibling as each sibling does its own
const CXmlItem* pXISibling = GetSibling();
if (pXISibling)
pFound = pXISibling->FindItemEx(szItemName, szItemValue, TRUE);
}
return pFound;
}
LPCTSTR CXmlItem::GetItemValue(LPCTSTR szItemName, LPCTSTR szSubItem) const
{
const CXmlItem* pXI = GetItem(szItemName, szSubItem);
if (pXI)
return pXI->GetValue();
else
{
static CString NULL_VALUE;
return NULL_VALUE;
}
}
int CXmlItem::GetItemCount(LPCTSTR szItemName) const
{
int nCount = 0;
const CXmlItem* pXI = GetItem(szItemName);
while (pXI)
{
nCount++;
pXI = pXI->GetSibling();
}
return nCount;
}
CXmlItem* CXmlItem::AddItem(LPCTSTR szName, LPCTSTR szValue, BOOL bCDATA)
{
ASSERT (szName && *szName);
if (!(szName && *szName))
return NULL;
CXmlItem* pXI = new CXmlItem(this, szName, szValue, bCDATA);
return AddItem(pXI);
}
CXmlItem* CXmlItem::AddItem(const CXmlItem& xi, BOOL bCopySiblings)
{
CXmlItem* pXI = new CXmlItem(this);
pXI->Copy(xi, bCopySiblings);
return AddItem(pXI);
}
CXmlItem* CXmlItem::AddItem(CXmlItem* pXI)
{
CXmlItem* pXIParent = pXI->GetParent();
if (pXIParent && pXIParent != this)
pXIParent->RemoveItem(pXI);
pXI->m_pParent = this;
// if an item of the same name already exists then add this
// item as a sibling to the existing item else its a new item
// so add and map name to this object
CXmlItem* pXPExist = GetItem(pXI->GetName());
if (pXPExist)
pXPExist->AddSibling(pXI);
else
m_mapItems[pXI->GetName()] = pXI;
return pXI;
}
CXmlItem* CXmlItem::AddItem(LPCTSTR szName, int nValue)
{
return AddItem(szName, ToString(nValue));
}
CXmlItem* CXmlItem::AddItem(LPCTSTR szName, double dValue)
{
return AddItem(szName, ToString(dValue));
}
CXmlItem* CXmlItem::SetItemValue(LPCTSTR szName, LPCTSTR sValue, BOOL bCData)
{
CXmlItem* pXI = GetItem(szName);
if (!pXI)
return AddItem(szName, sValue, bCData);
// else already exists
pXI->SetValue(sValue);
pXI->SetCDATA(bCData);
return pXI;
}
CXmlItem* CXmlItem::SetItemValue(LPCTSTR szName, int nValue)
{
return SetItemValue(szName, ToString(nValue));
}
CXmlItem* CXmlItem::SetItemValue(LPCTSTR szName, double dValue)
{
return SetItemValue(szName, ToString(dValue));
}
BOOL CXmlItem::SetName(LPCTSTR szName)
{
// can't have any siblings
if (!szName || !(*szName) || GetSibling())
return FALSE;
m_sName = szName;
return TRUE;
}
void CXmlItem::SetValue(LPCTSTR szValue)
{
m_sValue = szValue;
ValidateString(m_sValue);
}
void CXmlItem::SetValue(int nValue)
{
m_sValue = ToString(nValue);
}
void CXmlItem::SetValue(double dValue)
{
m_sValue = ToString(dValue);
}
BOOL CXmlItem::RemoveItem(CXmlItem* pXI)
{
if (!pXI)
return FALSE;
// lookup by name first
LPCTSTR szName = pXI->GetName();
CXmlItem* pXIMatch = GetItem(szName);
if (!pXIMatch)
return FALSE;
// now search the sibling chain looking for exact match
CXmlItem* pXIPrevSibling = NULL;
while (pXIMatch != pXI)
{
pXIPrevSibling = pXIMatch;
pXIMatch = pXIMatch->GetSibling();
}
if (!pXIMatch) // no match
return FALSE;
// else
ASSERT (pXIMatch == pXI);
CXmlItem* pNextSibling = pXI->GetSibling();
if (!pXIPrevSibling) // head of the chain
{
if (!pNextSibling)
m_mapItems.RemoveKey(szName);
else
m_mapItems[szName] = pNextSibling;
}
else // somewhere else in the chain
{
pXIPrevSibling->m_pSibling = pNextSibling; // can be NULL
}
// clear item's sibling
pXI->m_pSibling = NULL;
// and parent
pXI->m_pParent = NULL;
return TRUE;
}
BOOL CXmlItem::DeleteItem(CXmlItem* pXI)
{
if (RemoveItem(pXI))
{
delete pXI;
return TRUE;
}
return FALSE;
}
BOOL CXmlItem::DeleteItem(LPCTSTR szItemName)
{
CXmlItem* pXI = GetItem(szItemName);
if (pXI)
{
pXI->Reset(); // delete children and siblings
DeleteItem(pXI); // delete pXI
}
return TRUE;
}
BOOL CXmlItem::AddSibling(CXmlItem* pXI)
{
ASSERT (pXI);
if (!pXI)
return FALSE;
// must share the same name and parent
ASSERT (m_sName.CompareNoCase(pXI->GetName()) == 0 && m_pParent == pXI->GetParent());
if (!(m_sName.CompareNoCase(pXI->GetName()) == 0 && m_pParent == pXI->GetParent()))
return FALSE;
if (!m_pSibling)
m_pSibling = pXI;
else
m_pSibling->AddSibling(pXI); // recursive
return TRUE;
}
POSITION CXmlItem::GetFirstItemPos() const
{
return m_mapItems.GetStartPosition();
}
const CXmlItem* CXmlItem::GetNextItem(POSITION& pos) const
{
if (!pos)
return NULL;
CString sTemp;
CXmlItem* pItem = NULL;
m_mapItems.GetNextAssoc(pos, sTemp, pItem);
return pItem;
}
CXmlItem* CXmlItem::GetNextItem(POSITION& pos)
{
if (!pos)
return NULL;
CString sTemp;
CXmlItem* pItem = NULL;
m_mapItems.GetNextAssoc(pos, sTemp, pItem);
return pItem;
}
BOOL CXmlItem::NameMatches(const CXmlItem* pXITest) const
{
if (!pXITest)
return FALSE;
return NameMatches(pXITest->GetName());
}
BOOL CXmlItem::NameMatches(LPCTSTR szName) const
{
return (m_sName.CompareNoCase(szName) == 0);
}
BOOL CXmlItem::ValueMatches(const CXmlItem* pXITest, BOOL bIgnoreCase) const
{
if (!pXITest)
return FALSE;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?