NamespaceContext and using namespaces with XPath NamespaceContext and using namespaces with XPath xml xml

NamespaceContext and using namespaces with XPath


It is possible to get a NamespaceContext instance without writing your own class. Its class-use page shows you can get one using the javax.xml.stream package.

String ctxtTemplate = "<data xmlns=\"http://base\" xmlns:foo=\"http://foo\" />";NamespaceContext nsContext = null;XMLInputFactory factory = XMLInputFactory.newInstance();XMLEventReader evtReader = factory    .createXMLEventReader(new StringReader(ctxtTemplate));while (evtReader.hasNext()) {  XMLEvent event = evtReader.nextEvent();  if (event.isStartElement()) {    nsContext = ((StartElement) event)        .getNamespaceContext();    break;  }}System.out.println(nsContext.getNamespaceURI(""));System.out.println(nsContext.getNamespaceURI("foo"));System.out.println(nsContext    .getNamespaceURI(XMLConstants.XMLNS_ATTRIBUTE));System.out.println(nsContext    .getNamespaceURI(XMLConstants.XML_NS_PREFIX));

Forgoing prefixes altogether is likely to lead to ambiguous expressions - if you want to drop namespace prefixes, you'd need to change the document format. Creating a context from a document doesn't necessarily make sense. The prefixes have to match the ones used in the XPath expression, not the ones in any document, as in this code:

String xml = "<data xmlns=\"http://base\" xmlns:foo=\"http://foo\" >"    + "<foo:value>"    + "hello"    + "</foo:value>"    + "</data>";String expression = "/stack:data/overflow:value";class BaseFooContext implements NamespaceContext {  @Override  public String getNamespaceURI(String prefix) {    if ("stack".equals(prefix))      return "http://base";    if ("overflow".equals(prefix))      return "http://foo";    throw new IllegalArgumentException(prefix);  }  @Override  public String getPrefix(String namespaceURI) {    throw new UnsupportedOperationException();  }  @Override  public Iterator<String> getPrefixes(      String namespaceURI) {    throw new UnsupportedOperationException();  }}XPathFactory factory = XPathFactory.newInstance();XPath xpath = factory.newXPath();xpath.setNamespaceContext(new BaseFooContext());String value = xpath.evaluate(expression,    new InputSource(new StringReader(xml)));System.out.println(value);

Neither the implementation returned by the StAX API nor the one above implement the full class/method contracts as defined in the doc. You can get a full, map-based implementation here.


I've just been working through using xpath and NamespaceContexts myself. I came across a good treatment of the issue on developerworks.


I found a convenient implementation in "Apache WebServices Common Utilities" called NamespaceContextImpl.

You can use the following maven dependency to obtain this class:

<dependency>    <groupId>org.apache.ws.commons</groupId>    <artifactId>ws-commons-util</artifactId>    <version>1.0.1</version></dependency>

I've use it in the following manner (I know its built for sax, but after reading the code, its o.k):

NamespaceContextImpl nsContext = new NamespaceContextImpl();nsContext.startPrefixMapping("foo", "my.name.space.com");

You don't need to called endPrefixMapping.