\=== Nouveau - Donc vous devez utiliser DOM ===
Pour accélérer les choses, vous pouvez utiliser la mise en cache (comme l'a suggéré l'autre personne). Remarquez que votre code actuel calcule le xpath pour le même nœud plusieurs fois (ou chaque nœud N vous devrez calculer le xpath pour N pour chacun des enfants de N). Voici ce que j'ai en tête pour la mise en cache:
HashMap xpathCache;
HashMap nodeIndexCache;
public String getElementXpath(DOMElement elt){
String path = "";
for (Node fib = (Node) elt; fib != null; fib = fib.getParentNode()){
if (fib.getNodeType() == Node.ELEMENT_NODE){
String cachedParentPath = xpathCache.get(fib);
if (cachedParentPath != null){
path = cachedParentPath + path;
break;
}
DOMElement thisparent = (DOMElement) fib;
int idx = getElementIdx(thisparent);
String xname = thisparent.getTagName();
if (idx >= 1) xname += "[" + idx + "]";
path = "/" + xname + path;
}
}
/*
* ici, non seulement vous connaissez le xpath de elt,
* mais vous connaissez également le xpath des ancêtres de elt.
* Vous pouvez exploiter cela pour mettre en cache le xpath
* des ancêtres également. Mais je mets juste en cache
* le elt à titre d'illustration.
*
* Pour calculer efficacement le xpath des ancêtres, peut-être
* voulez-vous stocker le xpath en utilisant une structure
* de données différente autre qu'une chaîne de caractères.
* Peut-être une pile de chaînes ?
*/
if (! xpathCache.containsKey(elt)){
xpathCache.put (elt, path);
}
return path;
}
private int getElementIdx(DOMElement elt) {
Integer count = nodeIndexCache.get(elt);
if (count != null){
return count;
}
count = 1;
LinkedList siblings = new LinkedList();
for (Node sib = elt.getPreviousSibling(); sib != null; sib = sib.getPreviousSibling())
{
siblings.add(sib);
}
int offset = 0;
for (Node n : siblings)
{
nodeIndexCache.put(n, siblings.size() - index);
offset ++;
}
/*
* vous pouvez améliorer encore davantage la mise en cache
* de l'index en le faisant dans la boucle for ci-dessus.
*/
nodeIndexCache.put(elt, siblings.size()+1);
return count;
}
On dirait que vous avez un nœud aléatoire et vous devez calculer le xpath en remontant le chemin du nœud ? Si ce que vous voulez finalement réaliser est de calculer le xpath de tous les nœuds, le moyen le plus rapide est de commencer avec le nœud racine et de traverser l'arbre, à condition d'avoir une référence au nœud racine.
\=== ANCIEN ===
Vous pouvez essayer d'utiliser une API d'analyse XML basée sur des événements au lieu de DOM. JVM est livré avec un analyseur d'événements appelé SAXParser, vous pouvez commencer par utiliser celui-ci. Il y a aussi StAX que vous pouvez essayer.
L'analyseur XML basé sur des événements émet des "événements" lorsqu'il effectue une traversée en profondeur au lieu de parser XML en DOM en mémoire. Ainsi, l'analyseur basé sur des événements visite chaque élément de votre XML, émet des événements comme "onOpenTag", "onClosedTag" et "onAttribute". En écrivant un gestionnaire d'événements, vous pouvez construire et/ou stocker les chemins des éléments de cette manière :
...
currentPath=new Stack();
onOpenTag(String tagName){
this.currentPath.push("tagName");
if ("Item".equals(tagName)){
cache.store(convertToPathString(currentPath));
}
}
onCloseTag(String tagName){
this.currentPath.pop();
}
L'aspect positif de l'API basée sur des événements est qu'elle est rapide et économise beaucoup de mémoire pour les gros fichiers XML.
L'aspect négatif est que vous devez écrire plus de code pour obtenir les données souhaitées.