1081 lines
24 KiB
C++
1081 lines
24 KiB
C++
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// File: xml.cpp
|
||
|
//
|
||
|
// History: 16-Nov-00 markder Created.
|
||
|
//
|
||
|
// Desc: This file contains helper functions to manipulate
|
||
|
// the MSXML's document object model (DOM).
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "StdAfx.h"
|
||
|
#include "xml.h"
|
||
|
|
||
|
void __stdcall _com_issue_error(long)
|
||
|
{
|
||
|
SDBERROR(_T("Unknown COM error!!"));
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// XMLNodeList Implementation
|
||
|
//
|
||
|
// This class is a wrapper for the IXMLDOMNodeList interface. It simplifies
|
||
|
// C++ access by exposing functions for executing XQL queries and iterating
|
||
|
// through the elements in a node list.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
XMLNodeList::XMLNodeList()
|
||
|
{
|
||
|
m_nSize = 0;
|
||
|
}
|
||
|
|
||
|
XMLNodeList::~XMLNodeList()
|
||
|
{
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
void XMLNodeList::Clear()
|
||
|
{
|
||
|
m_nSize = 0;
|
||
|
m_csXQL.Empty();
|
||
|
|
||
|
if (m_cpList) {
|
||
|
m_cpList.Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LONG XMLNodeList::GetSize()
|
||
|
{
|
||
|
return m_nSize;
|
||
|
}
|
||
|
|
||
|
BOOL XMLNodeList::Query(IXMLDOMNode* pNode, LPCTSTR szXQL)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
BSTR bsXQL = NULL;
|
||
|
|
||
|
CString csXQL(szXQL);
|
||
|
bsXQL = csXQL.AllocSysString();
|
||
|
|
||
|
Clear();
|
||
|
|
||
|
if (FAILED(pNode->selectNodes(bsXQL, &m_cpList))) {
|
||
|
CString csFormat;
|
||
|
csFormat.Format(_T("Error executing XQL \"%s\""), szXQL);
|
||
|
SDBERROR(csFormat);
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(m_cpList->get_length(&m_nSize))) {
|
||
|
CString csFormat;
|
||
|
csFormat.Format(_T("Error executing XQL \"%s\""), szXQL);
|
||
|
SDBERROR(csFormat);
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
m_csXQL = szXQL;
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
if (bsXQL != NULL) {
|
||
|
SysFreeString(bsXQL);
|
||
|
}
|
||
|
|
||
|
if (!bSuccess) {
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
BOOL XMLNodeList::GetChildNodes(IXMLDOMNode* pNode)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
|
||
|
Clear();
|
||
|
|
||
|
if (FAILED(pNode->get_childNodes(&m_cpList))) {
|
||
|
SDBERROR(_T("Error retrieving child nodes"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(m_cpList->get_length(&m_nSize))) {
|
||
|
SDBERROR(_T("Error retrieving child nodes"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
|
||
|
if (!bSuccess) {
|
||
|
Clear();
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
BOOL XMLNodeList::GetItem(LONG nIndex, IXMLDOMNode** ppNode)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
|
||
|
if (nIndex < 0 || nIndex >= m_nSize) {
|
||
|
CString csFormat;
|
||
|
csFormat.Format(_T("XMLNodeList index %d out of range for XQL \"%s\""), nIndex, m_csXQL);
|
||
|
SDBERROR(csFormat);
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(m_cpList->get_item(nIndex, ppNode))) {
|
||
|
CString csFormat;
|
||
|
csFormat.Format(_T("XMLNodeList get_item failed for XQL \"%s\""), m_csXQL);
|
||
|
SDBERROR(csFormat);
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: OpenXML
|
||
|
//
|
||
|
// Desc: Opens an XML file or stream and returns the root node.
|
||
|
//
|
||
|
BOOL OpenXML(
|
||
|
CString csFileOrStream,
|
||
|
IXMLDOMNode** ppRootNode,
|
||
|
BOOL bStream,
|
||
|
IXMLDOMDocument** ppDoc)
|
||
|
{
|
||
|
long i;
|
||
|
long nErrorLine = 0;
|
||
|
long nErrorLinePos = 0;
|
||
|
long nListCount = 0;
|
||
|
BOOL bSuccess = FALSE;
|
||
|
BSTR bsSrcText = NULL;
|
||
|
BSTR bsErrorReason = NULL;
|
||
|
HRESULT hr = E_FAIL;
|
||
|
VARIANT vFileOrStream;
|
||
|
VARIANT_BOOL vbSuccess = VARIANT_FALSE;
|
||
|
IXMLDOMDocument* pDoc = NULL;
|
||
|
IXMLDOMParseErrorPtr cpXMLParseError;
|
||
|
|
||
|
VariantInit(&vFileOrStream);
|
||
|
VariantClear(&vFileOrStream);
|
||
|
|
||
|
if (ppDoc == NULL) {
|
||
|
ppDoc = &pDoc;
|
||
|
}
|
||
|
|
||
|
if (*ppDoc == NULL) {
|
||
|
if (FAILED(CoCreateInstance(CLSID_DOMDocument,
|
||
|
NULL,
|
||
|
CLSCTX_INPROC_SERVER,
|
||
|
IID_IXMLDOMDocument,
|
||
|
(LPVOID*)ppDoc))) {
|
||
|
|
||
|
SDBERROR(_T("Could not instantiate MSXML object.\n"));
|
||
|
goto eh;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
vFileOrStream.vt = VT_BSTR;
|
||
|
vFileOrStream.bstrVal = csFileOrStream.AllocSysString();
|
||
|
|
||
|
//
|
||
|
// This statement prevents XML parser from replacing white space
|
||
|
// characters with tabs
|
||
|
//
|
||
|
|
||
|
if (bStream) {
|
||
|
hr = (*ppDoc)->loadXML(vFileOrStream.bstrVal, &vbSuccess);
|
||
|
} else {
|
||
|
(*ppDoc)->put_preserveWhiteSpace(VARIANT_TRUE);
|
||
|
(*ppDoc)->put_validateOnParse(g_bStrict ? VARIANT_TRUE : VARIANT_FALSE);
|
||
|
|
||
|
hr = (*ppDoc)->load(vFileOrStream, &vbSuccess);
|
||
|
}
|
||
|
|
||
|
|
||
|
if (FAILED(hr) || vbSuccess == VARIANT_FALSE) {
|
||
|
|
||
|
if (FAILED((*ppDoc)->get_parseError(&cpXMLParseError))) {
|
||
|
SDBERROR(_T("Could not retrieve XMLDOMParseError object"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpXMLParseError->get_line(&nErrorLine))) {
|
||
|
SDBERROR(_T("Could not retrieve line number from XMLDOMParseError object"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpXMLParseError->get_linepos(&nErrorLinePos))) {
|
||
|
SDBERROR(_T("Could not retrieve line position from XMLDOMParseError object"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpXMLParseError->get_srcText(&bsSrcText))) {
|
||
|
SDBERROR(_T("Could not retrieve source text from XMLDOMParseError object"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpXMLParseError->get_reason(&bsErrorReason))) {
|
||
|
SDBERROR(_T("Could not retrieve error reason from XMLDOMParseError object"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
CString csError;
|
||
|
csError.Format(_T("XML parsing error on line %d:\n\n%ls\n\n%ls\n"),
|
||
|
nErrorLine, bsErrorReason, bsSrcText);
|
||
|
|
||
|
while (nErrorLinePos--) {
|
||
|
csError += " ";
|
||
|
}
|
||
|
|
||
|
csError += _T("^----- Error\n\n");
|
||
|
SDBERROR(csError);
|
||
|
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED((*ppDoc)->QueryInterface(IID_IXMLDOMNode, (LPVOID*)ppRootNode))) {
|
||
|
SDBERROR(_T("Could not retrieve XMLDOMNode object from XMLDOMDocument interface"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
if (pDoc) {
|
||
|
pDoc->Release();
|
||
|
}
|
||
|
|
||
|
if (bsSrcText) {
|
||
|
SysFreeString(bsSrcText);
|
||
|
}
|
||
|
|
||
|
if (bsErrorReason) {
|
||
|
SysFreeString(bsErrorReason);
|
||
|
}
|
||
|
|
||
|
VariantClear(&vFileOrStream);
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: SaveXMLFile
|
||
|
//
|
||
|
// Desc: Saves an XML file.
|
||
|
//
|
||
|
BOOL SaveXMLFile(
|
||
|
CString csFile,
|
||
|
IXMLDOMNode* pNode)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
|
||
|
DWORD dwAttr;
|
||
|
DWORD dwErr;
|
||
|
CString csFormat;
|
||
|
VARIANT vFilename;
|
||
|
HRESULT hr;
|
||
|
|
||
|
IXMLDOMDocumentPtr cpDocument;
|
||
|
|
||
|
VariantInit(&vFilename);
|
||
|
|
||
|
//
|
||
|
// Check file attributes
|
||
|
//
|
||
|
dwAttr = GetFileAttributes(csFile);
|
||
|
if ((DWORD)-1 == dwAttr) {
|
||
|
dwErr = GetLastError();
|
||
|
if (ERROR_FILE_NOT_FOUND != dwErr) {
|
||
|
csFormat.Format(_T("Error accessing XML file: %s (0x%lx)\n"), dwErr);
|
||
|
SDBERROR(csFormat);
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
} else if (dwAttr & FILE_ATTRIBUTE_READONLY) {
|
||
|
csFormat.Format(_T("File \"%s\" appears to be read-only and cannot be updated\n"),
|
||
|
csFile);
|
||
|
SDBERROR(csFormat);
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(pNode->get_ownerDocument(&cpDocument))) {
|
||
|
SDBERROR(_T("Could not retrieve ownerDocument property of node."));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
vFilename.vt = VT_BSTR;
|
||
|
vFilename.bstrVal = csFile.AllocSysString();
|
||
|
hr = cpDocument->save(vFilename);
|
||
|
|
||
|
if (FAILED(hr)) {
|
||
|
csFormat.Format(_T("Could not update XML file: %s (0x%lx)\n"), csFile, (DWORD)hr);
|
||
|
SDBERROR(csFormat);
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
|
||
|
VariantClear(&vFilename);
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
CString ReplaceAmp(
|
||
|
LPCTSTR lpszXML)
|
||
|
{
|
||
|
LPTSTR pchStart = (LPTSTR)lpszXML;
|
||
|
LPTSTR pchEnd;
|
||
|
LPTSTR pchHRef;
|
||
|
LPTSTR pchTag;
|
||
|
TCHAR ch;
|
||
|
CString csXML = ""; // << this is what we return
|
||
|
CString csHRef;
|
||
|
|
||
|
do {
|
||
|
pchHRef = _tcsstr(pchStart, _T("href"));
|
||
|
|
||
|
if (NULL == pchHRef) {
|
||
|
pchHRef = _tcsstr(pchStart, _T("HREF"));
|
||
|
}
|
||
|
|
||
|
if (NULL != pchHRef) {
|
||
|
//
|
||
|
// Find the closing bracket
|
||
|
//
|
||
|
pchEnd = _tcschr(pchHRef, _T('>'));
|
||
|
|
||
|
if (NULL == pchEnd) {
|
||
|
csXML += pchStart;
|
||
|
pchHRef = NULL;
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Now see where this thing starts
|
||
|
//
|
||
|
ch = *pchHRef;
|
||
|
*pchHRef = _T('\0');
|
||
|
|
||
|
//
|
||
|
// Search back to the first '<'
|
||
|
//
|
||
|
pchTag = _tcsrchr(pchStart, _T('<'));
|
||
|
*pchHRef = ch;
|
||
|
|
||
|
if (NULL == pchTag) {
|
||
|
pchTag = pchStart;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now we have < >
|
||
|
//
|
||
|
csHRef = CString(pchTag, (int)(pchEnd - pchTag + 1));
|
||
|
|
||
|
csHRef.Replace(_T("%26"), _T("&"));
|
||
|
csHRef.Replace(_T("&"), _T("&"));
|
||
|
|
||
|
csXML += CString(pchStart, (int)(pchTag-pchStart)) + csHRef;
|
||
|
pchStart = pchEnd + 1;
|
||
|
}
|
||
|
} else {
|
||
|
csXML += pchStart;
|
||
|
}
|
||
|
|
||
|
|
||
|
} while (NULL != pchHRef);
|
||
|
|
||
|
return csXML;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetInnerXML
|
||
|
//
|
||
|
// Desc: Returns the XML between the begin/end tag of pNode.
|
||
|
//
|
||
|
CString GetInnerXML(
|
||
|
IXMLDOMNode* pNode)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
|
||
|
long nIndex = 0;
|
||
|
long nListLength = 0;
|
||
|
IXMLDOMNode* pNodeChild = NULL;
|
||
|
IXMLDOMNodeList* pNodeList = NULL;
|
||
|
DOMNodeType NodeType;
|
||
|
CString csNodeXML;
|
||
|
CString csHRef;
|
||
|
CString csFixedHRef;
|
||
|
CString strXML;
|
||
|
|
||
|
strXML.Empty();
|
||
|
|
||
|
if (FAILED(pNode->get_childNodes(&pNodeList)) || pNodeList == NULL) {
|
||
|
SDBERROR(_T("get_childNodes failed while retrieving innerXML"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(pNodeList->get_length(&nListLength))) {
|
||
|
SDBERROR(_T("get_length failed while retrieving innerXML"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
while (nIndex < nListLength) {
|
||
|
|
||
|
if (FAILED(pNodeList->get_item(nIndex, &pNodeChild))) {
|
||
|
SDBERROR(_T("get_item failed while retrieving innerXML"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
csNodeXML = GetXML(pNodeChild);
|
||
|
|
||
|
strXML += csNodeXML;
|
||
|
|
||
|
pNodeChild->Release();
|
||
|
pNodeChild = NULL;
|
||
|
++nIndex;
|
||
|
}
|
||
|
|
||
|
ReplaceStringNoCase(strXML, _T(" xmlns=\"x-schema:schema.xml\""), _T(""));
|
||
|
|
||
|
|
||
|
eh:
|
||
|
|
||
|
if (NULL != pNodeList) {
|
||
|
pNodeList->Release();
|
||
|
}
|
||
|
|
||
|
if (NULL != pNodeChild) {
|
||
|
pNodeChild->Release();
|
||
|
}
|
||
|
|
||
|
return strXML;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetAttribute
|
||
|
//
|
||
|
// Desc: Returns the text value of the attribute specified by lpszAttribute on node
|
||
|
// pNode. If the the attribute doesn't exist, the function returns FALSE.
|
||
|
//
|
||
|
BOOL GetAttribute(
|
||
|
LPCTSTR lpszAttribute,
|
||
|
IXMLDOMNodePtr pNode,
|
||
|
CString* pcsValue,
|
||
|
BOOL bXML)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
|
||
|
BOOL bSuccess = FALSE;
|
||
|
BSTR bsQuery = NULL;
|
||
|
CString csQuery;
|
||
|
IXMLDOMNodePtr cpAttrNode;
|
||
|
|
||
|
csQuery = _T("@");
|
||
|
csQuery += lpszAttribute;
|
||
|
bsQuery = csQuery.AllocSysString();
|
||
|
|
||
|
//
|
||
|
// g_csError will not be set in this function. It is up
|
||
|
// to the caller to handle a FALSE return from this function
|
||
|
// and report appropriately.
|
||
|
//
|
||
|
if (FAILED(pNode->selectSingleNode(bsQuery, &cpAttrNode))) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (cpAttrNode == NULL) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (bXML) {
|
||
|
*pcsValue = GetXML(cpAttrNode);
|
||
|
} else {
|
||
|
*pcsValue = GetText(cpAttrNode);
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
|
||
|
if (bsQuery != NULL) {
|
||
|
SysFreeString(bsQuery);
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: RemoveAttribute
|
||
|
//
|
||
|
// Desc: Removes the specified attribute from the element.
|
||
|
//
|
||
|
BOOL RemoveAttribute(
|
||
|
CString csName,
|
||
|
IXMLDOMNodePtr pNode)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
|
||
|
BOOL bSuccess = FALSE;
|
||
|
BSTR bsName = NULL;
|
||
|
IXMLDOMNamedNodeMap* pNodeMap = NULL;
|
||
|
IXMLDOMNode* pAttrNode = NULL;
|
||
|
|
||
|
//
|
||
|
// g_csError will not be set in this function. It is up
|
||
|
// to the caller to handle a FALSE return from this function
|
||
|
// and report appropriately.
|
||
|
//
|
||
|
|
||
|
if (FAILED(pNode->get_attributes(&pNodeMap)) || pNodeMap == NULL) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bsName = csName.AllocSysString();
|
||
|
|
||
|
if (FAILED(pNodeMap->removeNamedItem(bsName, &pAttrNode))) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
if (pNodeMap != NULL) {
|
||
|
pNodeMap->Release();
|
||
|
}
|
||
|
|
||
|
if (pAttrNode != NULL) {
|
||
|
pAttrNode->Release();
|
||
|
}
|
||
|
|
||
|
if (bsName != NULL) {
|
||
|
SysFreeString(bsName);
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetChild
|
||
|
//
|
||
|
// Desc: Returns the child node corresponding to the specified tag name.
|
||
|
//
|
||
|
BOOL GetChild(
|
||
|
LPCTSTR lpszTag,
|
||
|
IXMLDOMNode* pParentNode,
|
||
|
IXMLDOMNode** ppChildNode)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
XMLNodeList XQL;
|
||
|
|
||
|
if (!XQL.Query(pParentNode, lpszTag)) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (XQL.GetSize() == 0) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (XQL.GetSize() > 1) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (!XQL.GetItem(0, ppChildNode)) {
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetText
|
||
|
//
|
||
|
// Desc: Returns the value of the text property on node pNode.
|
||
|
//
|
||
|
CString GetText(
|
||
|
IXMLDOMNode* pNode)
|
||
|
{
|
||
|
CString csText;
|
||
|
BSTR bsText = NULL;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = pNode->get_text(&bsText);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
csText = bsText;
|
||
|
|
||
|
if (bsText) {
|
||
|
SysFreeString(bsText);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If get_text fails, then csText is blank.
|
||
|
//
|
||
|
|
||
|
return csText;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetText
|
||
|
//
|
||
|
// Desc: Returns the value of the node pNode, in string form
|
||
|
//
|
||
|
|
||
|
CString GetNodeValue(
|
||
|
IXMLDOMNode* pNode)
|
||
|
{
|
||
|
CString csVal;
|
||
|
VARIANT var;
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
// BUGBUG: what if some of these calls fail!
|
||
|
|
||
|
if (S_OK == pNode->get_nodeValue(&var)) {
|
||
|
if (VT_BSTR == var.vt) {
|
||
|
csVal = var.bstrVal;
|
||
|
if (NULL != var.bstrVal) {
|
||
|
SysFreeString(var.bstrVal);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return csVal;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetText
|
||
|
//
|
||
|
// Desc: Retrieves the value of the text property on node pNode.
|
||
|
// excludes any comment text
|
||
|
// Returns FALSE in case of an error
|
||
|
//
|
||
|
|
||
|
BOOL GetNodeText(
|
||
|
IXMLDOMNode* pNode,
|
||
|
CString& csNodeText
|
||
|
)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
|
||
|
BOOL bSuccess = FALSE;
|
||
|
long nIndex = 0;
|
||
|
long nListLength = 0;
|
||
|
IXMLDOMNode* pNodeText = NULL;
|
||
|
IXMLDOMNodeList* pNodeList = NULL;
|
||
|
DOMNodeType NodeType;
|
||
|
CString csText;
|
||
|
|
||
|
csNodeText.Empty();
|
||
|
|
||
|
if (FAILED(pNode->get_childNodes(&pNodeList)) || pNodeList == NULL) {
|
||
|
// BUGBUG: display some error
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(pNodeList->get_length(&nListLength))) {
|
||
|
// BUGBUG: display some error
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
while (nIndex < nListLength) {
|
||
|
|
||
|
if (FAILED(pNodeList->get_item(nIndex, &pNodeText))) {
|
||
|
// BUGBUG: display some error
|
||
|
goto eh; // can't get the item
|
||
|
}
|
||
|
|
||
|
if (FAILED(pNodeText->get_nodeType(&NodeType))) {
|
||
|
// BUGBUG: display some error
|
||
|
goto eh; // can't get node type
|
||
|
}
|
||
|
|
||
|
if (NODE_TEXT == NodeType) {
|
||
|
//
|
||
|
// now this node is a body text
|
||
|
//
|
||
|
csText = GetNodeValue(pNodeText);
|
||
|
csText.TrimLeft();
|
||
|
csText.TrimRight();
|
||
|
|
||
|
if (!csText.IsEmpty()) {
|
||
|
csNodeText += CString(_T(' ')) + csText;
|
||
|
}
|
||
|
}
|
||
|
pNodeText->Release();
|
||
|
pNodeText = NULL;
|
||
|
|
||
|
++nIndex;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// we have gathered all the text from this node
|
||
|
//
|
||
|
|
||
|
bSuccess = !csNodeText.IsEmpty();
|
||
|
|
||
|
|
||
|
eh:
|
||
|
|
||
|
if (NULL != pNodeList) {
|
||
|
pNodeList->Release();
|
||
|
}
|
||
|
|
||
|
if (NULL != pNodeText) {
|
||
|
pNodeText->Release();
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetNodeName
|
||
|
//
|
||
|
// Desc: Returns the nodeName value from the specified node.
|
||
|
//
|
||
|
CString GetNodeName(
|
||
|
IXMLDOMNode* pNode)
|
||
|
{
|
||
|
CString csName;
|
||
|
BSTR bsName = NULL;
|
||
|
|
||
|
if (SUCCEEDED(pNode->get_nodeName(&bsName))) {
|
||
|
csName = bsName;
|
||
|
}
|
||
|
|
||
|
if (bsName)
|
||
|
SysFreeString(bsName);
|
||
|
|
||
|
//
|
||
|
// If get_nodeName fails, then csName is blank.
|
||
|
//
|
||
|
|
||
|
return csName;
|
||
|
}
|
||
|
|
||
|
CString GetParentNodeName(
|
||
|
IXMLDOMNode* pNode)
|
||
|
{
|
||
|
CString csName;
|
||
|
IXMLDOMNodePtr cpParent;
|
||
|
|
||
|
if (FAILED(pNode->get_parentNode(&cpParent))) {
|
||
|
return CString();
|
||
|
}
|
||
|
|
||
|
return GetNodeName(cpParent);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GetXML
|
||
|
//
|
||
|
// Desc: Returns the value of the xml property on node pNode.
|
||
|
//
|
||
|
CString GetXML(
|
||
|
IXMLDOMNode* pNode)
|
||
|
{
|
||
|
CString csXML;
|
||
|
BSTR bsXML = NULL;
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = pNode->get_xml(&bsXML);
|
||
|
if (SUCCEEDED(hr)) {
|
||
|
csXML = bsXML;
|
||
|
|
||
|
if (bsXML) {
|
||
|
SysFreeString(bsXML);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If get_xml fails, then csXML is blank.
|
||
|
//
|
||
|
return csXML;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: MapStringToLangID
|
||
|
//
|
||
|
// Desc: Returns a LANGID corresponding to the passed in string.
|
||
|
//
|
||
|
LANGID MapStringToLangID(
|
||
|
CString& csLang)
|
||
|
{
|
||
|
typedef struct _LANG_MAP {
|
||
|
LPTSTR szLang;
|
||
|
LANGID LangID;
|
||
|
} LANG_MAP, *PLANG_MAP;
|
||
|
|
||
|
static LANG_MAP s_LangMap[] = {
|
||
|
{ _T("usa"), MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US) },
|
||
|
{ _T(""), NULL }
|
||
|
};
|
||
|
|
||
|
long i;
|
||
|
BOOL bSuccess = FALSE;
|
||
|
LANGID LangID = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
||
|
|
||
|
if (csLang.Left(2) == _T("0x") ||
|
||
|
csLang.Left(2) == _T("0X")) {
|
||
|
_stscanf(csLang, _T("0x%x"), &LangID);
|
||
|
return LangID;
|
||
|
}
|
||
|
|
||
|
i = 0;
|
||
|
while (TRUE) {
|
||
|
if (s_LangMap[i].szLang[0] == _T('\0')) {
|
||
|
//
|
||
|
// End of map.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (0 == _tcsicmp(csLang, s_LangMap[i].szLang)) {
|
||
|
//
|
||
|
// Found string.
|
||
|
//
|
||
|
LangID = s_LangMap[i].LangID;
|
||
|
bSuccess = TRUE;
|
||
|
}
|
||
|
|
||
|
if (bSuccess) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
if (!bSuccess) {
|
||
|
//
|
||
|
// Couldn't map it. Give a useful error; list all recognized values.
|
||
|
//
|
||
|
CString csError;
|
||
|
CString csFormat;
|
||
|
|
||
|
i = 0;
|
||
|
|
||
|
csError = _T("LANG attribute on DATABASE is not one of recognized values:\n\n");
|
||
|
|
||
|
while (TRUE) {
|
||
|
if (s_LangMap[i].szLang[0] == _T('\0')) {
|
||
|
break;
|
||
|
}
|
||
|
csFormat.Format(_T(" %s\n"), s_LangMap[i].szLang);
|
||
|
csError += csFormat;
|
||
|
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
SDBERROR(csError);
|
||
|
}
|
||
|
|
||
|
return LangID;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: AddAttribute
|
||
|
//
|
||
|
// Desc: Adds an attribute to the specified XML node.
|
||
|
//
|
||
|
BOOL AddAttribute(
|
||
|
IXMLDOMNode* pNode,
|
||
|
CString csAttribute,
|
||
|
CString csValue)
|
||
|
{
|
||
|
USES_CONVERSION;
|
||
|
|
||
|
BOOL bSuccess = FALSE;
|
||
|
BSTR bsAttribute = NULL;
|
||
|
VARIANT vType;
|
||
|
VARIANT vValue;
|
||
|
IXMLDOMDocumentPtr cpDocument;
|
||
|
IXMLDOMNamedNodeMapPtr cpNodeMap;
|
||
|
IXMLDOMNodePtr cpAttrNode;
|
||
|
IXMLDOMNodePtr cpNamedAttr;
|
||
|
|
||
|
VariantInit(&vType);
|
||
|
VariantInit(&vValue);
|
||
|
|
||
|
vValue.bstrVal = csValue.AllocSysString();
|
||
|
|
||
|
if (vValue.bstrVal == NULL) {
|
||
|
SDBERROR(_T("CString::AllocSysString failed"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
vValue.vt = VT_BSTR;
|
||
|
|
||
|
vType.vt = VT_I4;
|
||
|
vType.lVal = NODE_ATTRIBUTE;
|
||
|
|
||
|
bsAttribute = csAttribute.AllocSysString();
|
||
|
|
||
|
if (bsAttribute == NULL) {
|
||
|
SDBERROR(_T("CString::AllocSysString failed"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(pNode->get_ownerDocument(&cpDocument))) {
|
||
|
SDBERROR(_T("createNode failed while adding attribute"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpDocument->createNode(vType, bsAttribute, NULL, &cpAttrNode))) {
|
||
|
SDBERROR(_T("createNode failed while adding attribute"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpAttrNode->put_nodeValue(vValue))) {
|
||
|
SDBERROR(_T("put_nodeValue failed while adding attribute"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(pNode->get_attributes(&cpNodeMap))) {
|
||
|
SDBERROR(_T("get_attributes failed while adding adding attribute"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpNodeMap->setNamedItem(cpAttrNode, &cpNamedAttr))) {
|
||
|
SDBERROR(_T("setNamedItem failed while adding adding attribute"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
VariantClear(&vType);
|
||
|
VariantClear(&vValue);
|
||
|
|
||
|
if (bsAttribute != NULL) {
|
||
|
SysFreeString(bsAttribute);
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Func: GenerateIDAttribute
|
||
|
//
|
||
|
// Desc: Adds an ID attribute to the specified XML node. The ID is in the
|
||
|
// traditional Windows GUID format.
|
||
|
//
|
||
|
BOOL GenerateIDAttribute(
|
||
|
IXMLDOMNode* pNode,
|
||
|
CString* pcsGuid,
|
||
|
GUID* pGuid)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
BSTR bsGUID = NULL;
|
||
|
GUID id;
|
||
|
|
||
|
//
|
||
|
// Generate guid
|
||
|
//
|
||
|
if (FAILED(CoCreateGuid(&id))) {
|
||
|
SDBERROR(_T("CoCreateGuid failed"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (NULL != pGuid) {
|
||
|
*pGuid = id;
|
||
|
}
|
||
|
|
||
|
bsGUID = SysAllocStringLen(NULL, 64);
|
||
|
|
||
|
if (bsGUID == NULL) {
|
||
|
SDBERROR(_T("SysAllocStringLen failed"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
StringFromGUID2(id, bsGUID, 64);
|
||
|
|
||
|
if (!AddAttribute( pNode, _T("ID"), CString(bsGUID) )) {
|
||
|
SDBERROR_PROPOGATE();
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
*pcsGuid = bsGUID;
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
if (bsGUID) {
|
||
|
SysFreeString(bsGUID);
|
||
|
}
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|
||
|
|
||
|
BOOL ReplaceXMLNode(IXMLDOMNode* pNode, IXMLDOMDocument* pDoc, BSTR bsText)
|
||
|
{
|
||
|
BOOL bSuccess = FALSE;
|
||
|
IXMLDOMNodePtr cpNewTextNode;
|
||
|
IXMLDOMNodePtr cpParentNode;
|
||
|
IXMLDOMNodePtr cpOldNode;
|
||
|
VARIANT vType;
|
||
|
|
||
|
VariantInit(&vType);
|
||
|
|
||
|
vType.vt = VT_I4;
|
||
|
vType.lVal = NODE_TEXT;
|
||
|
|
||
|
if (FAILED(pDoc->createNode(vType, NULL, NULL, &cpNewTextNode))) {
|
||
|
SDBERROR(_T("createNode failed while adding attribute"));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpNewTextNode->put_text(bsText))) {
|
||
|
SDBERROR(_T("Could not set text property of object."));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(pNode->get_parentNode(&cpParentNode))) {
|
||
|
SDBERROR(_T("Could not retrieve parent node of object."));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
if (FAILED(cpParentNode->replaceChild(cpNewTextNode, pNode, &cpOldNode))) {
|
||
|
SDBERROR(_T("Could not replace node with text node."));
|
||
|
goto eh;
|
||
|
}
|
||
|
|
||
|
bSuccess = TRUE;
|
||
|
|
||
|
eh:
|
||
|
VariantClear(&vType);
|
||
|
|
||
|
return bSuccess;
|
||
|
}
|