Search code examples
c++dommsxmlixmldomelementixmldomnode

How can I access element attributes from an IXMLDOMNode?


I'm building an XML DOM document in C++. My problem is this: I execute an XPATH query from an Element in my Document, which I know will return another Element. The elementPtr->selectSingleNode call returns an IXMLDOMNode. How can I gain access to the attributes of this node?

Part of me wants to downcast the Node to an Element, but I couldn't get the cast to work.

I tried

MSXML2::IXMLDOMElementPtr pParentElement;
pParentNode->QueryInterface(__uuidof(MSXML2::IXMLDOMElement), 
                            (void**) &pParentElement);

Which results in the following runtime error:

0x0057cc58 _com_error::`scalar deleting destructor'(unsigned int)

The other route I tried was to just use nodes:

MSXML2::IXMLDOMNodePtr pParentNode = 
    pParameterElement->selectSingleNode("parent");
MSXML2::IXMLDOMNamedNodeMap* pParentAttributes;
pParentNode->get_attributes(&pParentAttributes);

MSXML2::IXMLDOMNodePtr pCategoryNameNode = 
    pParentAttributes->getNamedItem("Category");
VARIANT value;
pCategoryNameNode->get_nodeValue(&value);
CString categoryName = value;

This fails at "parentNode->get_attributes()".

It seems like I'm missing something; the API should not be this hard to use.

--edit--

What I was missing was that the selectSingleNode call was failing, leaving me with a NULL pointer. You can't call QueryInterface on that, neither can you call get_attributes on it :P

I've selected the answer that fits the question that I asked, not the answer that helped me to realise that I asked the wrong question.


Solution

  • I don't see anything wrong with what you have written.

    The smart com pointers will help you convert if they can, you don't have to write the query interface yourself.

    MSXML2::IXMLDOMNodePtr pParentNode = pParameterElement->selectSingleNode("parent");
    MSXML2::IXMLDOMElementPtr pParentElement( pParentNode );
    

    Using the Ptr types is a bit painfull in my opinion, though the MSXML interface favours them. Here is an equivelant example using ATL

    CComPtr<IXMLDOMNode> node = ...;
    CComQIPtr<IXMLDOMElement> elementNode( node );
    
    if( elementNode ) { 
    // it was an element!
    } else { 
    // it's something else try again? 
    }
    

    The other attempt would look like...

    CComPtr<IXMLDOMNamedNodeMap> attributes;
    node->get_attributes( &attributes );
    if( attributes ) {
      _bstr_t name( L"category" );
      attributes->getNamedItem(name);
    }
    

    And it's COM, it's always hard to use in C++ :(