Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

Design

An MFC Wrapper for MSXML


February 2001/An MFC Wrapper for MSXML/Listing 2

Listing 2: xmlif.cpp — Implementation of CXmlIF

/***
*  MODULE:  XmlIF.cpp
*  PURPOSE: Implementation...XML Interface Class
*  AUTHOR:  Ben Campione
***/
#include "stdafx.h"
#include "XmlIF.h"

// Initialize XML Interface Object
bool CXmlIF::Initialize(void)
{
  // Initialize Members
  ClearParseError();
  m_szURL[0]     = 0;
  m_bInitialized = FALSE;
  m_bLoaded      = FALSE;
  m_pDoc         = NULL;
  m_pDocNode     = NULL;

  // Initialize COM Library
  if (CoInitialize(NULL) == S_OK)
    {
    // Create An Empty XML Document
    m_hr = CoCreateInstance(MS_XML_NS::CLSID_DOMDocument, 
                            NULL, CLSCTX_INPROC_SERVER,
                            MS_XML_NS::IID_IXMLDOMDocument, 
                            (void**) &m_pDoc);

    m_bInitialized = (m_hr == S_OK) ? TRUE : FALSE;
    if (m_bInitialized) m_pDoc->put_async(VARIANT_FALSE);
    }

  return m_bInitialized;
}

// UnInitialize XML Interface Object
void CXmlIF::UnInitialize(void)
{
  // Cleanup Allocated Memory
  if (m_pDocNode) m_pDocNode->Release(); 
  if (m_pDoc)     m_pDoc->Release(); 

  // Uninitialize COM Library
  CoUninitialize();

  // Initialize Members
  ClearParseError();
  m_szURL[0]     = 0;
  m_bInitialized = FALSE;
  m_bLoaded      = FALSE;
  m_pDocNode     = NULL;
  m_pDoc         = NULL;
}

// Convert ascii string to BSTR
BSTR CXmlIF::AsciiToBSTR(const char* pszString)
{
  WCHAR wszURL[XIF_MAX_STRING+1];
  ::MultiByteToWideChar(CP_ACP, 0, pszString, -1, wszURL, XIF_MAX_STRING);
  return (::SysAllocString(wszURL));
}

// Convert ascii string to BSTR
char* CXmlIF::BSTRToAscii(const BSTR pwszString)
{
  char* pszURL = new char[XIF_MAX_STRING+1];
  ::WideCharToMultiByte(CP_ACP, 0, pwszString, -1, 
                        pszURL, XIF_MAX_STRING, NULL, NULL);
  return pszURL;
}

// Get XML File Parsing Error Information
void CXmlIF::GetParseError(MS_XML_NS::IXMLDOMParseError *pXMLError)
{
  if (pXMLError)
    {
    BSTR pBReason;
    pXMLError->get_reason(&pBReason);
    pXMLError->get_line(&m_lErrLine);
    pXMLError->get_linepos(&m_lErrPos);

    char* pszReason = BSTRToAscii(pBReason);
    strncpy(m_szErrReason, pszReason, XIF_MAX_STRING);
    ::SysFreeString(pBReason);
    delete pszReason;
    }
}

// Clear XML File Parsing Error Information
void CXmlIF::ClearParseError(void)
{
  m_szErrReason[0] = 0;
  m_lErrLine       = -1;
  m_lErrPos        = -1;
}

// Check Document Load Results
HRESULT CXmlIF::CheckLoad(MS_XML_NS::IXMLDOMDocument* pDoc)
{
  // Since We Don't Have The VARIANT_BOOL From LoadDocument(),
  // Check The Parse Error Property (errorCode) To Validate
  LONG errorCode = E_FAIL;
  MS_XML_NS::IXMLDOMParseError *pXMLError = NULL;
  if (pDoc->get_parseError(&pXMLError) == S_OK)
    {
    if (pXMLError->get_errorCode(&errorCode) == S_OK)
      {
      if (errorCode != 0) GetParseError(pXMLError);
      else                ClearParseError();
      }
    }

  pXMLError->Release(); 
  return errorCode;
}

