XPath, les espaces de noms XML et Java
J'ai passé la dernière journée de tenter d'extraire un nœud XML d'un document et je suis incapable de saisir les nuances des espaces de noms XML pour le faire fonctionner.
Le fichier XML est de gros à poste au total donc, ici, est la partie qui me concerne:
<?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
<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">
<globalpage sid="global">
<global sid="global">
<xmlmodel xmlns:xforms="http://www.w3.org/2003/xforms">
<instances>
<xforms:instance id="metadata">
<form_metadata>
<metadataver version="1.0"/>
<metadataverdate>
<date day="05" month="Jul" year="2005"/>
</metadataverdate>
<title>
<documentnbr number="2062" prefix.army="DA" scope="army" suffix=""/>
<longtitle>HAND RECEIPT/ANNEX NUMBER </longtitle>
</title>
Le document se poursuit et est bien formé tout le chemin vers le bas. Je suis d'essayer d'extraire le "numéro" de l'attribut de la "documentnbr" tag (trois à partir du bas).
Le code que j'utilise pour ce faire ressemble à ceci:
/***
* 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.");
}
}
Où QUERY_FORM_NUMBER est mon expression XPath, et XFDLNamespaceContext implémente NamespaceContext et ressemble à ceci:
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;
}
}
J'ai essayé beaucoup de différentes requêtes XPath mais je garde le sentiment que cela devrait fonctionner:
protected static final String QUERY_FORM_NUMBER =
"/globalpage/global/xmlmodel/xforms:instances/instance" +
"/form_metadata/title/documentnbr[number]";
Malheureusement, il ne fonctionne pas et je ne cesse d'obtenir un retour null.
J'ai fait une bonne quantité de lecture ici, ici, et ici, mais rien n'a prouvé suffisamment éclairante pour m'aider à obtenir ce travail.
Je suis presque certain que je vais en face-palm quand je l'ai trouver ça mais je suis vraiment au bout du rouleau comme pour ce que je suis absent.
Vous remercie pour la lecture par le biais de tout cela, et merci d'avance pour l'aide.
-Andy
Vous devez vous connecter pour publier un commentaire.
Aha, j'ai essayé de déboguer votre expression + réussi à le faire fonctionner. Vous avez raté quelques choses. Cette expression XPath devrait le faire:
instance
avecxforms:instance
puis getNamespaceURI() est appelée une fois avecxforms
que l'argument d'entrée, mais le programme déclenche une exception.@attr
, pas[attr]
.Mon exemple complet de code:
dbfac.SetNamespaceAware(true)
avant de générer le DocumentBuilder peut changer les résultats.SAX (alternative à XPath) version:
Je vois c'est plus compliqué à utiliser XPath avec des espaces de noms qu'il devrait être (à mon avis). Voici mon (simple) code:
Vous pouvez obtenir NamespaceContextMap classe (pas le mien) à partir de ici (licence GPL). Il est également Six million trois cent soixante seize mille cinquante huit bug.
Ont un look à la XPathAPI de la bibliothèque. C'est une façon plus simple d'utiliser XPath sans jouer avec le faible niveau de l'API Java, en particulier lorsque vous traitez avec des espaces de noms.
Le code pour obtenir l'
number
attribut:Les espaces de noms sont automatiquement extraites à partir du nœud racine (
doc
dans ce cas). Dans le cas où vous avez besoin de définir explicitement les espaces de noms supplémentaires vous pouvez utiliser ceci:(Disclaimer: je suis l'auteur de la bibliothèque.)