c++windowsc++-winrt

How is the Windows::Data::Xml::Dom GetNamedItemNS method used to return the value of an attribute?


Given XML that looks like this, I am trying to loop through the Bar elements, extracting the title attribute. Attempts to extract the title return NULL.

<?xml version="1.0" encoding="UTF-8"?>
<Thing xmlns="https://thing">
  <Foos>
    <Bars>
      <Bar title="Firefox" description="You need firefox">
      </Bar>
      <Bar title="Chrome" description="You need chrome">
      </Bar>
    </Bars>
  </Foos>
</Thing>

Here is the code:

        auto nss = winrt::box_value(L"xmlns:sv='https://thing'");
        auto ns = winrt::box_value(L"https://thing");

        for (Windows::Data::Xml::Dom::IXmlNode node : document.SelectNodesNS(L"/sv:Things/sv:Foos/sv:Bars/sv:Bar", nss)) {

            auto attrs = node.Attributes();
            auto titleNode = attrs.GetNamedItemNS(ns, L"title");

            if (!titleNode) {
                // titleNode is NULL - why?
                continue;
            }
        }

The debugger confirms that attrs contains two elements as expected, but attrs.GetNamedItemNS does not match anything and NULL is returned.

Given the default namespace is being used in this element, what is the correct syntax for returning the title attribute of the Bar element given Bar and title are namespaced?


Solution

  • title isn't namespaced, because default namespace (i.e., xmlns="https://thing") is applied only to contained elements, not their attributes. From 6.2 of specification of XML namespaces (bold emphasis and ellipsis omissions mine):

    The scope of a default namespace declaration extends from the beginning of the start-tag in which it appears to the end of the corresponding end-tag, excluding the scope of any inner default namespace declarations. In the case of an empty tag, the scope is the tag itself.

    A default namespace declaration applies to all unprefixed element names within its scope. Default namespace declarations do not apply directly to attribute names; the interpretation of unprefixed attributes is determined by the element on which they appear.

    ...

    There's also a good example demonstrating this, though in 6.3 (which concerns uniqueness of attributes):

    ...

    However, each of the following is legal, the second because the default namespace does not apply to attribute names:

    <!-- http://www.w3.org is bound to n1 and is the default -->
    <x xmlns:n1="http://www.w3.org" 
       xmlns="http://www.w3.org" >
      <good a="1"     b="2" />
      <good a="1"     n1:a="2" />
    </x>
    

    So, you can just use a non-namespaced GetNamedItem like this:

    auto titleNode = attrs.GetNamedItem(L"title");