// Load XML Document From Specified URL
bool CXmlIF::LoadDocument(const char* szURL)
{
  // Must Be Initialized Prior To Loading Document
  if (!m_bInitialized || !szURL) return FALSE;

  // Convert File Name To BSTR
  strncpy(m_szURL, szURL, _MAX_PATH);
  BSTR pBURL = AsciiToBSTR(m_szURL);

  // Setup Variant URL For Load Method
  VARIANT vURL;
  VariantInit(&vURL);
  vURL.vt = VT_BSTR;
  V_BSTR(&vURL) = pBURL;

  // Load Xml Document From Specified URL
  m_bLoaded = FALSE;
  VARIANT_BOOL vb;
  if ((m_hr=GetDocument()->XML_LOAD(vURL, &vb)) == S_OK)
    {
    if (!CheckLoad(GetDocument())) m_bLoaded = TRUE;
    }

  // Set Member Document And Current Node To Top Level Node
  SetDocumentNode();

  ::SysFreeString(pBURL);
  return m_bLoaded;
}

// Save XML Document To Specified URL
bool CXmlIF::SaveDocument(const char* szURL)
{
  if (!m_bInitialized || !szURL) return FALSE;

  // Convert Argument to Variant
  BSTR pBURL = AsciiToBSTR(szURL);
  VARIANT vURL;
  VariantInit(&vURL);
  vURL.vt = VT_BSTR;
  V_BSTR(&vURL) = pBURL;

  // Save Xml Document To Specified URL
  bool bFlag = (GetDocument()->save(vURL) == S_OK) ? TRUE : FALSE;

  ::SysFreeString(pBURL);
  return bFlag;
}

// Set Top Level Document Node
bool CXmlIF::SetDocumentNode(void)
{
  if (!m_bInitialized) return FALSE;

  bool bFlag = FALSE;
  if (SUCCEEDED(m_pDoc->QueryInterface(MS_XML_NS::IID_IXMLDOMNode, 
                                       (void**) &m_pDocNode)))
    bFlag = TRUE;
  
  return bFlag;
}

// Insert Processing Instruction Node Into Document.
// Must Be Executed Prior To Creating Any Other Nodes
bool CXmlIF::InsertProcessingInst(void)
{
  if (!m_bInitialized) return FALSE;
  
  bool bFlag = FALSE;
  MS_XML_NS::IXMLDOMProcessingInstruction* pPI = NULL;
  BSTR pBTarget = (L"xml");
  BSTR pBData = (L" version=\"1.0\"");
  if (SUCCEEDED(m_pDoc->XML_CRP(pBTarget, pBData, &pPI)))
    m_pDoc->XML_APPCHILD(pPI, NULL);

  return bFlag;
}

// Get Name From This Node
bool CXmlIF::GetName(MS_XML_NS::IXMLDOMNode* pNode, BSTR pBName, UINT uSize)
{
  if (!pNode || !pBName || uSize <= 0) return FALSE;

  BSTR pBNodeName = NULL;
  bool bFlag = (pNode->get_nodeName(&pBNodeName) == S_OK) ? TRUE : FALSE;
  if (bFlag)
    {
    wcsncpy(pBName, pBNodeName, uSize);
    ::SysFreeString(pBNodeName);
    }

  return bFlag;
}

// Set Node Text To Argument Value
bool CXmlIF::SetText(MS_XML_NS::IXMLDOMNode* pNode, BSTR pBText)
{
  if (!pNode || !pBText) return FALSE;

  return ((pNode->put_text(pBText) == S_OK) ? TRUE : FALSE);
}

// Get Specified Text From This Node
bool CXmlIF::GetText(MS_XML_NS::IXMLDOMNode* pNode, BSTR pBText, UINT uSize)
{
  if (!pNode || !pBText || uSize <= 0) return FALSE;

  BSTR pBNodeText = NULL;
  bool bFlag = (pNode->get_text(&pBNodeText) == S_OK) ? TRUE : FALSE;
  if (bFlag)
    {
    wcsncpy(pBText, pBNodeText, uSize);
    ::SysFreeString(pBNodeText);
    }

  return bFlag;
}

// Set Node Value To Argument Value
bool CXmlIF::SetValue(MS_XML_NS::IXMLDOMNode* pNode, BSTR pBValue)
{
  if (!pNode || !pBValue) return FALSE;

  // Set Value As Variant Type
  VARIANT vValue;
  VariantInit(&vValue);
  vValue.vt = VT_BSTR;
  V_BSTR(&vValue) = pBValue;

  return ((pNode->put_nodeValue(vValue) == S_OK) ? TRUE : FALSE);
}

