tags:

views:

29

answers:

3

I have the following XML that is provided to me and I cannot change it:

<Parent>
  <Settings Version="1234" xmlns="urn:schemas-stuff-com"/>
</Parent>

I am trying to retrieve the "Version" attribute value using XPath. It appears since the xmlns is defined without an alias it automatically assigns that xmlns to the Settings node. When I read this XML into an XMLDocument and view the namespaceURI value for the Settings node it is set to "urn:schemas-stuff-com".

I have tried:

//Parent/Settings/@Version - returns Null

//Parent/urn:schemas-stuff-com:Settings/@Version - invalid syntax

A: 

The solution depends on which version of XPath you are using. In XPath 2.0 the following should work:

declare namespace foo = "urn:schemas-stuff-com";
xs:string($your_xml//Parent/foo:Settings/@Version)

In XPath 1.0, on the other hand, the only solution I've managed to get to work was:

//Parent/*[name() = Settings and namespace-uri() = "urn:schemas-stuff-com"]/@Version

It seems to me that the XPath processor doesn't change the default namespace when it changes between nodes, though I am not sure whether this is really the case.

Hope this helps.

finrod
@finrod - `namespace()` should be `namespace-uri()`.
Mads Hansen
@Mads Hansen - of course you're right. Fixed.
finrod
I ended up using the XPath 1.0 syntax because of some other reasons I would have had to dynamically create the 'foo' namespace name which I didn't want to do. You have a typo in your example though..."Settings" should be wrapped in single quotes.thanks for the help all.
Jay
A: 

Use an XmlNamespaceManager:

XmlDocument doc = new XmlDocument();
doc.Load("file.xml");

XmlNamespaceManager mgr = new XmlNamespaceManager(doc.NameTable);
mgr.AddNamespace("foo", "urn:schemas-stuff-com");

XmlElement settings = doc.SelectSingleNode("Parent/foo:Settings", mgr) as XmlElement;
if (settings != null)
{
  // access settings.GetAttribute("version") here
}

// or alternatively select the attribute itself with XPath e.g.
XmlAttribute version = doc.SelectSingleNode("Parent/foo:Settings/@Version", mgr) as XmlAttribute;
if (version != null)
{
  // access version.Value here
}
Martin Honnen
A: 

In addition to Martin Honnen's correct answer, which unfortunately is implementation and programming-language specific, here is a pure XPath solution:

/*/*[name()='Settings ']/@Version
Dimitre Novatchev
Which is pretty similar to mine below, only it (potentially) could also catch other nodes
finrod