dimanche 15 juin 2008

Utiliser xpath

Dans cet article, je présente une petite collection de requête exemple de xpath. En la matière, l'empirisme est roi !

Comment retrouver tous les élément img dans un document html (Quelque soit leur hiérarchie)

XPath xpath = XPathFactory.newInstance().newXPath();
InputSource is = new InputSource(new FileInputStream(
"src/test/resources/testXpath.xml"));
NodeList str =(NodeList) xpath.evaluate("//img",
is,XPathConstants.NODESET);
log.debug(str.getLength());


Comment effectuer une transformation à l'aide de XPATH (Sans utiliser XQuery)
XPath xpath = XPathFactory.newInstance().newXPath();
DocumentBuilder db = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document document = db.parse(new File(
"src/test/resources/testXpath.xml"));
InputSource is = new InputSource(new FileInputStream(
"src/test/resources/testXpath.xml"));
NodeList str = (NodeList) xpath.evaluate("//img", document,
XPathConstants.NODESET);
Element el = (Element) str.item(0);
el.setAttribute("src", "newValue");
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
Source source = new DOMSource(document);
StreamResult sr = new StreamResult(System.out);
transformer.transform(source, sr);



Attention à la manipulation des namespaces dans XPATH !

Quand les requêtes xpath utilisent des namespaces, deux options sont possible :

La première est d'utiliser les noms absolus et non pas les alias pour effectuer la recherche :

//urn:oasis:names:tc:opendocument:xmlns:text:1.0:span


Malheureusement, cette méthode ne fonctionne lorsque les namespaces comportent le caractère '/' (qui sont descaractère utilisé pour écrire les requête Xpath). Dans ce cas, une deuxième méthode consiste à fournir à Xpath les alias des namspaces que nous utiliserons dans la requête. Cette approche est préférable, car les namespaces qui ne comportent pas de '/' sont plutôt rares.


NamespaceContext ctx = new NamespaceContext() {
public String getNamespaceURI(String prefix) {
String uri;
if (prefix.equals("w")) {
uri = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
}
else if (prefix.equals("ns2")) {
uri = "http://www.davber.com/sales-format";
}
else {
uri = null;
}
return uri;
}
public String getPrefix(String namespaceURI) {
return null;
}
public Iterator getPrefixes(String namespaceURI) {
return null;
}
};
xpath.setNamespaceContext(ctx);


Il faut également rappeler que les namespaces sont héritables par les balise fille lorsque le namespace est déclaré par un attribut xmlns. Concrétement, dans l'exemple suivant, la balise Relationship est à rechercher dans le namespace : http://schemas.openxmlformats.org/package/2006/relationships car la balise parente Relationships est affectée à ce namespace par l'attribut xmlns.


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId8" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" Target="footer1.xml"/><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Target="settings.xml"/><Relationship Id="rId7" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" Target="header1.xml"/><Relationship Id="rId2"



Dans le cas ou le JDK a une version inférieure à la 1.5, JDOM fournira l'api XPath.



SAXBuilder sxb = new SAXBuilder();
File file = new File(filename);
FileInputStream fis = new FileInputStream(file);
InputSource is = new InputSource(fis);
is.setEncoding("ISO-8859-1");
org.jdom.Document document = sxb.build(is);
// On initialise un nouvel élément racine avec l'élément racine du
// document.
Element racine = document.getRootElement();
XPath xpath = XPath.newInstance("count(/document/firstBranch/order/orderStatus/OrderStatusCode[text()='MARECHERCHE'])");
String result = xpath.valueOf(racine);


Exemple de requête

Pour compter le nombre de balise ayant l'arborescence /document/firstBranch/order/orderStatus/OrderStatusCode et contenant le texte 'MARECHERCHE'

/document/firstBranch/order/orderStatus/OrderStatusCode[text()='MARECHERCHE'])



Pour récuppérer toutes les balises img sous forme de nodeset


xpath.evaluate("//img", document,
XPathConstants.NODESET);

Aucun commentaire: