Click here to Skip to main content
Click here to Skip to main content

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

By , 10 Jan 2013
 

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.  

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.

#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:

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

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

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

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

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)

About the Author

Jerry.Wang
Team Leader
China China
Member
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
  • PHP / HTML / CSS / Javascript
  • Gaming Server programming / video, audio processing / image & graphics
 
Contact: 32775973(at)qq.com
Chinese Blog: http://blog.csdn.net/wangjia184

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5membermaplewang22 Jan '13 - 15:59 
Thanks very good and easy to use.
GeneralMy vote of 5memberskyformat99@gmail.com11 Jan '13 - 17:55 
建议把文档合并为2个文件,这样用起来方便啊
GeneralRe: My vote of 5memberJerry.Wang12 Jan '13 - 13:50 
That would be a bad practice for OO programming
GeneralMy vote of 5memberH.Brydon10 Jan '13 - 8:51 
This is great. I see it is an update. I wish I had seen it before now.
Question这个项目有人在版本低于6.0的MSXML环境下用过吗?memberdothan00925 Feb '12 - 1:37 
我在没装MSXML6.0的xp sp2环境下运行Sample报Runtime Error,集成到自己的项目中也是同样错误
Question没有一个比较简便的demo么?memberyanzhiwei1475 Feb '12 - 20:47 
看了demo,发现已经完整了。可是我刚开始接触这个,没懂得怎么从小处开始。。
GeneralMy vote of 5memberjerry_wangjh11 Nov '11 - 20:39 
哈哈,作者和我的名字一样。。。
GeneralMy vote of 5membertankfun12 Sep '11 - 23:49 
Excellent,but is there any method to add a CDATA node? (like createCDATASection...) modified on Monday, September 19, 2011 4:14 AM
Generalnew function - GetXML()memberMaster^Tristar30 Mar '11 - 19:28 
CString CXml::GetXML(void) const { ASSERT( m_pDoc != NULL ); _bstr_t xml; xml = m_pDoc->Getxml(); CString x; x.Format(TEXT("%S"), xml.GetBSTR()); return x; }   to get the XML content for those who are lazy to read the file (save function)
GeneralRe: new function - GetXML()memberJerry.Wang12 Apr '11 - 18:45 
There is a method named GetOuterXml   you can use it to retrive the whole HTML
GeneralRe: new function - GetXML()memberhazywxin226 May '11 - 5:06 
能否提供个VC6的例程?谢谢
GeneralMy vote of 5memberJhomes14 Feb '11 - 11:21 
Great library
AnswerAdded two new functions: GetAttributeCountmemberLars [Large] Werner19 Dec '10 - 9:49 
I've been using the CXml class for quite some time. Today I got a need to index the attributes on a node and return each of them. Here is my solution.   In XMLNode.cpp / XMLNode.h add these two functions:  ...
Generaland GetAttributeByIndexmemberLars [Large] Werner19 Dec '10 - 9:51 
//--------------------------...
GeneralRe: and GetAttributeByIndexmemberJerry.Wang12 Apr '11 - 18:48 
Thank you, I would like to add the Attributes feature in next version
QuestionIf I call _tsplitpath first then call CXmlNode::SetAttribute(strName, lpszValue). It's default parameter will have some value. why?membersilvonli15 Nov '10 - 21:56 
If I call _tsplitpath first then call CXmlNode::SetAttribute(strName, lpszValue). It's default parameter will have some value. why?
GeneralGood job, if you provide more sample is bettermembermaplewang26 Oct '10 - 0:59 
for example a small XML editor or even simple viewer.
Question不支持命名空间?memberhellohuhu6 Apr '10 - 23:26 
在测试Query By XPath功能时发现XPath路径不能支持命名空间。 xml文件: <?xml version="1.0" encoding="UTF-16"?> <xsd:schema xmlns:xdb="http://xmlns.oracle.com/xdb" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <xsd:include schemaLocation="common.xsd"/> <xsd:complexType...
AnswerRe: 不支持命名空间?memberJerry.Wang7 Jul '10 - 16:34 
please look at the sample carefully, there is a way to indicate the namespace
Question如何解决缩进的问题??memberzhuliyan23 Feb '10 - 21:39 
使用CXml得到的XML文件中的父节点和子节点都在一块,如何让他们符合一定格式的缩进???谢谢啦
AnswerRe: 如何解决缩进的问题??memberJerry.Wang8 Mar '10 - 16:35 
Use CXml::SaveWithFormat
Question如何解决缩进的问题??memberzhuliyan23 Feb '10 - 21:37 
使用CXml得到的XML文件中的父节点和子节点都在一块,如何让他们符合一定格式的缩进???谢谢啦
GeneralHeap corruption detectedmemberSnakefoot8 Dec '09 - 11:10 
I have a problem with the following code: BSTR bstr = NULL; HRESULT hr = m_pNode->get_nodeName(&bstr); ASSERT( SUCCEEDED(hr) ); strRet = (LPCTSTR)_bstr_t( bstr, true);   if( bstr != NULL ) { SysFreeString(bstr); bstr = NULL; } It crashes when the temporary _bstr_t is...
QuestionSaveWithFormatted 保存为UTF-8编码文件的时候如何带签名?membertopexcel18 Nov '09 - 4:09 
SaveWithFormatted 保存为UTF-8编码文件的时候如何带签名?或者说如何生成带签名的UTF-8编码文件?
AnswerRe: SaveWithFormatted 保存为UTF-8编码文件的时候如何带签名?memberJerry.Wang18 Nov '09 - 15:33 
带签名的文件的前面3个字节是一个 BOM, 指定了后面的字节顺序   UTF-8一般是3个字节 如 0xEFBBBF UTF-16一般是2个字节,如 0xEFFF 或者 0xFFEF 等等   MSXML组件有木有提供这么细节的方式我还真没去研究过,不过你知道原理可以自己修改代码来实现

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

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 10 Jan 2013
Article Copyright 2007 by Jerry.Wang
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid