XPath evaluator in MSXML

MSXML comes with full XPath support. When XPath is used to select a node (or node list), you can just use IXMLDOMNode::selectSingleNode method. It’s quite easy.

However, when XPath doesn’t return node(s), IXMLDOMNode::selectSingleNode doesn’t work because it must return the result in a node (or node list).

// Doesn't work: count the number of Pin nodes.
pNode->selectSingleNode(L"count(//Pin)", ...)

You can use XSLT to perform such XPath. Here is a sample code.

// Header File: xpath_evaluator.hpp
#ifndef _INCLUDED_386FDA9A_D447_4ad6_A406_BC71280B43EE
#define _INCLUDED_386FDA9A_D447_4ad6_A406_BC71280B43EE

#include <comdef.h>
#include <msxml2.h>
#include <string>

class XPathEvaluator {
    _COM_SMARTPTR_TYPEDEF(IXMLDOMDocument, __uuidof(IXMLDOMDocument));
    _COM_SMARTPTR_TYPEDEF(IXSLTemplate, __uuidof(IXSLTemplate));
    _COM_SMARTPTR_TYPEDEF(IXSLProcessor, __uuidof(IXSLProcessor));
public:
    XPathEvaluator(const std::wstring& xpath) {
        using namespace std;
        
        wstring xslt = wstring() + 
            L"<xsl:transform version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>"
            L"  <xsl:output method='xml' omit-xml-declaration='yes'/>"
            L"  <xsl:template match='/'>"
            L"    <xsl:copy-of select='" + xpath + L"'/>"
            L"  </xsl:template>"
            L"</xsl:transform>";

        IXMLDOMDocumentPtr xsltDoc;
        HRESULT hr = xsltDoc.CreateInstance(__uuidof(FreeThreadedDOMDocument60));
        if(FAILED(hr)){
            throw runtime_error("Error");
        }

        VARIANT_BOOL isSuccess;
        hr = xsltDoc->loadXML(_bstr_t(xslt.c_str()), &isSuccess);
        if(FAILED(hr) || !isSuccess){
            throw runtime_error("Error");
        }
        
        
        IXSLTemplatePtr IXSLTTemplate;
        hr = IXSLTTemplate.CreateInstance(__uuidof(XSLTemplate60));
        if(FAILED(hr)){
            throw runtime_error("Error");
        }

        hr = IXSLTTemplate->putref_stylesheet(xsltDoc.GetInterfacePtr());
        if(FAILED(hr)){
            throw runtime_error("Error");
        }
                    
                    
        hr = IXSLTTemplate->createProcessor(&m_IXSLProcessor);
        if(FAILED(hr)){
            throw runtime_error("Error");
        }
    }

    std::wstring Evaluate(IXMLDOMNodePtr doc){
        using namespace std;
        
        HRESULT hr = m_IXSLProcessor->put_input(variant_t(doc.GetInterfacePtr()));
        if(FAILED(hr)){
            throw runtime_error("Error");
        }
        
        VARIANT_BOOL vtRet;
        hr = m_IXSLProcessor->transform(&vtRet);
        if(FAILED(hr) || vtRet != VARIANT_TRUE){
            throw runtime_error("Error");
        }

        _variant_t vtOutput;
        hr = m_IXSLProcessor->get_output(&vtOutput);
        if(FAILED(hr)){
            throw runtime_error("Error");
        }
        _bstr_t bstrOutput(vtOutput);
        return wstring(bstrOutput.GetBSTR());
    }
private:
    IXSLProcessorPtr m_IXSLProcessor;
};
#endif

 

The usage is like this:

#include "xpath_evaluator.hpp"

#include <comdef.h>
#include <msxml2.h>

#include <iostream>
#include <memory>

_COM_SMARTPTR_TYPEDEF(IXMLDOMDocument2, __uuidof(IXMLDOMDocument2));

using namespace std;

int main(int argc, char** argv){
    try{
        if(argc != 3){
            throw runtime_error("Specify input file and xpath expression.");
        }
        
        string inputFile = argv[1];
        string xpath     = argv[2];

        cout << "Input File: " << inputFile << endl;
        cout << "XPath:      " << xpath << endl;

        CoInitialize(NULL);
        
        IXMLDOMDocument2Ptr domDocument;
        HRESULT hr = domDocument.CreateInstance(__uuidof(DOMDocument60));
        if(FAILED(hr)){
            throw runtime_error("Error");
        }

        _variant_t varInputFileName(_bstr_t(inputFile.c_str()));

        VARIANT_BOOL isSuccess;
        hr = domDocument->load(varInputFileName, &isSuccess);
        if(FAILED(hr) || !isSuccess){
            throw runtime_error("Error");
        }

        _bstr_t bstrXPath(xpath.c_str());
        auto_ptr< XPathEvaluator > evaluator(new XPathEvaluator(wstring(bstrXPath)));
        wstring strValue = evaluator->Evaluate(domDocument);
        
        wcout << L"Result: " << strValue << endl;
        
    }catch(std::exception& e){
        cout << e.what() << endl;
    }
}

Advertisements

About Moto

Engineer who likes coding
This entry was posted in Tips. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s