First time here? You are looking at the most recent posts. You may also want to check out older archives or the tag cloud. Please leave a comment, ask a question and consider subscribing to the latest posts via RSS. Thank you for visiting! (hide this)

I just spent a few hours banging my head against a XPath query that didn't return the node I was trying to select using the right xpath string: to make a long story short, if your XML document has a default namespace without any prefix, to make XPath queries on it you have to use a NamespageManager, add the default namespace with a fake prefix, and then query the document specifying the namespace manager in the SelectNodes method.

But let's explain a bit more in detail. Imagine you want to make a XPath query on a VisualStudio project (the following is just a part of a real csproj file):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="2.0" DefaultTargets="Build"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ProjectType>Local</ProjectType>
    <ProductVersion>8.0.50727</ProductVersion>
    <SchemaVersion>2.0</SchemaVersion>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="System" />
    <Reference Include="System.Data" />
    <Reference Include="Microsoft.Practices.EnterpriseLibrary.Common">
      <Name>Microsoft.Practices.EnterpriseLibrary.Common</Name>
      <HintPath>C:\...\Microsoft.Practices.EnterpriseLibrary.Common.dll</HintPath>
    </Reference>
    <Reference Include="Microsoft.Practices.EnterpriseLibrary.Data">
      <Name>Microsoft.Practices.EnterpriseLibrary.Data</Name>
      <HintPath>C:\...\Microsoft.Practices.EnterpriseLibrary.Data.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

If the xml document didn't have the default namespace

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

we could have queried the document to select the node with the reference for the Enterprise Library Data dll with the following XPath query string:

XmlNode entlibDataNode = doc.SelectSingleNode(
"/Project/ItemGroup/Reference[Name='Microsoft.Practices.EnterpriseLibrary.Data']"
);

But unfortunately our xml document has a default namespace, so this query doesn't work: in order to make it work we need to instruct the XPath query engine to use the default namespace as follows:

XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace(
             "a",
             "http://schemas.microsoft.com/developer/msbuild/2003"
              );

The code above creates a XmlNamespaceManager and then add the document namespace with the fictitious prefix "a".

Once the XmlNamespaceManager has been set up we can go and query the document, but this time adding "a:" prefix before every node name:

XmlNode entlibDataNode = doc.SelectSingleNode(
"/a:Project/a:ItemGroup/a:Reference[a:Name='Microsoft.Practices.EnterpriseLibrary.Data']",
nsManager
);

I also noticed that this approach is probably used also by the XML Notepad 2007. If you open a VisualStudio project file with the XML Notepad and open the Find dialog selecting "Use XPath", and then you select a node of the XML, in the search string you will notice that it generates the XPath string using the prefix "a" before every node name.

xmlNotepad_search

Not sure if it's a bug or a feature, but this way it works. Hope this will save a bit of your time.

kick it on DotNetKicks.com

Technorati Tag: ,,
posted on Wednesday, January 9, 2008 12:39 AM

Comments on this entry:

# re: How to query a XPath doc that has a default namespace

Left by John-Daniel Trask at 1/9/2008 1:30 AM

I ran into that issue several years back - it's a real pain in the backside!

I don't think it's a bug but it sure would be nice if you could enabled a "relaxed mode" which just does what you wish it would do! :)

- JD

Comments have been closed on this topic.