In the below sample XML, how to remove Entire B Node if E=13 using java parser.
11
Here is the code of removing node B using XPath with predicate. It is based on VTD-XML, which uniquely implements incremental update.
import com.ximpleware.*;
import java.io.*;
public class removeNode {
public static void main(String s[]) throws VTDException, IOException{
VTDGen vg = new VTDGen();
if (!vg.parseFile("input.xml", false));
VTDNav vn = vg.getNav();
AutoPilot ap = new AutoPilot(vn);
XMLModifier xm = new XMLModifier(vn);
ap.selectXPath("/xml/A/B[C/E='13']");
while (ap.evalXPath()!=-1){
xm.remove();
}
xm.output("output.xml");
}
}
Alternative DOM Approach
Alternatively, instead of doing a brute force traversal of the XML document you could use the XPath capabilities in the JDK to find the "B" element with value "13" and then remove it from its parent:
import java.io.File;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import org.w3c.dom.*;
public class Demo {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
Document document = dbf.newDocumentBuilder().parse(new File("input.xml"));
XPathFactory xpf = XPathFactory.newInstance();
XPath xpath = xpf.newXPath();
XPathExpression expression = xpath.compile("//A/B[C/E/text()=13]");
Node b13Node = (Node) expression.evaluate(document, XPathConstants.NODE);
b13Node.getParentNode().removeChild(b13Node);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
t.transform(new DOMSource(document), new StreamResult(System.out));
}
}
The advantage of using an XPath it's easier to maintain, if the structure changes it's just a one line change to your code. Also if the depth of your document grows the XPath based solution stays the same number of lines.
Non-DOM Approach
If you don't want to materialize your XML as a DOM. You could use a Transformer and a stylesheet to remove a node:
It's easy if you are using DOM. Just traverse the document and keep track of the B nodes. When you hit an E=13 node, remove the B node. Here is some code to help:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
Document doc = factory.newDocumentBuilder().parse(new File("file.xml"));
DocumentTraversal traversal = (DocumentTraversal) doc;
Node a = doc.getDocumentElement();
NodeIterator iterator = traversal.createNodeIterator(a, NodeFilter.SHOW_ELEMENT, null, true);
Element b = null;
for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) {
Element e = (Element) n;
if ("B".equals(e.getTagName())) {
b = e;
} else if ("E".equals(e.getTagName()) && "13".equals(e.getTextContent()) && b != null) {
a.removeChild(b);
}
}
I tried this example of file with the Blaise code and I get
Exception in thread "main" java.lang.NullPointerException
at myxml.xmlParty2.main(xmlParty2.java:22)
This is the file
<?xml version="1.0" encoding="UTF-8"?>
<favoris>
<workflow codewf="wf2333">
<information>
<title>wf2333</title>
<desc>desc_title_5</desc>
<nberState>2</nberState>
<text>Impossible de joindre Cliquez sur le lien ci-dessous pour effectuer une nouvelle tentative.</text>
</information>
<states>
<state id="1" IDemployee="2">desc_wf_1_etat_1</state>
<state id="2" IDemployee="3">desc_wf_1_etat_2</state>
</states>
</workflow>
<workflow codewf="wf2334">
<information>
<title>wf2334</title>
<desc>desc_title_5</desc>
<nberState>2</nberState>
<text>Impossible de joindre Cliquez sur le lien ci-dessous pour effectuer une nouvelle tentative.</text>
</information>
<states>
<state id="1" IDemployee="2">desc_wf_1_etat_1</state>
<state id="2" IDemployee="3">desc_wf_1_etat_2</state>
</states>
</workflow>
</favoris>
and the Xptah Query is XPathExpression expression = xpath.compile("/favoris/workflow[@id='wf2333']");