jeudi 21 août 2008

requête XPath en java

Une solution simple (à mon goût) existe pour récupérer une valeur ou un attribut dans un fichier Xml en java sans avoir à le parcourir complètement avec Sax ou avec Dom.

Voici un petit exemple de mise en œuvre des APIS XPATH de java 1.5 s'appuyant sur Sax :

Voici le fichier XML source :
<?xml version="1.0" encoding="ISO-8859-1"?>
<level1>
<level2 level2-attribute1="valueOfLevel2-attribute1">
<level3 level3-attribute1="valueOfLevel3-attribute1">
<level41>valueOfLevel41</level41>
<level42>valueOfLevel42</level42>
</level3>
</level2>
</level1>
le code "technique" :

...
import java.io.InputStream;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.xml.sax.InputSource;

...

public static String executeXpath(InputStream sourceXml, String xPathQuery)
throws XPathExpressionException {

// creation de la source sax
InputSource source = new InputSource(sourceXml);

// creation de la requete XPTAH
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xpath = xPathFactory.newXPath();
XPathExpression xPathExpression = xpath.compile(xPathQuery);

/* execution de la requete xPath sur le fichier XML */
String resultat = (String) xPathExpression.evaluate(source,
XPathConstants.STRING);

return resultat;

}
...
}
La mise en œuvre :

public static void main(String[] args) {

try {
/* recuperation du flux xml */

InputStream xml = null;
String result = null;
String xPathQuery = null;

/* exemple 1 */
xml = Main.class.getResourceAsStream("/fichier.xml");
xPathQuery = "/level1/level2/@level2-attribute1";
result = XpathHelper.executeXpath(xml, xPathQuery);

System.out.println("xpathQuery : " + xPathQuery
+ "---> resultat : " + result);

/* exemple 2 */
xml = Main.class.getResourceAsStream("/fichier.xml");
xPathQuery = "/level1/level2/level3/level41";
result = XpathHelper.executeXpath(xml, xPathQuery);

System.out.println("xpathQuery : " + xPathQuery
+ "---> resultat : " + result);
} catch (XPathExpressionException e) {
e.printStackTrace();
}

}


Le résultat en console :
xpathQuery : /level1/level2/@level2-attribute1---> resultat : valueOfLevel2-attribute1
xpathQuery : /level1/level2/level3/level41---> resultat : valueOfLevel41


Le tout a le mérite d'être assez simple, élégant et performant.

3 commentaires:

jey350 a dit…

J'ai mis en ligne sur mon blog, une classe java de gestion des requêtes Xpath avec mise en cache des expressions XPath compilées, pour récupérer le source c'est cette adresse: http://www.devbypractice.com/cache-de-requete-xpath-java/

Anonyme a dit…

Cela ne semble pas fonctionner avec un namespace particulier.

Exemple si dan sle fichier xml on a

blabla

la requete

*[dc:title] ne fonctionnera pas.


Une idée ?

Jérémy Sevellec a dit…

Tout à fait exact, si tu utilises un namespace, il faut mettre en place une classe de type NameSpaceContext comme documenté ici : http://xml.apache.org/xalan-j/xpath_apis.html#namespacecontext