So che questa domanda è vecchia ma ho appena trascorso 3 ore a cercare di risolvere questo problema e @kdgregorys answer mi ha aiutato molto. Volevo solo mettere esattamente quello che ho fatto usando kdgregorys come guida.
Il problema è che XPath in java non cerca nemmeno uno spazio dei nomi se non si dispone di un prefisso sulla query, quindi per mappare una query in uno spazio dei nomi specifico è necessario aggiungere un prefisso alla query. Ho usato un prefisso arbitrario per mappare il nome dello schema. Per questo esempio userò lo spazio dei nomi e la query di OP e il prefisso abc
. La vostra nuova espressione sarebbe simile a questa:
String expression = "/abc:html/abc:head/abc:title/text()";
quindi effettuare le seguenti
1) accertarsi che il documento è impostato su namespace consapevoli.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
2) implementare un NamespaceContext
che risolverà il prefisso. Questo ho preso da qualche altro post su SO e modificato un po '
.
public class NamespaceResolver implements NamespaceContext {
private final Document document;
public NamespaceResolver(Document document) {
this.document = document;
}
public String getNamespaceURI(String prefix) {
if(prefix.equals("abc")) {
// here is where you set your namespace
return "http://www.w3.org/1999/xhtml";
} else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) {
return document.lookupNamespaceURI(null);
} else {
return document.lookupNamespaceURI(prefix);
}
}
public String getPrefix(String namespaceURI) {
return document.lookupPrefix(namespaceURI);
}
@SuppressWarnings("rawtypes")
public Iterator getPrefixes(String namespaceURI) {
// not implemented
return null;
}
}
3) Quando si crea l'oggetto XPath impostare il vostro NamespaceContext.
xPath.setNamespaceContext(new NamespaceResolver(document));
Ora non importa quale sia il prefisso dello schema attuale è che si può utilizzare il proprio prefisso che mapperà al corretto schema. Quindi il tuo codice completo utilizzando la classe sopra sarebbe simile a questo.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
Document document = factory.newDocumentBuilder().parse(sourceDocFile);
XPathFactory xPFactory = XPathFactory.newInstance();
XPath xPath = xPFactory.newXPath();
xPath.setNamespaceContext(new NamespaceResolver(document));
String expression = "/abc:html/abc:head/abc:title/text()";
String value = xpath.evaluate(query, expression);
fonte
2014-06-11 07:54:21
Grazie per i suggerimenti. Ho finito per disattivare la consapevolezza dello spazio dei nomi poiché non era necessario per questo semplice caso (cioè lavorando sempre solo con uno spazio dei nomi). – Rob
Come parte, XPath2.0 consente i caratteri jolly dello spazio dei nomi, quindi '*: html/*: head' ad esempio corrisponderà a una testa all'interno di un html in qualsiasi spazio dei nomi. – biziclop
Come altro, JAXP 1.6 (utilizzato in Java 8) è ancora bloccato con XPath 1.0 (https://jaxp.java.net/docs/spec/pdf/JAXP1_6-FinalSpec.pdf 3.5) – Abdull