Traversing a DOM tree and workaround for reading attribute value in WinRT with Visual C++

Hi Community,

As a follow up to my previous post. This one shows how to execute an XPATH query, loop through the nodes returned by the query, how to use a lambda to retrieve the attributes from a given node but most importantly, how to read the attribute’s value… Yes, you read the last point right. Please remember that we’re working with a preview release and some of the features are not available yet like the one I just mentioned.  Let’s get started by having a look at the code snippet below

void DataContext::ParseXml() {
    if (!xml->IsEmpty()) {
        auto doc = ref new XmlDocument;
        ReplaceSpecialCharactersIfAny();
        doc->LoadXml(xml);

        if (doc->HasChildNodes()) {
            items->Clear();
            auto names = std::vector<String^>();
            auto values = ref new Vector<String^>();
            auto nodeList = doc->SelectNodes("uiInspector/element");
            names.push_back("id");
            names.push_back("hWnd");
            names.push_back("text");
            names.push_back("className");
            names.push_back("parentHwnd");

            for (unsigned int nNode = 0; nNode < nodeList->Length; nNode++)
            {
                auto attributes = nodeList->Item(nNode)->Attributes;

                std::for_each(names.begin(), names.end(), [&] (String^ propertyName) {
                    auto attribute = attributes->GetNamedItem(propertyName)->NodeValue;
                    values->Append(((Windows::Foundation::IReference<String^>^) attribute)->Value);
                });

                items->Append(ref new UIInspector::UIElement(values));
            }
        }
    } else throw ref new NullReferenceException;
}

The beauty of WinRT is that COM is made easier & cleaner than before, and the developer can focus on the requirement instead of the plumbing and counting of references, as depicted in the image below  (See __cli_refcount)

image

Let’s put it this way, by instantiating an object via ref new it’s similar to do it the old fashion way in COM through a smart pointer (e.g.: CComPtr), therefore the object is less prone to memory leaks by performing automatic reference counting.

Back to our code snippet, WinRT & STL are fully compatible – Let’s remember this is native code Smile , so I put in a vector the names of the attributes I want to read, and since there’s an outer for loop responsible for iterating the XML nodes we then retrieve the attributes while looping. We use std::for_each that takes a lambda (functor) in order to read the attributes we’re interested in… So far, so good… As mentioned at the beginning, we’re working with a preview release so it’s expected to find glitches, well… One of these glitches it’s the inability to read the attribute values via the NodeValue property because it returns an object regardless of calling the ToString() method which gives us the following

+        attributes->GetNamedItem(propertyName)->NodeValue->ToString()    0x03bb9a38 0x03bb9a38 L"Windows.Foundation.IReference`1<String>"    Platform::String *

An object of the Windows.Foundation.IReference type and I was like Disappointed smile that’s maybe (I’m speculating now) why the XML section is missing in the preview documentation. The easiest way to solve this issue was to cast the object to the right type, and read the attribute value from the Value property.

Regards,

Angel

Leave a Reply

Your email address will not be published. Required fields are marked *