I have the following XML from which I am trying to remove the whole node if the status matched DEACTIVATED.

Below is the input.xml

<devicesInfo>
    <deviceID>DEVICE1</deviceID>
    <secondaryDevice>false</secondaryDevice>
    <status>ACTIVE</status>
</devicesInfo>
<devicesInfo>
    <deviceID>DEVICE2</deviceID>
    <secondaryDevice>false</secondaryDevice>
    <status>DEACTIVATED</status>
</devicesInfo>
<devicesInfo>
    <deviceID>DEVICE3</deviceID>
    <secondaryDevice>false</secondaryDevice>
    <status>ACTIVE</status>
</devicesInfo>
<devicesInfo>
    <deviceID>DEVICE4</deviceID>
    <secondaryDevice>false</secondaryDevice>
    <status>ACTIVE</status>
</devicesInfo>

And the desired output to be:

<devicesInfo>
    <deviceID>DEVICE1</deviceID>
    <secondaryDevice>false</secondaryDevice>
    <status>ACTIVE</status>
</devicesInfo>
<devicesInfo>
    <deviceID>DEVICE3</deviceID>
    <secondaryDevice>false</secondaryDevice>
    <status>ACTIVE</status>
</devicesInfo>
<devicesInfo>
    <deviceID>DEVICE4</deviceID>
    <secondaryDevice>false</secondaryDevice>
    <status>ACTIVE</status>
</devicesInfo>

I have already been able to extract the deviceID that match the status DEACTIVATED but struggling in deleting the whole node

void removeDeactivatedDevices() throws SAXException, IOException, ParserConfigurationException {
        String device;
        try {
            File inputFile = new File(input.xml);
            DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
            Document doc = dBuilder.parse(inputFile);

            doc.getDocumentElement().normalize();
            NodeList nList = doc.getElementsByTagName("devicesInfo");

            for (int i = 0; i < nList.getLength(); i++) {
                Node nNode = nList.item(i);

                if (nNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element eElement = (Element) nNode;

                    if (eElement.getElementsByTagName("status").item(0).getTextContent().contentEquals("DEACTIVATED")) {
                        device = eElement.getElementsByTagName("deviceID").item(0).getTextContent();

                        // print out the devices that match this status
                        System.out.println(device);

                                  // HELP Need to delete parent node of that device...
                    }

                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

So, when I run it I get:

DEVICE1
DEVICE3
DEVICE4

What I want is the full XML returned without the DEACTIVATED Status items.

2 Answers

1
Some random IT boy On Best Solutions

Well, it should be easy enough assuming you are using the org.w3c.dom.* library to parse XML documents. Just use Document.removeChild(node)

Here's an example:

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class MainClass {


    public static void main(String[] args) throws Exception {
        File f = new File("input.xml");
        Document XML_DOC = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(f);
        NodeList devices = XML_DOC.getElementsByTagName("devicesInfo");
        printDocument(XML_DOC);


        for (int i = 0; i < devices.getLength(); i++) {
            Node device = devices.item(i);
            if(isDeviceDeactivated(device))
                //remove from .item(0) because we have to remove them from the <devices> node
                XML_DOC.getChildNodes().item(0).removeChild(device);

        }

        System.out.println("");System.out.println("");
        System.out.println("------------------------------------");
        printDocument(XML_DOC);
    }

    public static void printDocument(Document doc) throws IOException, TransformerException {
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");


        transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(System.out, "UTF-8")));
    }

    public static boolean isDeviceDeactivated(Node node) {
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element e = (Element) node;
            if (e.getElementsByTagName("status").item(0).getTextContent().contentEquals("DEACTIVATED"))
                return true;
        }
        return false;
    }

}

The XML document that has been used to test this with: (I had to wrap the device info list with another node)

<?xml version="1.0" encoding="UTF-8"?>
<devices>
    <devicesInfo>
        <deviceID>DEVICE1</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
    <devicesInfo>
        <deviceID>DEVICE2</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>DEACTIVATED</status>
    </devicesInfo>
    <devicesInfo>
        <deviceID>DEVICE3</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
    <devicesInfo>
        <deviceID>DEVICE4</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
</devices>

And that code just outputs:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<devices>
    <devicesInfo>
        <deviceID>DEVICE1</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
    <devicesInfo>
        <deviceID>DEVICE2</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>DEACTIVATED</status>
    </devicesInfo>
    <devicesInfo>
        <deviceID>DEVICE3</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
    <devicesInfo>
        <deviceID>DEVICE4</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
</devices>


------------------------------------
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<devices>
    <devicesInfo>
        <deviceID>DEVICE1</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>

    <devicesInfo>
        <deviceID>DEVICE3</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
    <devicesInfo>
        <deviceID>DEVICE4</deviceID>
        <secondaryDevice>false</secondaryDevice>
        <status>ACTIVE</status>
    </devicesInfo>
</devices>
0
Joe On

I tried the following which also solved it using xPath

void removeDevicesWithDeactivatedStatus() throws SAXException, IOException, ParserConfigurationException, XPathExpressionException,
            TransformerException {

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true); // never forget this!
        Document document = dbf.newDocumentBuilder().parse(new File("input.xml"));

        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();
        XPathExpression expression = xpath.compile("//devices/devicesinf[status/text()='DEACTIVATED']");

        // 1) Get book titles written after 2001
        Object result = expression.evaluate(document, XPathConstants.NODESET);

        NodeList nodes = (NodeList) result;

        int numberOfDeactivatedDevices = 0;
        for (int i = 0; i < nodes.getLength(); i++) {
            numberOfDeactivatedDevices = +i;
            // System.out.println(nodes.item(i).getNodeValue() + " [" + i+"]");
            Node b13Node = (Node) expression.evaluate(document, XPathConstants.NODE);
            b13Node.getParentNode().removeChild(b13Node);

        }

        System.out.println("Deactivated devices removed: " + numberOfDeactivatedDevices);

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        t.transform(new DOMSource(document), new StreamResult(new File("output.xml")));
        //t.transform(new DOMSource(document), new StreamResult(System.out));
}