Hi all,
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.
-
How did you try to do the downcast from IXMLDOMNode to IXMLDOMElement? You can't just use a C++ cast for that, as it's a COM object: you've got to use QueryInterface().
Looking at your QueryInterface() code, some thoughts:
- Is pParentNode definitely not null? I don't think that this is the problem, given what you get, but it's worth checking.
The QueryInterface() call isn't quite right, I think: you've got to call AddRef() one way or another on the returned interface, and your code won't. As another poster noted, you can get _com_ptr_t<> to do this for you:
MSXML2::IXMLDOMElementPtr pParentElement(pParentNode);
Doing this will, I hope, stop that "scalar deleting destructor" error that's probably caused by an AddRef()/Release() mis-match.
Anyway, try the above and see if pParentElement is null or not. If it is, the next thing I'd suggest is calling get_nodeType() on pParentNode to see what sort of node it really is. This might give a clue as to whether the XPath is not returning what you expect.
Symmetric : Thanks for the suggestion; I looked into QueryInterface, but couldn't get it to work. I've added my latest attempt to the original question; can you see anything wrong with what I'm doing? ThanksSymmetric : You've pointed me to the source of my problem; the QueryInterface call was correct, but my pParentNode was null, as the selectSingleNode call failed. The pParentElement(pParentNode) call is a much nicer way of performing the downcast though. -
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++ :(
Symmetric : It turns out that my problem was not the question that I asked ;) What would I gain by using ATL here? (I'm not being difficult, I just don't know about ATL). The syntax looks pretty similar.
0 comments:
Post a Comment