3

OK, so I've been pulling my hair out all day with this problem in XPATH and C#.

I have the following XML document:

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0"     xmlns:c="http://base.google.com/cns/1.0">
  <item id="362">
    <title>Family Holiday</title>
    <description>a long, wordy description goes here</description>
    <g:id xmlns:g="g">FPS</g:id>
    <g:latitude xmlns:g="g">42.502260</g:latitude>
    <g:longitude xmlns:g="g">1.532850</g:longitude>
  </item>
 </entry>

I then do the following:

XmlDocument _xmlDocument = new XmlDocument();
_xmlDocument.Load(xmlfile);

XmlNamespaceManager _nameSpaceManager = new XmlNamespaceManager(_xmlDocument.NameTable);
_nameSpaceManager.AddNamespace("RN", "http://www.w3.org/2005/Atom");
_nameSpaceManager.AddNamespace("g", "http://base.google.com/ns/1.0");
_nameSpaceManager.AddNamespace("c", "http://base.google.com/cns/1.0");

XPathNavigator navigator = _xmlDocument.CreateNavigator();

My problem lies with this:

XmlNode nde = _xmlDocument.SelectSingleNode("/RN:entry/RN:item/g:id", _nameSpaceManager);

returns null - not the Id node. However,

XmlNode nde = _xmlDocument.SelectSingleNode("/RN:entry/RN:item/RN:title", _nameSpaceManager);

does return the title node.

Any ideas on what I'm doing wrong would be much appreciated!

Cheers Simon

7
  • 1
    I believe you have to use the at sign (@) to retrieve attributes Commented Oct 15, 2012 at 15:59
  • 3
    Where did you get your XML from? The locally qualified namespaces (e.g. xmlns:g="g") are wrong; they should be xmlns:g="http://base.google.com/ns/1.0" [or simply omitted, after all, you've defined what namespace g imports in the document element) for your XPath to work. Commented Oct 15, 2012 at 16:12
  • Also keep in mind that the prefixes used in the XML and in your code don't have to match. The only thing that matters is the namespace that defines the prefix. Commented Oct 15, 2012 at 16:23
  • 1
    @MilkyWayJoe - g:id isn't an attribute, it's a node Commented Oct 15, 2012 at 16:28
  • @dthorpe I really wish I could replace wrong with inconsistent :-) Commented Oct 15, 2012 at 16:28

3 Answers 3

3

Your local namespace declarations are overriding the root namespace definitions;

<g:id xmlns:g="g">FPS</g:id>

Is effectively saying the g:id attribute here is coming from the namespace 'g' not the same namespace as g is defined as coming from in your document element.

For example, if I change your XML to:

  string xml = @"<entry xmlns=""http://www.w3.org/2005/Atom"" xmlns:g=""http://base.google.com/ns/1.0""     xmlns:c=""http://base.google.com/cns/1.0"">
                  <item id=""362"">
                    <title>Family Holiday</title>
                    <description>a long, wordy description goes here</description>
                    <g:id xmlns:g=""http://base.google.com/ns/1.0"">FPS</g:id>
                    <g:latitude xmlns:g=""http://base.google.com/ns/1.0"">42.502260</g:latitude>
                    <g:longitude xmlns:g=""http://base.google.com/ns/1.0"">1.532850</g:longitude>
                  </item>
                 </entry>";

or simply:

string xml = @"<entry xmlns=""http://www.w3.org/2005/Atom"" xmlns:g=""http://base.google.com/ns/1.0""     xmlns:c=""http://base.google.com/cns/1.0"">
                      <item id=""362"">
                        <title>Family Holiday</title>
                        <description>a long, wordy description goes here</description>
                        <g:id>FPS</g:id>
                        <g:latitude>42.502260</g:latitude>
                        <g:longitude>1.532850</g:longitude>
                      </item>
                     </entry>";

Your XPath expression works as the local namespace for g now matches the document element namespace declaration of g

If you are stuck with your XML then the only other thing you can do is:

XmlNamespaceManager _nameSpaceManager = new XmlNamespaceManager(_xmlDocument.NameTable);
_nameSpaceManager.AddNamespace("RN", "http://www.w3.org/2005/Atom");
_nameSpaceManager.AddNamespace("g", "g");
_nameSpaceManager.AddNamespace("c", "http://base.google.com/cns/1.0");

Your XPath will now work.

Tested with XmlDocument, .Net Framework version 4.

Sign up to request clarification or add additional context in comments.

Comments

3

I would expect the "/RN:entry/RN:item/g:id" XPath expressions to return null - in your XPath the g: namespace alias refers to the namespace "http://base.google.com/ns/1.0", however in your XML document the g: namespace alias has been modified to refer to the namespace "g" on the id, latitude and longitude elements.

Remove the xmlns:g="g" namespace alias definitions on each of these elements and it should work as expected - namespace alias defintions are inherited from parent XML elements and so these aliases are not needed (as well as being incorrect)

<entry xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0">
  <item id="362">
    <title>Family Holiday</title>
    <description>a long, wordy description goes here</description>
    <g:id>FPS</g:id>
    <g:latitude>42.502260</g:latitude>
    <g:longitude>1.532850</g:longitude>
  </item>
</entry>

If you want to modify your code to work with the unmodified XML then instead change the definition of the g: namespace declaration in code to match the one in the XML

_nameSpaceManager.AddNamespace("g", "g");

Comments

0

Simply replace your line:

_nameSpaceManager.AddNamespace("g", "http://base.google.com/ns/1.0");

with

_nameSpaceManager.AddNamespace("g", "g");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.