// Get Specified Value From This Node
bool CXmlIF::GetValue(MS_XML_NS::IXMLDOMNode* pNode, BSTR pBValue, UINT uSize)
{
  if (!pNode || !pBValue || uSize <= 0) return FALSE;

  VARIANT vValue;
  VariantInit(&vValue);

  bool bFlag = (pNode->get_nodeValue(&vValue) == S_OK) ? TRUE : FALSE;
  if (vValue.vt == VT_BSTR) wcsncpy(pBValue, V_BSTR(&vValue), uSize);

  return bFlag;
}

// Get List Of All Child Nodes
MS_XML_NS::IXMLDOMNodeList* CXmlIF::GetChildren(MS_XML_NS::IXMLDOMNode* pNode, 
                                            const BSTR pBName, long* pCnt)
{
  if (!pNode) return NULL;

  // Get List Of All Children, Either Name Matched Or All Children
  MS_XML_NS::IXMLDOMNodeList* pList = NULL; 
  if (!pBName) pNode->get_childNodes(&pList);
  else         pNode->XML_SELNODES(pBName, &pList);

  // Get Number Of Items In List...If NULL, Don't Fill Arguement
  if (pCnt)
    {
    if (pList) pList->get_length(pCnt);
    else       *pCnt = 0;
    }
  return pList;   // NOTE: Calling Method Must Call pList->Release()
}

// Get Indexed Child From Argument List...Index Is Zero Based
MS_XML_NS::IXMLDOMNode* CXmlIF::GetChild(MS_XML_NS::IXMLDOMNodeList* pList,
                                         const long lItem)
{
  if (!pList) return NULL;

  // Sanity Check
  long lListCnt = 0;
  pList->get_length(&lListCnt);
  if (lItem >= lListCnt) return NULL;

  // Get Node List Item That Matches The Occurance
  MS_XML_NS::IXMLDOMNode* pChild = NULL;
  pList->get_item(lItem, &pChild);
  return pChild;  // NOTE: Calling Method Must Call pChild->Release()
}

// Get Child From Node Using Element Name For Pattern Matching
MS_XML_NS::IXMLDOMNode* CXmlIF::GetChild(MS_XML_NS::IXMLDOMNode* pNode, 
                                         const BSTR pBName, UINT uOccurance)
{
  if (!pNode || !pBName) return NULL;

  // Get List Of Matching Child Nodes
  long lListCnt = 0;
  MS_XML_NS::IXMLDOMNodeList* pList = GetChildren(pNode, pBName, &lListCnt);

  // Set Which Occurance Of Element Name To Return...Occurance Is One Based
  long lItem = (lListCnt < (long) uOccurance) ? lListCnt : (long) uOccurance;
  if (lItem > 0) lItem--;
  else           lItem = 0;

  // Get Node List Item That Matches The Occurance
  MS_XML_NS::IXMLDOMNode* pChild = NULL;
  if (pList)
    {
    pList->get_item(lItem, &pChild);
    pList->Release();
    }
  return pChild;  // NOTE: Calling Method Must Call pChild->Release()
}

// Create Child Under Argument Node And Append To Child Map
MS_XML_NS::IXMLDOMNode* CXmlIF::CreateChild(MS_XML_NS::IXMLDOMNode* pNode, 
                                            const BSTR pBName, int nType)
{
  if (!m_bInitialized || !pNode || !pBName) return NULL;

  // Set Node Type As Variant
  VARIANT vType;
  vType.vt = VT_I4;
  V_I4(&vType) = nType;

  // Create New Node
  MS_XML_NS::IXMLDOMNode* pChild = NULL;
  if (SUCCEEDED(m_pDoc->XML_CRTNODE(vType, pBName, (L""), &pChild)))
    pNode->XML_APPCHILD(pChild, NULL);

  return pChild;  // NOTE: Calling Method Must Call pChild->Release()
}

// Get Specified Attribute From This Node Using Attribute Name
MS_XML_NS::IXMLDOMNamedNodeMap* CXmlIF::GetAttributeList(
                                        MS_XML_NS::IXMLDOMNode* pNode, 
                                        long* pCnt)
{
  if (!pNode) return NULL;

  // Get All Node Attributes
  MS_XML_NS::IXMLDOMNamedNodeMap* pAttrs = NULL;
  MS_XML_NS::IXMLDOMNode*         pChild = NULL;
  pNode->get_attributes(&pAttrs);

  // Get Number Of Items In List...If NULL, Don't Fill Arguement
  if (pCnt)
    {
    if (pAttrs) pAttrs->get_length(pCnt);
    else        *pCnt = 0;
    }
  return pAttrs;  // NOTE: Calling Method Must Call pAttrs->Release()
}

