Como usar XPath em documentos xml com espaço para nome padrão

Eu quero manipular xml doc com espaço para nome padrão, mas sem prefixo. Existe uma maneira de usar xpath sem namespace uri como se não houvesse namespace?
Eu acredito que deveria ser possível se definirmos a propriedade namespaceAware de documentBuilderFactory como false. Mas no meu caso não está funcionando.
Meu entendimento está incorreto ou estou cometendo algum erro no código?

Aqui está o meu código:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(false); try { DocumentBuilder builder = domFactory.newDocumentBuilder(); Document dDoc = builder.parse("E:/test.xml"); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nl = (NodeList) xPath.evaluate("//author", dDoc, XPathConstants.NODESET); System.out.println(nl.getLength()); } catch (Exception e) { e.printStackTrace(); } 

Aqui está o meu xml:

        

O processamento XPath para um documento que usa o espaço de nomes padrão (sem prefixo) é o mesmo que o processamento XPath para um documento que usa prefixos:

Para documentos qualificados para espaço de nomes, você pode usar um NamespaceContext ao executar o XPath. Você precisará prefixar os fragments no XPath para corresponder ao NamespaceContext. Os prefixos que você usa não precisam corresponder aos prefixos usados ​​no documento.

Aqui está como se parece com o seu código:

 import java.util.Iterator; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class Demo { public static void main(String[] args) { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setNamespaceAware(true); try { DocumentBuilder builder = domFactory.newDocumentBuilder(); Document dDoc = builder.parse("E:/test.xml"); XPath xPath = XPathFactory.newInstance().newXPath(); xPath.setNamespaceContext(new MyNamespaceContext()); NodeList nl = (NodeList) xPath.evaluate("/ns:root/ns:author", dDoc, XPathConstants.NODESET); System.out.println(nl.getLength()); } catch (Exception e) { e.printStackTrace(); } } private static class MyNamespaceContext implements NamespaceContext { public String getNamespaceURI(String prefix) { if("ns".equals(prefix)) { return "http://www.mydomain.com/schema"; } return null; } public String getPrefix(String namespaceURI) { return null; } public Iterator getPrefixes(String namespaceURI) { return null; } } } 

Nota: Eu também usei o XPath corrigido sugerido por Dennis .

O seguinte também parece funcionar e está mais próximo da sua pergunta original:

 import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathFactory; import org.w3c.dom.Document; import org.w3c.dom.NodeList; public class Demo { public static void main(String[] args) { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); try { DocumentBuilder builder = domFactory.newDocumentBuilder(); Document dDoc = builder.parse("E:/test.xml"); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList nl = (NodeList) xPath.evaluate("/root/author", dDoc, XPathConstants.NODESET); System.out.println(nl.getLength()); } catch (Exception e) { e.printStackTrace(); } } } 

Blaise Doughan está certo, o código em anexo está correto.
Problema estava em algum lugar elese. Eu estava executando todos os meus testes através do lançador de aplicativos no Eclipse IDE e nada estava funcionando. Então eu descobri projeto Eclipse foi causa de todo o pesar. Eu corri minha class no prompt de comando, funcionou. Criado um novo projeto de eclipse e colado o mesmo código lá, ele funcionou lá também. Obrigado a todos pelo seu tempo e esforços.

Eu escrevi uma implementação simples NamespaceContext ( aqui ), que pode ser de ajuda. Ele recebe um Map como input, em que a key é um prefixo e o value é um namespace.

Ele segue a especificação NamespaceContext e você pode ver como ele funciona nos testes de unidade .

 Map mappings = new HashMap<>(); mappings.put("foo", "http://foo"); mappings.put("foo2", "http://foo"); mappings.put("bar", "http://bar"); context = new SimpleNamespaceContext(mappings); context.getNamespaceURI("foo"); // "http://foo" context.getPrefix("http://foo"); // "foo" or "foo2" context.getPrefixes("http://foo"); // ["foo", "foo2"] 

Observe que isso depende do Google Goiaba