views:

1459

answers:

4

What is the story behind XPATH and support for namespaces? Did XPATH as a specification precede namespaces? If I have a document where elements have been given a default namespace:

<foo xmlns="uri" />

It appears as though some of the XPATH processor libraries won't recognize //foo because of the namespace whereas others will. The option my team has thought about is to add a namespace prefix using regular expressions to the XPATH (you can add a namespace prefix via XmlNameTable) but this seems brittle since XPATH is such a flexible language when it comes to node tests.

Is there a standard that applies to this?

My approach is a bit hackish but it seems to work fine; I remove the xmlns declaration with a search/replace and then apply xpaths.

string readyForXpath = Regex.Replace( xmldocument, "xmlns=\".+\"", String.Empty );

Is that a fair approach or has anyone solved this differently?

+4  A: 

You need local-name():

http://www.w3.org/TR/xpath#function-local-name

To crib from http://jcooney.net/archive/2005/08/09/6517.aspx:

<foo xmlns='urn:foo'>

  <bar>

    <asdf/>

  </bar>            

</foo>

This expression will match the “bar” element:

  //*[local-name()='bar']

This one won't:

 //bar
Stu
A: 

If you are trying to use xslt you can add the namespace in to the stylesheet delcaration. If you do that, you must make sure that there is a prefix or it will not work. If the source XML does not have a prefix, that is still fine, you add your own prefix in the stylesheet.

Stylesheet

<xsl:stylesheet
    xmlns:fb="uri"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

    <xsl:template match="fb:foo/bar">
        <!--  do stuff here -->
    </xsl:template>
</xsl:stylsheet>

Or something like that.

palehorse
+1  A: 

The issue is that an element without a namespace is declared to be in the NULL namespace - therefore if //foo matched against the namespace you consider to be the 'default' there would be no way to refer to an element in the null namespace.

Remember as well that the prefix for a namespace is only a shorthand convention, the real element name (Qualified Name, or QName for short) consists of the full namespace and the local name. Changing the prefix for a namespace does not change the 'identity' of an element - if it is in the same namespace and same local name then it is the same kind of element, even if the prefix is different.

XPath 2.0 (or rather XSLT 2.0) has the concept of the 'default xpath namespace'. You can set the xpath-default-namespace attribute on the xsl:stylesheet element.

samjudson
+3  A: 

I tried something similar to what palehorse proposed and could not get it to work. Since I was getting data from a published service I couldn't change the xml. I ended up using XmlDocument and XmlNamespaceManager like so:

   

XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlWithBogusNamespace);            
XmlNamespaceManager nSpace = new XmlNamespaceManager(doc.NameTable);
nSpace.AddNamespace("myNs", "http://theirUri");

XmlNodeList nodes = doc.SelectNodes("//myNs:NodesIWant",nSpace);
//etc

Andrew Cowenhoven
If you want to select using nodes at multiple depths, you end up having to do something like: `xml.SelectNodes("kml:kml/kml:Document/kml:Folder", manager)`
Drew Noakes