Houlàlà je vois ce qui se passe. C'est compliqué.
C'est à cause de la gestion désastreuse des namespaces par Java.
Par défaut, DocumentBuilderFactory considère que les namespaces, ça n'existe pas. On peut changer ce comportement en appelant setNamespaceAware(true) dessus, mais si on le fait pas, par défaut, les namespaces ça existe pas.
Normalement, tu devrais échouer avec les deux méthodes. Mais dans le cas de passer par un fichier temporaire, la non-gestion des namespaces te sauve.
Seulement, quand tu ne passes pas par un fichier temporaire, ce n'est pas ton DocumentBuilderFactory qui te génère le document. C'est ton TransformerFactory. Et lui il est bien obligé de gérer les namespaces, parceque XSLT c'est basé à fond sur les namespaces. Il te génère donc un document dans lequel les namespaces, ça existe, et tous les éléments sont dans le namespace http://www.example.org/test.
Ces éléments étant dans un namespace, tu ne peux pas les atteindre avec un XPath genre /Message/Out/Personne/CodeCivilite. En effet, avec ce XPath tu n'indiques pas dans quel namespace sont les éléments. Or c'est obligatoire.
Il faut que ton XPath ressemble à ça : /t:Message/t:Out/t:Personne/t:CodeCivilite.
Tous les éléments doivent avoir un préfixe, là j'ai choisi t: pour test, qui indique qu'ils sont dans un namespace.
Il reste à lier ce préfixe t: au namespace http://www.example.org/test, et ça se fait comme ça :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| xPathProcessor.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if(prefix.equals("t")) {
return "http://www.example.org/test";
} else {
return null;
}
}
@Override public String getPrefix(String namespaceURI) {
return null; // on s'en fout
}
@Override
public Iterator<?> getPrefixes(String namespaceURI) {
return null; // on s'en fout aussi
}
}); |
Avec ces deux corrections, tu peux essayer, la méthode sans fichier temporaire marche.
Mais la méthode avec fichier temporaire ne marche plus -_-°. Parce qu'on vient de gérer les namespaces, alors que la méthode avec fichier temporaire n'a pas de namespaces.
Pour corriger ça, il faudrait faire :
dbf.setNamespaceAware(true);
Mais si on fait ça, les deux méthodes cessent de marcher ! Parce que la transformation XSLT ne tranforme plus les <In> en <Out> !
Eh oui. Parce que Java de base ne gère pas XSLT 2.0 mais XSLT 1.0. En XSLT 1.0, xpath-default-namespace n'existe pas. Par conséquent, si tu fais un match comme
<xsl:template match="In">
Il considère que c'est les éléments <In> sans namespace, pas ceux avec namespace. Avant ça marchait, parce que les namespaces n'existaient pas.
Mais maintenant qu'on les a activés, ça ne marche plus !
Deux possibilités :
- utiliser un moteur XSLT compatible 2.0, comme Saxon par exemple.
- modifier la XSLT, avec un match comme ça :
<xsl:template match="t:In">
et ajouter xmlns:t="http://www.example.org/test" dans la stylesheet.
=> Problèmes résolus !
Ça aurait été plus simple avec JDOM :
- Lui il gère toujours les namespaces. Tu aurais eu les mêmes problèmes avec les deux méthodes.
- Faire une requête XPath avec namespace est plus simple.
Partager