Affichage des articles dont le libellé est namespace. Afficher tous les articles
Affichage des articles dont le libellé est namespace. Afficher tous les articles

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);