Pergunta

Quero usar o JDOM para ler em um arquivo XML e, em seguida, use o XPath para extrair dados do documento JDOM. Ele cria bem o objeto do documento, mas quando eu uso o XPath para consultar o documento para uma lista de elementos, não recebo nada.

Meu documento XML possui um espaço de nome padrão definido no elemento raiz. O engraçado é que, quando removo o espaço para nome padrão, ele executa com sucesso a consulta XPath e retorna os elementos que eu quero. O que mais devo fazer para obter minha consulta XPath para retornar os resultados?

Xml:

<?xml version="1.0" encoding="UTF-8"?>
<collection xmlns="http://www.foo.com">
<dvd id="A">
  <title>Lord of the Rings: The Fellowship of the Ring</title>
  <length>178</length>
  <actor>Ian Holm</actor>
  <actor>Elijah Wood</actor>
  <actor>Ian McKellen</actor>
</dvd>
<dvd id="B">
  <title>The Matrix</title>
  <length>136</length>
  <actor>Keanu Reeves</actor>
  <actor>Laurence Fishburne</actor>
</dvd>
</collection>

Java:

public static void main(String args[]) throws Exception {
    SAXBuilder builder = new SAXBuilder();
    Document d = builder.build("xpath.xml");
    XPath xpath = XPath.newInstance("collection/dvd");
    xpath.addNamespace(d.getRootElement().getNamespace());
    System.out.println(xpath.selectNodes(d));
}
Foi útil?

Solução

XPath 1.0 não suporta o conceito de um espaço de nome padrão (XPath 2.0 faz). Qualquer tag não prefixada é sempre assumida como parte do espaço para nome sem nome.

Ao usar XPath 1.0 Você precisa de algo assim:

public static void main(String args[]) throws Exception {
    SAXBuilder builder = new SAXBuilder();
    Document d = builder.build("xpath.xml");
    XPath xpath = XPath.newInstance("x:collection/x:dvd");
    xpath.addNamespace("x", d.getRootElement().getNamespaceURI());
    System.out.println(xpath.selectNodes(d));
}

Outras dicas

Eu tive um problema semelhante, mas o meu era que eu tinha uma mistura de entradas XML, algumas das quais tinham um espaço para nome definido e outras que não tinham. Para simplificar meu problema, executei o seguinte trecho de juiz após o carregamento do documento.

for (Element el : doc.getRootElement().getDescendants(new ElementFilter())) {
    if (el.getNamespace() != null) el.setNamespace(null);
}

Depois de remover todos os namespaces, pude usar simples getChild ("elname") Navegação de estilo ou consultas XPath simples.

Eu não recomendaria essa técnica como uma solução geral, mas, no meu caso, foi definitivamente útil.

Você também pode fazer o seguinte

/*[local-name() = 'collection']/*[local-name() = 'dvd']/

Aqui é lista de consultas XPath úteis.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top