Click here to Skip to main content
15,884,298 members
Articles / Desktop Programming / MFC

CXml - A Wrapping Class for MSXML 3.0/4.0/5.0/6.0

Rate me:
Please Sign up or sign in to vote.
4.99/5 (45 votes)
10 Jan 2013CPOL2 min read 151.4K   9.5K   165   85
This wrapping class will try to use the latest version of MSXML in the machine, and it is easy because of using auto_ptr.

Introduction

MSXML, a window component shipped with Windows / Office and other Microsoft products, exists in all Windows platforms. But there are different versions of MSXML, from 2.6 to 6.0, which causes a lot of problems.

This is a wrapping class library for MSXML 3.0/4.0/5.0/6.0 consisting of resolving the above problem -- you don't need to worry about the available MSXML version on different machines any more. Also it provides an easy-to-use interface -- each node in the XML is considered an object and you can use some code like below to locate a node.  

C++
xml.GetRoot()->GetChild(_T("a"))->GetChild(_T("b"))->GetChild(_T("c")) 

Sample Code

Please find the sample code in the demo project.

JW_CXml/demo.jpg

Using the Code

Copy all the files in the /CXml/*.* directory and add them into your project.

C++
#include "Xml.h"
using namespace JWXml;

Here, I have added a namespace for the classes, you can change it as you like.

MSXML Version

The class will try to choose the version of MSXML in the following order:

C++
hr = (hr == S_OK) ? hr : m_pDoc.CreateInstance( __uuidof(MSXML2::DOMDocument60) );
hr = (hr == S_OK) ? hr : m_pDoc.CreateInstance( __uuidof(MSXML2::DOMDocument30) );
hr = (hr == S_OK) ? hr : m_pDoc.CreateInstance( __uuidof(MSXML2::DOMDocument50) );
hr = (hr == S_OK) ? hr : m_pDoc.CreateInstance( __uuidof(MSXML2::DOMDocument40) );
hr = (hr == S_OK) ? hr : m_pDoc.CreateInstance( __uuidof(MSXML2::DOMDocument26) );
hr = (hr == S_OK) ? hr : m_pDoc.CreateInstance( __uuidof(MSXML2::DOMDocument) );

Classes Overview

CXml

C++
class CXml
{
    friend class CXsl;

public:
    CXml(void);
    ~CXml(void);

protected:
    MSXML2::IXMLDOMDocument2Ptr m_pDoc;
    CString m_strFilePath;
    MSXML_VERSION m_emVersion;
    std::map< CString, CString> m_mpNamespace;

    BOOL CreateInstance(void);

public:
    // Open XML file
    BOOL Open(LPCTSTR lpszXmlFilePath);

    // Create a new XML file
    BOOL Create( LPCTSTR lpszRootName = _T("xmlRoot")
        , LPCTSTR lpszPrefix = _T("")
        , LPCTSTR lpszNamespaceURI = _T("")
        );

    // Load XML string
    BOOL LoadXml(LPCTSTR lpszXmlContent);

    // save XML file
    BOOL Save(LPCTSTR lpszFilePath);

    // save XML file with formatted output
    BOOL SaveWithFormatted(LPCTSTR lpszFilePath = NULL, 
            LPCTSTR lpszEncoding = _T("UTF-8"));

    // close XML file
    void Close(void);

    CString GetXmlFile(void) const;

    // Encode the binary data into string
    CString Base64Encode( LPBYTE pBuf, ULONG ulSize);

    // Decode the string into binary data
    BOOL Base64Decode( CString strIn, LPBYTE pBuf, LONG & lSize);

    // namespace
    void AddSelectionNamespace( LPCTSTR lpszPrefix, LPCTSTR lpszURI);

    // get the root element of
    CXmlNodePtr GetRoot(void);

    // get single node by XPath
    CXmlNodePtr SelectSingleNode(LPCTSTR lpszPath);

    // get nodes by XPath
    CXmlNodesPtr SelectNodes(LPCTSTR lpszPath);

    // create node
    CXmlNodePtr CreateNode(LPCTSTR lpszName
        , LPCTSTR lpszPrefix = _T("")
        , LPCTSTR lpszNamespaceURI = _T("")
        );

    // get the current version of MSXML
    MSXML_VERSION GetVersion(void) const;
};

CXmlNode

C++
class CXmlNode
{
    friend class CXml;
    friend class CXmlNode;
    friend class CXmlNodes;

protected:
    MSXML2::IXMLDOMNodePtr m_pNode;

    CXmlNode( MSXML2::IXMLDOMNodePtr pNode);

    BOOL _GetValue(CString & strValue) const;
    BOOL _SetValue(CString & strValue) const;

    BOOL _GetAttribute( CString & strName, CString & strValue) const;
    BOOL _SetAttribute( CString & strName IN
                      , CString & strValue IN
                      , CString & strPrefix IN
                      , CString & strNamespaceURI IN
                      ) const;

public:

    CXmlNode(void);
    CXmlNode(const CXmlNode & refNode IN);
    CXmlNode(const CXmlNodePtr pNode IN);
    ~CXmlNode(void);

    CXmlNodePtr operator = (CXmlNodePtr pNode);
    CXmlNode & operator = (const CXmlNode & refNode);

    BOOL IsNull(void) const;     // Whether the current element exist
    CString GetName(void) const;// Get the name of the current node
    CXmlNode & Detach(void);    // Detach the current node
    void Release(void);    // Release this node

    CXmlNodePtr GetChild( CString strName, BOOL bBuildIfNotExist = TRUE);
    CXmlNodePtr NewChild( CString strName );
    CXmlNodePtr GetParent(void);
    CXmlNodesPtr GetChildren();
    void AttachChild( CXmlNodePtr & pChildNode);
    void AttachChild( CXmlNode & refChildNode);
    BOOL HasChildren(void);
    BOOL RemoveChildren(void);

    CString    GetAttribute( CString strName, LPCTSTR lpszDefault = NULL) const;
    bool    GetAttribute( CString strName, bool bDefault) const;
    int        GetAttribute( CString strName, int nDefault) const;
    long    GetAttribute( CString strName, long lDefault) const;
    __int64    GetAttribute( CString strName, __int64 llDefault) const;
    float    GetAttribute( CString strName, float fDefault) const;
    double    GetAttribute( CString strName, double dDefault) const;
    DWORD    GetAttribute( CString strName, DWORD dwDefault) const;

    BOOL    SetAttribute( CString strName, LPCTSTR lpszValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));
    BOOL    SetAttribute( CString strName, bool bValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));
    BOOL    SetAttribute( CString strName, int nValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));
    BOOL    SetAttribute( CString strName, long lValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));
    BOOL    SetAttribute( CString strName, __int64 llValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));
    BOOL    SetAttribute( CString strName, float fValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));
    BOOL    SetAttribute( CString strName, double dValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));
    BOOL    SetAttribute( CString strName, DWORD dwValue ,
            CString strPrefix = _T(""), CString strNamespaceURI = _T(""));

    BOOL RemoveAttribute( CString strName );

    CString    GetValue( LPCTSTR lpszDefault = NULL ) const;
    bool    GetValue( bool bDefault ) const;
    int        GetValue( int nDefault) const;
    long    GetValue( long lDefault) const;
    __int64    GetValue( __int64 llDefault) const;
    float    GetValue( float fDefault) const;
    double    GetValue( double dDefault) const;
    DWORD    GetValue( DWORD dwDefault) const;

    BOOL    SetValue( LPCTSTR lpszValue );
    BOOL    SetValue( bool bValue );
    BOOL    SetValue( int nValue );
    BOOL    SetValue( long lValue );
    BOOL    SetValue( __int64 llValue );
    BOOL    SetValue( float fValue );
    BOOL    SetValue( double dValue );
    BOOL    SetValue( DWORD dwValue );

    CXmlNodePtr SelectSingleNode(LPCTSTR lpszPath);
    CXmlNodesPtr SelectNodes(LPCTSTR lpszPath);

    CString GetOuterXml(void) const;
    CString GetInnerXml(void) const;
};

CXmlNodes

C++
class CXmlNodes
{
    friend class CXml;
    friend class CXmlNode;
    friend class CXmlNodes;

public:
    ~CXmlNodes(void);
    CXmlNodes(void);
    CXmlNodes( const CXmlNodes & refNodes );
    CXmlNodes( CXmlNodesPtr pNodes );

    CXmlNodesPtr operator = (CXmlNodesPtr pNodes);
    CXmlNodes & operator = (const CXmlNodes & refNodes);
    CXmlNodePtr operator[] ( LONG lIndex );
    CXmlNodePtr operator[] ( LPCTSTR lpszName );

    LONG GetCount(void);
    void Release(void);

    CXmlNodePtr GetItem( LONG nIndex );
    CXmlNodePtr GetItem( LPCTSTR lpszName );

protected:
    CXmlNodes(MSXML2::IXMLDOMNodeListPtr pNodeList);
    MSXML2::IXMLDOMNodeListPtr m_pNodeList;

};

CXsl

C++
class CXsl
{
public:
    CXsl(void);
    ~CXsl(void);

    // Open XSL file
    BOOL Open(LPCTSTR lpszXslFilePath);

    // close XSL file
    void Close(void);

    // transform to file
    BOOL TransformToFile( CXml & objXml, LPCTSTR lpszFilePath);

    // add a parameter
    BOOL AddParameter( LPCTSTR lpszParamName, LPCTSTR lpszParamValue, 
            LPCTSTR lpszNamespaceURI = NULL);

protected:
    MSXML2::IXSLTemplatePtr m_pIXSLTemplate;
    MSXML2::IXMLDOMDocument2Ptr m_pStyleSheet;
    MSXML2::IXSLProcessorPtr m_pIXSLProcessor;
};

History

  • v2.0
    • Created: 2007-07-16
  • v2.1
    • Added LoadXml method
    • Added GetVersion method
    • Added const for GetXXX methods
    • Defined ASSERT as ATLASSERT for ATL
    • Defined TRACE as ATLTRACE for ATL
  • V2.2
    • Added the parameter lpszRootName for CXml::Open
    • Removed CXml::GetLastError
    • Added CXml::AddNamespace
    • Added two new overrides for CXml::CreateNode with namespace support
  • V3.0
    • Added another copy constructor for CXmlNode and CXmlNodes
    • Added const modifier for some variables
    • Added CXmlNode::GetInnerXml
    • Added CXmlNode::GetOuterXml
    • Added CXml::Create
    • Changed the MSXML version for Create to 6.0 -> 3.0 -> 5.0 -> 4.0
    • Added namespace support for attributes
    • Added a new class named CXsl
  • V3.1
    • Add method CXml::SaveWithFormatted (Thanks to roel_)
    • Reuse CXml::SaveStreamToFile in CXsl::TransformToFile
    • Add CXsl::AddParameter to allow passing parameters to XSLT
    • Use std::tr1::shared_ptr if exists instead of std::auto_ptr
    • Change namespace from Generic to JWXml 
  • V3.2
    • Bug fix for the Create method usage in demo.
    • Upgrade to VS2010

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Team Leader
China China
Jerry is from China. He was captivated by computer programming since 13 years old when first time played with Q-Basic.



  • Windows / Linux & C++
  • iOS & Obj-C
  • .Net & C#
  • Flex/Flash & ActionScript
  • HTML / CSS / Javascript
  • Gaming Server programming / video, audio processing / image & graphics


Contact: vcer(at)qq.com
Chinese Blog: http://blog.csdn.net/wangjia184

Comments and Discussions

 
GeneralRe: Usage under Windows CE Pin
Yoisel17-Nov-09 4:47
Yoisel17-Nov-09 4:47 
GeneralVery easy to use after reading the code samples Pin
Rolf Kristensen24-Sep-09 23:33
Rolf Kristensen24-Sep-09 23:33 
GeneralSpecial characters Pin
Member 2888148-May-09 13:42
Member 2888148-May-09 13:42 
QuestionHow can I change a node's name? Pin
sheng.wang1-Apr-09 17:20
sheng.wang1-Apr-09 17:20 
General当用创建XML文件时存在虫虫. Pin
linshengfeng7-Mar-09 1:28
linshengfeng7-Mar-09 1:28 
GeneralRe: 当用创建XML文件时存在虫虫. Pin
Jerry.Wang7-Mar-09 2:20
Jerry.Wang7-Mar-09 2:20 
GeneralIs it better to use vector<cxmlnodeptr> to replace CXmlNodes? [modified]</cxmlnodeptr> Pin
jerry_wangjh27-Feb-09 15:12
jerry_wangjh27-Feb-09 15:12 
QuestionPerformance problem Pin
poney8-Dec-08 16:17
poney8-Dec-08 16:17 
我使用CXml遍历一个xml文件,文件如下:

<root>
<edit>
<element type="0" key="1000" branch="1">
<instruction code="MOVE" comment="">
<parameters>
<parameter address="0x21" comment="">


……都是Element的重复。
当Element有几千的时候,遍历速度就出现大起大落。有时要3、4秒,有时要20、30秒。
遍历操作要访问Element中的每个节点。
请问出现这种性能的大起大落可能的原因是什么呢?

Hello, I am Poney

AnswerIf there are hundreds of nodes in the xml, or the xml file is very huge. SAX is better. Pin
Jerry.Wang8-Dec-08 19:35
Jerry.Wang8-Dec-08 19:35 
NewsA bug was found in the DEMO program Pin
Jerry.Wang4-Dec-08 14:40
Jerry.Wang4-Dec-08 14:40 
GeneralGet whole xml string method Pin
poney4-Dec-08 14:20
poney4-Dec-08 14:20 
GeneralRe: Get whole xml string method Pin
Jerry.Wang4-Dec-08 14:38
Jerry.Wang4-Dec-08 14:38 
NewsMessage Closed Pin
31-Oct-08 20:08
codemobile31-Oct-08 20:08 
GeneralRe: Cool Articles about This Topic Pin
KnDol10-Nov-08 22:09
KnDol10-Nov-08 22:09 
GeneralSome more API comments... Pin
roel_12-Oct-08 22:19
roel_12-Oct-08 22:19 
GeneralRe: Some more API comments... Pin
roel_12-Oct-08 22:25
roel_12-Oct-08 22:25 
GeneralRe: Some more API comments... Pin
Jerry.Wang13-Oct-08 15:14
Jerry.Wang13-Oct-08 15:14 
GeneralRe: Some more API comments... Pin
KarstenK23-Oct-08 2:20
mveKarstenK23-Oct-08 2:20 
GeneralHere's an addition to add formatted output Pin
roel_2-Oct-08 23:27
roel_2-Oct-08 23:27 
GeneralRe: Here's an addition to add formatted output Pin
Jerry.Wang13-Oct-08 15:15
Jerry.Wang13-Oct-08 15:15 
NewsGood news, shared_ptr is added in VS2008 SP1 within the stl::tr1 namespace Pin
Jerry.Wang15-Jul-08 16:36
Jerry.Wang15-Jul-08 16:36 
GeneralWonderful Article! Extended it a bit...thought I'd share. Pin
Brett Fowle9-May-08 6:17
Brett Fowle9-May-08 6:17 
GeneralExcellent! Pin
javan8-May-08 6:33
javan8-May-08 6:33 
GeneralVery well ~~excellent~!! Pin
Ruifeng Zhang15-Apr-08 23:03
Ruifeng Zhang15-Apr-08 23:03 
QuestionVARIANT values handling Pin
Sapien215-Apr-08 3:03
Sapien215-Apr-08 3:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.