Remove empty nodes from a XML recursively

Dheeraj Joshi picture Dheeraj Joshi · Sep 21, 2012 · Viewed 18.3k times · Source

I want to delete the empty nodes from an XML element. This xml is generated from a vendor and i dont have control on xml generation. But since the XML has few empty nodes i need to delete those empty nodes recursively.

This xml is got from OMElement and i get an Element from this object using [XMLUtils][1] Sample XML

<A>
  <B>
    <C>
      <C1>
        <C11>something</C11>
        <C12>something</C12>
      </C1>
    </C>
    <D>
      <D1>
        <D11>
          <D111 operation="create">
            <Node>something else</Node>
          </D11>
        </D11>
      </D1>
      <D2>
        <D21>

        </D21>
      </D2>
    </D>
  </B>
</A> 

Since D21 is an empty node i want to delete D21 and since now D2 is an empty node i want to delete D2 but since D has D1 i dont want to delete D.

Similarly it is possible that i can get

<A>
  <B>
    <C>

    </C>
  </B>
</A>

Now since C is empty i want to delete C and then B and then eventually node A. I am trying to do this using removeChild() method in Node

But so far i am unable to remove them recursively. Any suggestions to remove them recursively?

I am recursively trying to get node and node length. But node length is of no help

if(childNode.getChildNodes().getLength() == 0 ){
       childNode.getParentNode().removeChild(childNode);

               }

Regards
Dheeraj Joshi

Answer

fazed picture fazed · Nov 10, 2014

I don't have enough rep to comment on @Adam's solution, but I was having an issue where after a node removal, the last sibling of that node was moved to index zero, causing it to not fully remove empty elements. The fix was to use a list to hold all of the nodes we want to recursively call for removal.

Also, there was a bug that removed empty elements that had attributes.

Solution to both issues:

public static void removeEmptyNodes(Node node) {

    NodeList list = node.getChildNodes();
    List<Node> nodesToRecursivelyCall = new LinkedList();

    for (int i = 0; i < list.getLength(); i++) {
        nodesToRecursivelyCall.add(list.item(i));
    }

    for(Node tempNode : nodesToRecursivelyCall) {
        removeEmptyNodes(tempNode);
    }

    boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE 
          && node.getChildNodes().getLength() == 0;
    boolean emptyText = node.getNodeType() == Node.TEXT_NODE 
          && node.getNodeValue().trim().isEmpty();

    if (emptyElement || emptyText) {
        if(!node.hasAttributes()) {
            node.getParentNode().removeChild(node);
        }
    }

}