1

I have this XML document:

<?xml version="1.0" encoding="utf-8"?>
<document xmlns="file:///someurl/goes.here">
  <levelone>
    <leveltwo>
      <title>Test Title</title>
      <item>Item 1</item>
      <item>Item 2</item>
      <item>Item 3</item>
    </leveltwo>
  </levelone>
</document>

And this code:

static void Main(string[] args)
{
    XmlDocument fileIn = new XmlDocument();
    fileIn.Load("XMLFile1.xml");
    XmlNamespaceManager nsm = new XmlNamespaceManager(fileIn.NameTable);
    nsm.AddNamespace(String.Empty, "file:///someurl/goes.here");
    XmlNode docElem = fileIn.DocumentElement;
    string title = docElem.SelectSingleNode("levelone/leveltwo/title", nsm).InnerText;
    Console.WriteLine("Title: " + title);
    Console.WriteLine("Items: " + docElem.SelectNodes("//item", nsm).Count);
    Environment.Exit(0);
}

If I run this, I get a NullReferenceException when I attempt to get the InnerText of the node I'm attempting to select for title. However, if I change my AddNamespace call to nsm.AddNamespace("a", "file:///someurl/goes.here") and update all of my XPaths to use that a namespace, then it works fine.

My understanding is that elements without the prefixes in an XPath refer to the empty namespace. String.Empty is said to be for the empty namespace in MSDN's docs, and I'm giving the NamespaceManager the correct namespace URI for the empty namespace. Yet it doesn't seem to be working and I find myself having to make a dummy namespace in the manager to get it to work right, which is really annoying. Why do I have to use this, or any workaround?

I am not looking for a way to get my code to run, I know of a couple ways and detailed one widely-accepted method above. I want to know why my understanding of the documentation is resulting in broken code - e.g. is this an issue on Microsoft's end or am I just misunderstanding something?

p0lar_bear
  • 2,203
  • 2
  • 21
  • 31
  • 1
    possible duplicate of [Why does NamespaceManager not use DefaultNamespace when using no prefix in XPath](http://stackoverflow.com/questions/26630995/why-does-namespacemanager-not-use-defaultnamespace-when-using-no-prefix-in-xpath) – JLRishe Dec 02 '14 at 14:42
  • You are misunderstanding something. Did you read the **Note** directly underneath the text you are talking about on that MSDN page? – JLRishe Dec 02 '14 at 14:46
  • @JLRishe Okay, I see that it says "...a prefix must be specified." However, immediately after that, it says "If an XPath expression does not include a prefix, it is assumed that the namespace Uniform Resource Identifier (URI) is the empty namespace." What does that mean, exactly? It seems worded odd and I understand that as that the given URI will be assigned to the empty namespace... – p0lar_bear Dec 02 '14 at 15:03
  • 1
    The empty namespace, a.k.a. the null namespace, is the namespace with no URI. I.e. the namespace that this element is in: ``. – JLRishe Dec 02 '14 at 16:01

1 Answers1

0

Your XML elements are bound to the namespace file:///someurl/goes.here. Although a namespace-prefix isn't used (or required) for the XML content, you need to register and then use a namespace-prefix in your XPath if you want to address any of those elements that are bound to a namespace.

https://learn.microsoft.com/en-us/dotnet/standard/data/xml/xpath-queries-and-namespaces#the-default-namespace

XPath treats the empty prefix as the null namespace. In other words, only prefixes mapped to namespaces can be used in XPath queries. This means that if you want to query against a namespace in an XML document, even if it is the default namespace, you need to define a prefix for it.

An XPath that does not have a namespace-prefix is addressing items in the null "no namespace" and your XML content is bound to a namespace. So, you must use a namespace-prefix (that is defined and refers to the namespace-uri) in your XPath.

Change your code to register a prefix for that URI (doesn't matter what you use). For the purpose of this example, let's use the namespace-prefix "x":

nsm.AddNamespace("x", "file:///someurl/goes.here");

And then adjust your XPath to use that namespace-prefix:

string title = docElem.SelectSingleNode("x:levelone/x:leveltwo/x:title", nsm).InnerText;
Console.WriteLine("Title: " + title);
Console.WriteLine("Items: " + docElem.SelectNodes("//x:item", nsm).Count);
Mads Hansen
  • 63,927
  • 12
  • 112
  • 147