Reputation: 102
I have an XML file as below:
<CourseList>
<Course>
<CourseName>CoreJava</CourseName>
<Teacher>Bui Duy Linh</Teacher>
<Duration>90 minutes</Duration>
<Student>
<StudentID>C001</StudentID>
<StudentName>Nam</StudentName>
<DateRegister>15/11/2016</DateRegister>
</Student>
<Student>
<StudentID>C002</StudentID>
<StudentName>Vi</StudentName>
<DateRegister>13/11/2016</DateRegister>
</Student>
</Course>
And I want to remove a student with ID C001, but my search function seem to return null
public static Node searchByID(String id, Document doc) {
try {
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
NodeList list = (NodeList) xp.evaluate("CourseList/Course/Student/StudentID", doc, XPathConstants.NODESET);
for (int i = 0; i < list.getLength(); i++) {
String content = list.item(i).getTextContent();
if (content.equalsIgnoreCase(id)) {
Node p = list.item(i).getParentNode();
return p;
}
}
} catch (XPathExpressionException ex) {
Logger.getLogger(AssignmentXML.class.getName()).log(Level.SEVERE, null, ex);
}
return null;
}
Is there a way to fix it? Should I use DOM instead? Appreciate anyone help
Upvotes: 1
Views: 2694
Reputation: 107587
For OP and future readers, consider using XSLT when needing to restructure or re-design an XML document. No looping or if/then logic is needed. XSLT is a native special-purpose language designed for this exact need. Like general purpose languages including C#, Python, Perl, PHP, and VB, Java maintains an XSLT 1.0 processor. Below is a working example for OP's request.
XSLT Script (save as .xsl or .xslt to be used in Java)
<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output version="1.0" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*"/>
<!-- Identity Transform -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- Removes all Student nodes with C001 ID condition -->
<xsl:template match="Student[StudentID='C001']"/>
</xsl:transform>
Java Script
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.*;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.transform.OutputKeys;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
public class CourseList {
public static void main(String[] args) throws IOException, URISyntaxException,
SAXException,
ParserConfigurationException,
TransformerException {
// LOAD XML AND XSL DOCUMENTS
String inputXML = "C:\\Path\\To\\Input.xml";
String xslFile = "C:\\Path\\To\\XSLTScript.xsl";
String outputXML = "C:\\Path\\To\\Output.xml";
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document doc = docBuilder.parse (new File(inputXML));
Source xslt = new StreamSource(new File(xslFile));
// XSLT TRANSFORMATION WITH PRETTY PRINT
TransformerFactory prettyPrint = TransformerFactory.newInstance();
Transformer transformer = prettyPrint.newTransformer(xslt);
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
transformer.setOutputProperty(OutputKeys.STANDALONE, "yes");
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");
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File(outputXML));
transformer.transform(source, result);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<CourseList>
<Course>
<CourseName>CoreJava</CourseName>
<Teacher>Bui Duy Linh</Teacher>
<Duration>90 minutes</Duration>
<Student>
<StudentID>C002</StudentID>
<StudentName>Vi</StudentName>
<DateRegister>13/11/2016</DateRegister>
</Student>
</Course>
</CourseList>
Upvotes: 1
Reputation: 102
Well, turn out nothing wrong with the search but with the remove function. My old code:
Node delNode = searchByID(id, doc);
doc.getDocumentElement().removeChild(delNode);
which only remove the Node in the document, not the Element of the node. I did this to fix:
Node delNode = searchByID(id, doc);
delNode.getParentNode().removeChild(delNode);
Thanks for you guys help anyway :)
Upvotes: 1
Reputation: 159086
You say it returns null, but it doesn't. It returns a Node
object for the <Student>
node with the given ID. If you print the node, you get:
[Student: null]
That is not a null value, but a Node
object, with a toString()
method like this:
public String toString() {
return "["+getNodeName()+": "+getNodeValue()+"]";
}
And according to the Node
javadoc for an Element
node:
nodeName
is "same as Element.tagName"nodeValue
is "null"If you actually transform the node to text using:
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(node), new StreamResult(System.out));
You will get:
<Student>
<StudentID>C001</StudentID>
<StudentName>Nam</StudentName>
<DateRegister>15/11/2016</DateRegister>
</Student>
Upvotes: 0