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 + -
显示快捷键?