Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XPATH issue in C#

Tags:

c#

xpath

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

like image 913
Swomble Avatar asked Mar 17 '26 01:03

Swomble


2 Answers

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.

like image 99
dash Avatar answered Mar 18 '26 14:03

dash


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");
like image 28
Justin Avatar answered Mar 18 '26 15:03

Justin



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!