Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java: get xpath of element in org.w3c.dom document

Tags:

java

dom

I've written what I want to achieve. however, getElementIdx() function doesn't return proper count. There's an issue with getPreviousSibling() but I don't know why.

public static String getElementXpath(DOMElement elt){
        String path = ""; 

        try{
            for (; elt != null; elt = (DOMElement) elt.getParentNode()){
                int idx = getElementIdx(elt);
                String xname = elt.getTagName().toString();

                if (idx >= 1) xname += "[" + idx + "]";
                path = "/" + xname + path;  
            }
        }catch(Exception ee){
        }
        return path;                            
    }

    public static int getElementIdx(DOMElement elt) {
      int count = 1;
      try{

         for (DOMElement sib = (DOMElement) elt.getNextSibling(); sib != null; sib = (DOMElement) sib.getNextSibling())
            {
                if(sib.getTagName().equals(elt.getTagName())){
                    count++;
                }
            }
      }catch(Exception ee){      
      }
        return count;
    }
like image 645
KJW Avatar asked Mar 11 '11 05:03

KJW


2 Answers

Your title talks about getPreviousSibling(), but your code only uses getNextSibling() - why? I can't see why you'd want to use getNextSibling() at all... you want to find out how many elements of the same name come before the current one, not how many come after it.

The fact that you're catching and swallowing exceptions is also deeply suspicious... why would you want to do that? If you have an exception, shouldn't the method terminate with an exception?

You should also probably take account of the fact that getPreviousSibling may not return an element - it may return a text node, for example. You'll want to skip over those - currently you'd get an exception, which would terminate the loop and return the current count.

If these don't help, please post some sample XML, point out a node, and say what the code is currently returning (as well as posting your updated code). Just saying it doesn't return the proper count isn't nearly as useful as saying what it does return, and what you expected it to return.

EDIT: This is what I'd expect the code to look like:

public static int getElementIndex(Element original) {
  int count = 1;

  for (Node node = original.getPreviousSibling(); node != null;
       node = node.getPreviousSibling()) {
    if (node instanceof Element) {
      Element element = (Element) node;
      if (element.getTagName().equals(original.getTagName()) {
        count++;
      }
    }
  }

  return count;
}

You could also use if (node.getNodeType() == Node.ELEMENT_NODE) instead of the instanceof test.

like image 92
Jon Skeet Avatar answered Sep 23 '22 14:09

Jon Skeet


Dom4j xpath support is really good, you can access any element by providing the xpath expression.
However I'm not sure whether the reverse is true, i.e. whether given an element you can derive the xpath expression.

See the api at http://www.docjar.com/projects/dom4j-1.6.1-code.html

Note avoid www.dom4j.org, it appears to have been hi-jacked by some kind of spammy link farm.

like image 27
crowne Avatar answered Sep 21 '22 14:09

crowne