xml-namespacesmsxmlmsxml6

How to query default namespace with MSXML


I have some XML:

<?xml version="1.0" ?>
<Project ToolsVersion="4.0">
    <PropertyGroup Condition="'$(key)'=='1111'">
          <Key>Value</Key>
    </PropertyGroup>
</Project>

Note: This isn't the actual XML i'm using, it's just prettier and shorter, and demonstrates the problem.

Using MSXML i can query for nodes:

IXMLDOMNode node = doc.selectSingleNode("//PropertyGroup/@Condition");

And it works fine:

Condition="'$(key)'=='1111'"

But that's not really the XML i have

In reality the XML i have contains a namespace declaration:

xmlns="http://schemas.microsoft.com/developer/msbuild/2003"

making the actual XML document:

<?xml version="1.0" ?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    <PropertyGroup Condition="'$(key)'=='1111'">
          <Key>Value</Key>
    </PropertyGroup>
</Project>

Now my query:

IDOMNode node = doc.selectSingleNode("//PropertyGroup/@Condition");

returns no matching nodes.

How do i query the default namespace using MSXML?

Note:

How do i query the "default", or "unnamed" namespace using MSXML?


Note: In reality the XML i am using the SQL Server's XML ShowPlan output:

<?xml version="1.0" encoding="UTF-16" standalone="yes"?>
   <ShowPlanXML Version="1.1" Build="10.50.1600.1" 
                   xmlns="http://schemas.microsoft.com/sqlserver/2004/07/showplan">
      <BatchSequence>
           <Batch>
           ...
           </Batch>
      </BatchSequence>
   </ShowPlanXML> 

Again you can see the offending namespace declaration. Deleting it works, but that's tedious.

What else have you tried?

i also tried setting the SelectionNamespace:

doc.setProperty('SelectionNamespaces', 
      'xmlns="http://schemas.microsoft.com/developer/msbuild/2003"');

as Microsoft hints at in a KB article.

How do i get the default namespace?

In reality i don't care about namespaces. My query makes sense, and i want it to work. So, Another approach to the question might be:

How can i query the default namespace whether, or not, and no matter what, that namespace name is (or isn't)?

Note: msxml is native code, and using it from a native Win32 compiler (i.e. no .NET framework or CLR)


Solution

  • Explicitly give the namespace an abbreviated-alias when you add it to the SelectionNamespaces:

    doc.setProperty("SelectionNamespaces",
          "xmlns:peanut='http://schemas.microsoft.com/developer/msbuild/2003'");
    

    and then query using that namespace (but referring to it by its abbreviated-alias):

    IDOMNode node = doc.selectSingleNode("//peanut:PropertyGroup/@Condition");
    

    You can give that namespace any abbreviated-alias you want (here I use value of peanut to demonstrate it can be any value you want for the value of the abbreviated-alias).
    And then use that same abbreviated-alias as a prefix (peanut:PropertyGroup in this case) in the "search-criteria".

    Earlier suggestions

    I would try moving to Xml.Linq.

    Here is a sample (with a namespace).

          try
        {
    
            XDocument xDoc1 = XDocument.Parse("<?xml version=\"1.0\" ?><Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\"><PropertyGroup Condition=\"'$(key)'=='1111'\"><Key>Value</Key></PropertyGroup></Project>");
            XNamespace ns1 = XNamespace.Get("http://schemas.microsoft.com/developer/msbuild/2003");
    
            var list1 = from list in xDoc1.Descendants(ns1 + "Project")
                        from item in list.Elements(ns1 + "PropertyGroup")
                        /* where item.Element(ns + "HintPath") != null */
                        where item.Attribute("Condition") != null
                        select new
                        {
                            MyCondition = item.Attribute("Condition") == null ? "Not Here!" : item.Attribute("Condition").Value,
                            MyFake = item.Attribute("DoesNotExistTest") == null ? "Not Here Sucker!" : item.Attribute("DoesNotExistTest").Value
                        };
    
    
            foreach (var v in list1)
            {
                Console.WriteLine(v.ToString());
            }
    
    
            XDocument xDoc2 = XDocument.Parse("<?xml version=\"1.0\" encoding=\"UTF-16\" standalone=\"yes\"?>   <ShowPlanXML Version=\"1.1\" Build=\"10.50.1600.1\"                    xmlns=\"http://schemas.microsoft.com/sqlserver/2004/07/showplan\">      <BatchSequence>            <Batch>Something I Threw In Here</Batch>      </BatchSequence>    </ShowPlanXML> ");
            XNamespace ns2 = XNamespace.Get("http://schemas.microsoft.com/sqlserver/2004/07/showplan");
    
            var list2 = from list in xDoc2.Descendants(ns2 + "ShowPlanXML")
                        from item in list.Elements(ns2 + "BatchSequence")
                        /*                             where item.Attribute("Condition") != null */
                        where item.Element(ns2 + "Batch") != null 
                        select new
                        {
                            BatchValue = (item.Element(ns2 + "Batch") == null) ? string.Empty : item.Element(ns2 + "Batch").Value
                        };
    
    
            foreach (var v in list2)
            {
                Console.WriteLine(v.ToString());
            }
    
    
    
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }