=== Новое - поэтому вам нужно использовать DOM ===
Чтобы ускорить процесс, вы можете сделать кеширование (как предложил другой человек). Обратите внимание, что ваш текущий код вычисляет xpath для одного и того же узла несколько раз (или для каждого узла N вам придется вычислять xpath для N для каждого из дочерних элементов N). Вот что я имею в виду для кэширования:
HashMap<Node, String> xpathCache;
HashMap<Node, Integer> 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;
}
}
/*
* here, not only you know the xpath to the elt, you also
* know the xpath to the ancestors of elt. You can leverage
* this to cache the ancestor's xpath as well. But I just
* cache the elt for illustration purpose.
*
* To compute ancestor's xpath efficiently, maybe you want to
* store xpath using different data structure other than String.
* Maybe a Stack of Strings?
*/
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<Node> siblings = new LinkedList<Node>();
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 ++;
}
/*
* you can improve index caching even further by doing it in the
* above for loop.
*/
nodeIndexCache.put(elt, siblings.size()+1);
return count;
}
Похоже, что вы получили случайный узел, и вам нужно вычислить xpath путем возврата пути узла? Если в конечном итоге вы хотите получить xpath для всех узлов, самый быстрый способ - начать с корневого узла и пройти через дерево, если у вас есть ссылка на корневой узел.
=== СТАРЫЙ ===
Вы можете попробовать использовать API анализа XML на основе событий вместо DOM. JVM поставляется с анализатором событий SAXParser , вы можете начать с него. Существует также StAX , который вы можете попробовать.
Анализатор XML, основанный на событиях, генерирует «события», поскольку он выполняет обход в глубину вместо анализа XML в in-memory-DOM. Таким образом, анализатор на основе событий посещает каждый элемент вашего XML, генерирует такие события, как «onOpenTag», «onClosedTag» и «onAttribute». Написав обработчик событий, вы можете построить и / или сохранить пути к элементам следующим образом:
...
currentPath=new Stack();
onOpenTag(String tagName){
this.currentPath.push("tagName");
if ("Item".equals(tagName)){
cache.store(convertToPathString(currentPath));
}
}
onCloseTag(String tagName){
this.currentPath.pop();
}
Отличительной особенностью API, основанного на событиях, является то, что он быстрый и экономит много памяти для большого XML.
Плохая вещь в том, что вы должны написать код режима, чтобы получить нужные данные.