user3768377
user3768377

Reputation: 45

Find the number of XML nodes at same level or above

I want to find the number of nodes that are in the same level as the node with @title="d" or are in the higher level

XML:

<item title="a">
       <item title="b">               
           <item title="c"></item>
           <item title="d">  
               <item title="e"></item>  
               <item title="f"></item>
           </item>                 
       </item> 
       <item title="x">             
           <item title="y"></item> 
           <item title="z"></item>  
       </item>            
</item> 
L0 . . . . . .  a . . . .
              /   \
L1 . . . . . b . . x .  .
           /  \   / \
L2 . . . .c . d .y . z  .
             / \
L3 . . . . .e . f . . . .

Some examples:

System.out.println(leftDomainSize("d")); // 7
System.out.println(leftDomainSize("x")); // 3
System.out.println(leftDomainSize("e")); // 9

Code:

public int leftDomainSize(String s){
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
        Document document = documentBuilder.parse(path);
        //????
}

Upvotes: 3

Views: 811

Answers (3)

kjhughes
kjhughes

Reputation: 111591

Pure XPath solution:

You can count the number of items whose ancestor count is less than or equal to the ancestor count of the given item. So, for the item with a title equal to 'd':

count(//item[count(//item[@title='d']/ancestor::item) >= count(ancestor::item)])

7

Works with your other examples too:

count(//item[count(//item[@title='x']/ancestor::item) >= count(ancestor::item)])

3

and:

count(//item[count(//item[@title='e']/ancestor::item) >= count(ancestor::item)])

9

Upvotes: 1

faljbour
faljbour

Reputation: 1377

Try this function, it should work by looking in reverse at the parent nodes and their children nodes,

public int findNodes(Node node)
{
  int count = 0;
  Node parent = null;
  do
  {
    parent = node.getParentNode();
    if(parent==null)break;
    NodeList list = parent.getChildNodes();
    count += list.getLength();
    node = parent;
  }
  while(parent != null);
  return count;
}

Upvotes: 0

Balint Domokos
Balint Domokos

Reputation: 1021

You can use Breadth First Search, like this:

public int leftDomainSize(String s) throws Exception{
    class Pair {
        Element elem;
        int depth;

        public Pair(Element elem, int depth) {
            this.elem = elem;
            this.depth = depth;
        }
    }

    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

    Document document = documentBuilder.parse(path);
    Element root = document.getDocumentElement();

    // Breadth First Search
    LinkedList<Pair> queue = new LinkedList<Pair>();
    int depth = Integer.MAX_VALUE;
    queue.add(new Pair(root, 1));
    int result = 0;
    while(!queue.isEmpty()) {
        Pair curr = queue.remove();
        if(curr.depth > depth) {
            continue;
        }
        result++;
        if (curr.elem.getAttribute("title").equals(s)) {
            depth = curr.depth;
        }
        NodeList children = curr.elem.getChildNodes();
        for(int i = 0; i<children.getLength(); i++) {
            Node child = children.item(i);
            if(child instanceof Element) {
                queue.add(new Pair((Element)child, curr.depth + 1));
            }
        }
    }
    return result;
}

Upvotes: 0

Related Questions