// Get Indexed Attribute From Argument List...Index Is Zero Based
MS_XML_NS::IXMLDOMNode* CXmlIF::GetAttribute(
                        MS_XML_NS::IXMLDOMNamedNodeMap* pAttrs, 
                        long lIndex)
{
  if (!pAttrs) return NULL;

  MS_XML_NS::IXMLDOMNode* pAttr = NULL;
  pAttrs->get_item(lIndex, &pAttr);
  return pAttr;   // NOTE: Calling Method Must Call pAttr->Release()
}

// Get Attribute From Node Using Attribute Name For Pattern Matching
MS_XML_NS::IXMLDOMNode* CXmlIF::GetAttribute(MS_XML_NS::IXMLDOMNode* pNode, 
                                             const BSTR pBName)
{
  if (!pNode || !pBName) return NULL;

  // Get All Node Attributes
  MS_XML_NS::IXMLDOMNamedNodeMap* pAttrs = NULL;
  MS_XML_NS::IXMLDOMNode*         pAttr  = NULL;
  if (SUCCEEDED(pNode->get_attributes(&pAttrs)) && pAttrs != NULL)
    {
    // Get Specific Attribute Using Name For Tag Lookup
    pAttrs->XML_GETNI(pBName, &pAttr);

    pAttrs->Release();
    }
  return pAttr;  // NOTE: Calling Method Must Call pAttr->Release()
}

// Create Specified Attribute From This Node Using Attribute Name
MS_XML_NS::IXMLDOMAttribute* CXmlIF::CreateAttribute(
                             MS_XML_NS::IXMLDOMNode* pNode, 
                             const BSTR pBName, const BSTR pBValue)
{
  if (!m_bInitialized || !pNode || !pBName || !pBValue) return NULL;

  // Convert BSTR To Variant Type
  VARIANT vValue;
  VariantInit(&vValue);
  vValue.vt = VT_BSTR;
  V_BSTR(&vValue) = pBValue;

  // Create New Node Attribute And Set Value
  MS_XML_NS::IXMLDOMAttribute* pNewAttr = NULL;
  m_pDoc->XML_CRTATTR(pBName, &pNewAttr);  
  pNewAttr->put_value(vValue);

  // Append New Attribute To This Nodes List
  AppendAttribute(pNode, pNewAttr);
  return pNewAttr;  // NOTE: Calling Method Must Call pNewAttr->Release()
}

// Create Specified Attribute From This Node Using Attribute Name
void CXmlIF::AppendAttribute(MS_XML_NS::IXMLDOMNode* pNode, 
                             MS_XML_NS::IXMLDOMAttribute* pAttr)
{
  if (!pNode || !pAttr) return;

  MS_XML_NS::IXMLDOMNamedNodeMap* pAttrs = NULL;
  if (SUCCEEDED(pNode->get_attributes(&pAttrs)) && pAttrs != NULL)
    {
    pAttrs->XML_SETNI(pAttr, NULL);
    pAttrs->Release();
    }
}

// Set Attribute Value To Arguement Value
bool CXmlIF::SetAttributeValue(MS_XML_NS::IXMLDOMNode* pNode, 
                               const BSTR pBName, BSTR pBValue)
{
  if (!pNode || !pBName || !pBValue) return FALSE;

  // Get Node Attribute And Set Value
  bool bFlag = FALSE;
  MS_XML_NS::IXMLDOMNode* pChild = GetAttribute(pNode, pBName);
  if (pChild)
    {
    bFlag = SetValue(pChild, pBValue);
    pChild->Release();
    }
  return bFlag;
}

// Get Specified Attribute Value From This Node Using Attribute Name
bool CXmlIF::GetAttributeValue(MS_XML_NS::IXMLDOMNode* pNode, 
                               const BSTR pBName, 
                               BSTR pBValue, UINT uSize)
{
  if (!pNode || !pBName || !pBValue || uSize <= 0) return FALSE;

  // Get Node Attribute Value
  bool bFlag = FALSE;
  MS_XML_NS::IXMLDOMNode* pChild = GetAttribute(pNode, pBName);
  if (pChild)
    {
    bFlag = GetValue(pChild, pBValue, uSize);
    pChild->Release();
    }
  return bFlag;
}
//End of File

Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.