Home   |   Products   |   Documentation
 

dev net revision
29 July 2008
 

 
 

MSXML Wrapper CMarkupMSXML

Since near the beginning of CMarkup, there has always been a companion MSXML wrapper version of CMarkup which provides a way to get started with MSXML in Visual Studio. This is great if you want to use MSXML but want to avoid the initial learning curve of programming to the COM interface, or if you are accustomed to CMarkup methods but want to take advantage of specific MSXML features.

To get started, just add MarkupMSXML.cpp and MarkupMSXML.h to your Visual Studio project. All of the basic CMarkup methods are implemented, so for example you can load an XML file and get its root element tag name as follows:

#include "MarkupMSXML.h"
...
CMarkupMSXML xml;
if ( xml.Load("sample.xml") )
{
  xml.FindElem();
  CString csRootName = xml.GetTagName();
}

Because of its dependency on the MSXML component installed on the machine, there is the deployment issue to consider. MSXML has been available on Windows machines since Internet Explorer 4.0 and Windows 95 OSR 2.5. It was not on Windows machines installed in the first year or two of Windows 95, but definitely available from 1998 forward. Through the years there have been numerous versions. To build a reliable solution for wide deployment you might either utilize only the most common problem-free MSXML features, or integrate installation of a specific MSXML version with your software. Find details on Microsoft's XML area.

CMarkupMSXML has differences from CMarkup. MSXML is a fully compliant validating parser, so when a document is loaded it is checked for all aspects of well-formedness including character encoding, and validated if there is a DTD or XML Schema associated with the document. Also, if the parser returns an error, the document object is left empty (see When CMarkup Load Returns false), and parser error messages are generally quite different from those generated by CMarkup. Of course there is no support for HTML or ill-formed XML in CMarkupMSXML and whitespace is not preserved unless forced (see MSXML notes in Node Methods in CMarkup). CMarkupMSXML does not have any of the functions specific to the implementation of CMarkup such as offsets, index, file and encoding functions.

Other differences are kept to a minimum and many of the examples in the CMarkup documentation will work with CMarkupMSXML. The copy constructor works properly now in the release 8.0 developer version of CMarkupMSXML, but in previous releases and in the evaluation version making a copy of a CMarkupMSXML object creates references instead of copies which can lead to problems. Release 8.0 also brought absolute path behavior in line with CMarkup (see Paths In CMarkup).

For MSXML 3.0 or 4.0, use the preprocessor definitions MARKUP_MSXML3 and MARKUP_MSXML4. These switch to #import <msxml3.dll> or <msxml4.dll> from <msxml.dll>, and namespace MSXML2 from MSXML, among other things. See specific notes:

CMarkupMSXML has a public member m_pDOMDoc to provide access to the document for utilizing additional features of MSXML beyond the encapsulated methods.

Update August 17, 2005: CMarkupMSXML release 8.1 has the SetMainPosPtr method for setting the position back into the CMarkupMSXML object after external queries like the following two examples. The first example finds a single element based on the MSXML selectSingleNode function.

CMarkupMSXML xml;
xml.SetDoc( _T("<TOP><MID><LEAF1/></MID><MID/><MID><LEAF2/></MID></TOP>") );
_bstr_t bstrQuery( _T("/TOP/MID/LEAF2") );
xml.SetMainPosPtr( xml.m_pDOMDoc->selectSingleNode(bstrQuery) );
// xml.GetTagName() == _T("LEAF2")

With MSXML 3.0 forward, you can use XPath to query the document for a collection of nodes. First you need to set the SelectionLanguage.

CMarkupMSXML xml;
xml.SetDoc( _T("<Admin><Area AreaName=\"a\"/></Admin>") );
xml.m_pDOMDoc->setProperty( _T("SelectionLanguage"), _T("XPath") );
CString csQuery = _T("/Admin/Area[string-length(@AreaName) = 1]");
MSXMLNS::IXMLDOMNodeListPtr pNodes;
pNodes = xml.m_pDOMDoc->selectNodes( csQuery );
int nSelectCount = pNodes->Getlength();
xml.SetMainPosPtr( pNodes->Getitem(0) );
// xml.GetTagName() == _T("Area")

MSXML Processing InstructionTien 16-Jul-2008

I use CMarkupMSXML with msxml4.dll and Visual C++. I got an error when trying to create processing indtruction <?xml version="1.0"?> and don't know how to resolve it. Here is what happens:

CMarkupMSXML Xmldoc;
Xmldoc.ResetPos();
Xmldoc.InsertNode(CMarkupMSXML::MNT_PROCESSING_INSTRUCTION,
    "xml" ); ///problem here
Xmldoc.SetAttrib( "version", "1.0" );

Traced through MarkupMSXML.cpp

pPI = m_pDOMDoc->createProcessingInstruction(
    ToBSTR(strTarget), ToBSTR(strData) );

Then failed in msxml.tli at:

inline IXMLDOMProcessingInstructionPtr
    IXMLDOMDocument::createProcessingInstruction (
    _bstr_t target, _bstr_t data )

With error message because the HRESULT was not S_OK:

Unhandled exception at 0x7c812a7b in TestMarkup.exe: Microsoft C++
exception: _com_error @ 0x0012ee04.

MSXML does not allow the XML declaration to be created without the version in it from the beginning. So:

Xmldoc.InsertNode( CMarkupMSXML::MNT_PROCESSING_INSTRUCTION,
    "xml version = \"1.0\"" );

CMarkupMSXML puts the version into the data argument of the call to createProcessingInstruction.

 
 

Question or comment about this article?

©Copyright 2008 First Objective Software, Inc. All rights reserved.