title: XPath and namespace specification for XML documents with an explicit default namespace
body: <p>I'm struggling to get the correct combination of an XPath expression and the namespace specification as required by package <a href="http://cran.r-project.org/web/packages/XML/index.html" rel="nofollow noreferrer"><code>XML</code></a> (argument <code>namespaces</code>) <strong>for a XML document that has an explicit <code>xmlns</code> namespace</strong> defined at the top element.</p>
  
  <h2>UPDATE</h2>
  
  <p>Thanks to har07 I was able to put it together:</p>
  
  <p>Once you query the namespaces, the first entry of <code>ns</code> has no name yet and that's the problem:</p>
  
  <pre><code>nsDefs &lt;- xmlNamespaceDefinitions(doc)
  ns &lt;- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))
  
  &gt; ns
                                               omegahat                          r 
      "http://something.org"  "http://www.omegahat.org" "http://www.r-project.org" 
  </code></pre>
  
  <p>So we'll just assign a name that serves as a prefix (this can be any valid R name):</p>
  
  <pre><code>names(ns)[1] &lt;- "xmlns"
  </code></pre>
  
  <p>Now all we have to do is using that default namespace prefix <strong>everywhere</strong> in our XPath expressions:</p>
  
  <pre><code>getNodeSet(doc, "/xmlns:doc//xmlns:b[@omegahat:status='foo']", ns)
  </code></pre>
  
  <p>For those interested in alternative solutions based on <code>name()</code> and <code>namespace-uri()</code> (amongst others) might find <a href="https://stackoverflow.com/questions/5239685/xml-namespace-breaking-my-xpath">this post</a> helpful.</p>
  
  <hr>
  
  <p>Just for the sake of reference: this was the trial-and-error code before we came to the solution:</p>
  
  <p>Consider the example from <code>?xmlParse</code>: </p>
  
  <pre><code>require("XML")
  
  doc &lt;- xmlParse(system.file("exampleData", "tagnames.xml", package = "XML"))
  
  &gt; doc
  &lt;?xml version="1.0"?&gt;
  &lt;doc&gt;
    &lt;!-- A comment --&gt;
    &lt;a xmlns:omegahat="http://www.omegahat.org" xmlns:r="http://www.r-project.org"&gt;
      &lt;b&gt;
        &lt;c&gt;
          &lt;b/&gt;
        &lt;/c&gt;
      &lt;/b&gt;
      &lt;b omegahat:status="foo"&gt;
        &lt;r:d&gt;
          &lt;a status="xyz"/&gt;
          &lt;a/&gt;
          &lt;a status="1"/&gt;
        &lt;/r:d&gt;
      &lt;/b&gt;
    &lt;/a&gt;
  &lt;/doc&gt;
  nsDefs &lt;- xmlNamespaceDefinitions(getNodeSet(doc, "/doc/a")[[1]])
  ns &lt;- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))
  getNodeSet(doc, "/doc//b[@omegahat:status='foo']", ns)[[1]]
  </code></pre>
  
  <p>In my document, however, the namespaces are already defined in <code>&lt;doc&gt;</code> tag, so I adapted the example XML code accordingly:</p>
  
  <pre><code>xml_source &lt;- c(
    "&lt;?xml version=\"1.0\"?&gt;",
    "&lt;doc xmlns:omegahat=\"http://www.omegahat.org\" xmlns:r=\"http://www.r-project.org\"&gt;",
    "&lt;!-- A comment --&gt;",
    "&lt;a&gt;",
    "&lt;b&gt;",
    "&lt;c&gt;",
    "&lt;b/&gt;",
    "&lt;/c&gt;",
    "&lt;/b&gt;",
    "&lt;b omegahat:status=\"foo\"&gt;",
    "&lt;r:d&gt;",
    "&lt;a status=\"xyz\"/&gt;",
    "&lt;a/&gt;",
    "&lt;a status=\"1\"/&gt;",
    "&lt;/r:d&gt;",
    "&lt;/b&gt;",
    "&lt;/a&gt;",
    "&lt;/doc&gt;"
  )
  write(xml_source, file="exampleData_2.xml")  
  doc &lt;- xmlParse("exampleData_2.xml")
  nsDefs &lt;- xmlNamespaceDefinitions(doc)
  ns &lt;- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))    
  getNodeSet(doc, "/doc", namespaces = ns)
  getNodeSet(doc, "/doc//b[@omegahat:status='foo']", namespaces = ns)[[1]]  
  </code></pre>
  
  <p>Everything still works fine. What's more, though, is that my XML code additionally has an explicit definition of the default namespace (<code>xmlns</code>):</p>
  
  <pre><code>xml_source &lt;- c(
    "&lt;?xml version=\"1.0\"?&gt;",
    "&lt;doc xmlns=\"http://something.org\" xmlns:omegahat=\"http://www.omegahat.org\" xmlns:r=\"http://www.r-project.org\"&gt;",
    "&lt;!-- A comment --&gt;",
    "&lt;a&gt;",
    "&lt;b&gt;",
    "&lt;c&gt;",
    "&lt;b/&gt;",
    "&lt;/c&gt;",
    "&lt;/b&gt;",
    "&lt;b omegahat:status=\"foo\"&gt;",
    "&lt;r:d&gt;",
    "&lt;a status=\"xyz\"/&gt;",
    "&lt;a/&gt;",
    "&lt;a status=\"1\"/&gt;",
    "&lt;/r:d&gt;",
    "&lt;/b&gt;",
    "&lt;/a&gt;",
    "&lt;/doc&gt;"  
  )
  write(xml_source, file="exampleData_3.xml")  
  doc &lt;- xmlParse("exampleData_3.xml")
  nsDefs &lt;- xmlNamespaceDefinitions(doc)
  ns &lt;- structure(sapply(nsDefs, function(x) x$uri), names = names(nsDefs))
  </code></pre>
  
  <p>What used to work fails now:</p>
  
  <pre><code>&gt; getNodeSet(doc, "/doc", namespaces = ns)
  list()
  attr(,"class")
  [1] "XMLNodeSet"
  Warning message:
  using http://something.org as prefix for default namespace http://something.org 
  
  &gt; getNodeSet(doc, "/xmlns:doc", namespaces = ns)
  XPath error : Undefined namespace prefix
  XPath error : Invalid expression
  Error in xpathApply.XMLInternalDocument(doc, path, fun, ..., namespaces = namespaces,  : 
    error evaluating xpath expression /xmlns:doc
  In addition: Warning message:
  using http://something.org as prefix for default namespace http://something.org 
  getNodeSet(doc, "/xmlns:doc", 
    namespaces = matchNamespaces(doc, namespaces="xmlns", nsDefs = nsDefs)
  )
  </code></pre>
  
  <p>This seems to get me closer:</p>
  
  <pre><code>&gt; getNodeSet(doc, "/xmlns:doc",
  + namespaces = matchNamespaces(doc, namespaces="xmlns", nsDefs = nsDefs)
  + )[[1]]
  &lt;doc xmlns="http://something.org" xmlns:omegahat="http://www.omegahat.org" xmlns:r="http://www.r-project.org"&gt;
    &lt;!-- A comment --&gt;
    &lt;a&gt;
      &lt;b&gt;
        &lt;c&gt;
          &lt;b/&gt;
        &lt;/c&gt;
      &lt;/b&gt;
      &lt;b omegahat:status="foo"&gt;
        &lt;r:d&gt;
          &lt;a status="xyz"/&gt;
          &lt;a/&gt;
          &lt;a status="1"/&gt;
        &lt;/r:d&gt;
      &lt;/b&gt;
    &lt;/a&gt;
  &lt;/doc&gt; 
  
  attr(,"class")
  [1] "XMLNodeSet"
  </code></pre>
  
  <p>Yet, now I don't know how to proceed in order to get to the children nodes:</p>
  
  <pre><code>&gt; getNodeSet(doc, "/xmlns:doc//b[@omegahat:status='foo']", ns)[[1]]
  XPath error : Undefined namespace prefix
  XPath error : Invalid expression
  Error in xpathApply.XMLInternalDocument(doc, path, fun, ..., namespaces = namespaces,  : 
    error evaluating xpath expression /xmlns:doc//b[@omegahat:status='foo']
  In addition: Warning message:
  using http://something.org as prefix for default namespace http://something.org 
  
  &gt; getNodeSet(doc, "/xmlns:doc//b[@omegahat:status='foo']",
  + namespaces = c(
  + matchNamespaces(doc, namespaces="xmlns", nsDefs = nsDefs),
  + matchNamespaces(doc, namespaces="omegahat", nsDefs = nsDefs)
  + )
  + )
  list()
  attr(,"class")
  [1] "XMLNodeSet"
  </code></pre>