title: XPath, XML Namespaces and Java
body: <p>I've spent the past day attempting to extract a one XML node out of the following document and am unable to grasp the nuances of XML Namespaces to make it work.</p>
  
  <p>The XML file is to large to post in total so here is the portion that concerns me:</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="ISO-8859-1" standalone="no"?&gt;
  &lt;XFDL xmlns="http://www.PureEdge.com/XFDL/6.5" xmlns:custom="http://www.PureEdge.com/XFDL/Custom" xmlns:designer="http://www.PureEdge.com/Designer/6.1" xmlns:pecs="http://www.PureEdge.com/PECustomerService" xmlns:xfdl="http://www.PureEdge.com/XFDL/6.5"&gt;
     &lt;globalpage sid="global"&gt;
        &lt;global sid="global"&gt;
           &lt;xmlmodel xmlns:xforms="http://www.w3.org/2003/xforms"&gt;
              &lt;instances&gt;
                 &lt;xforms:instance id="metadata"&gt;
                    &lt;form_metadata&gt;
                       &lt;metadataver version="1.0"/&gt;
                       &lt;metadataverdate&gt;
                          &lt;date day="05" month="Jul" year="2005"/&gt;
                       &lt;/metadataverdate&gt;
                       &lt;title&gt;
                          &lt;documentnbr number="2062" prefix.army="DA" scope="army" suffix=""/&gt;
                          &lt;longtitle&gt;HAND RECEIPT/ANNEX NUMBER &lt;/longtitle&gt;
                       &lt;/title&gt;
  </code></pre>
  
  <p>The document continues and is well formed all the way down.  I am attempting to extract the "number" attribute from the "documentnbr" tag (three from the bottom).</p>
  
  <p>The code that I'm using to do this looks like this:</p>
  
  <pre><code>/***
       * Locates the Document Number information in the file and returns the form number.
       * @return File's self-declared number.
       * @throws InvalidFormException Thrown when XPath cannot find the "documentnbr" element in the file.
       */
      public String getFormNumber() throws InvalidFormException
      {
          try{
              XPath xPath = XPathFactory.newInstance().newXPath();
              xPath.setNamespaceContext(new XFDLNamespaceContext());
  
              Node result = (Node)xPath.evaluate(QUERY_FORM_NUMBER, doc, XPathConstants.NODE);
              if(result != null) {
                  return result.getNodeValue();
              } else {
                  throw new InvalidFormException("Unable to identify form.");
              }
  
          } catch (XPathExpressionException err) {
              throw new InvalidFormException("Unable to find form number in file.");
          }
  
      }
  </code></pre>
  
  <p>Where QUERY_FORM_NUMBER is my XPath expression, and XFDLNamespaceContext implements NamespaceContext and looks like this:</p>
  
  <pre><code>public class XFDLNamespaceContext implements NamespaceContext {
  
      @Override
      public String getNamespaceURI(String prefix) {
          if (prefix == null) throw new NullPointerException("Invalid Namespace Prefix");
          else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX))
              return "http://www.PureEdge.com/XFDL/6.5";
          else if ("custom".equals(prefix))
              return "http://www.PureEdge.com/XFDL/Custom";
          else if ("designer".equals(prefix)) 
              return "http://www.PureEdge.com/Designer/6.1";
          else if ("pecs".equals(prefix)) 
              return "http://www.PureEdge.com/PECustomerService";
          else if ("xfdl".equals(prefix))
              return "http://www.PureEdge.com/XFDL/6.5";      
          else if ("xforms".equals(prefix)) 
              return "http://www.w3.org/2003/xforms";
          else    
              return XMLConstants.NULL_NS_URI;
      }
  
      @Override
      public String getPrefix(String arg0) {
          // TODO Auto-generated method stub
          return null;
      }
  
      @Override
      public Iterator getPrefixes(String arg0) {
          // TODO Auto-generated method stub
          return null;
      }
  
  }
  </code></pre>
  
  <p>I've tried many different XPath queries but I keep feeling like this should work:</p>
  
  <pre><code>protected static final String QUERY_FORM_NUMBER = 
          "/globalpage/global/xmlmodel/xforms:instances/instance" + 
          "/form_metadata/title/documentnbr[number]";
  </code></pre>
  
  <p>Unfortunately it does not work and I continually get a null return.</p>
  
  <p>I've done a fair amount of reading <a href="https://stackoverflow.com/questions/122463/how-to-retrieve-namespaces-in-xml-files-using-xpath">here</a>, <a href="http://www.ibm.com/developerworks/xml/library/x-nmspccontext/index.html?ca=drs-" rel="nofollow noreferrer">here</a>, and <a href="http://blog.davber.com/2006/09/17/xpath-with-namespaces-in-java/" rel="nofollow noreferrer">here</a>, but nothing has proved sufficiently illuminating to help me get this working.  </p>
  
  <p>I'm almost positive that I'm going to face-palm when I figure this out but I'm really at wit's end as to what I'm missing.</p>
  
  <p>Thank you for reading through all of this and thanks in advance for the help.</p>
  
  <p>-Andy</p>