Problems removing nodes from XML file using java - java

currently I'm required to remove a specific node and its child in an XML file
, however I always encountered null pointer exception whenever I'm trying to remove the nodes. The "position" parameter would be the # of node to remove. e.g position 3 should remove reservation id(04113049)and everything under it.
public void removeReservation(int position){
try{
File file = new File("reservations.xml");
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(file);
Element element = (Element)doc.getElementsByTagName("reservation").item(position);
element.getParentNode().removeChild(element);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("reservations.xml"));
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(source, result);
}
catch(Exception e){
e.printStackTrace();
}
}
Here are the contents of the xml file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<data>
<reservation_list>
<reservation>
<resID>01014664</resID>
<roomNo>0101</roomNo>
<roomType>VIPSuite</roomType>
<noOfGuest>3</noOfGuest>
<bedType>Master</bedType>
<smoking>Y</smoking>
<startDate>121313</startDate>
<endDate>121316</endDate>
<wifi>Y</wifi>
<roomView>Y</roomView>
<availability>Reserved</availability>
<name>Johnny depp</name>
<address>NTU Hall 17 #01-111</address>
<country>Singapore</country>
<gender>Male</gender>
<nationality>Singaporean</nationality>
<contact>92003239</contact>
<creditCardNo>1234567812345678</creditCardNo>
<creditCardCSV>432</creditCardCSV>
<creditCardExpDate>11/16</creditCardExpDate>
<identity>U0000000I</identity>
</reservation>
<reservation>
<resID>11025652</resID>
<roomNo>1102</roomNo>
<roomType>Double</roomType>
<noOfGuest>3</noOfGuest>
<bedType>Master</bedType>
<smoking>Y</smoking>
<startDate>1212</startDate>
<endDate>1213</endDate>
<wifi>Y</wifi>
<roomView>Y</roomView>
<availability>Reserved</availability>
<name>Thomas</name>
<address>Mountbatten #2-12 Garden ave</address>
<country>Singapore</country>
<gender>Male</gender>
<nationality>Singaporean</nationality>
<contact>93482032</contact>
<creditCardNo>1234567812345678</creditCardNo>
<creditCardCSV>588</creditCardCSV>
<creditCardExpDate>3/16</creditCardExpDate>
<identity>U1234567I</identity>
</reservation>
<reservation>
<resID>04113049</resID>
<roomNo>0411</roomNo>
<roomType>VIPSuite</roomType>
<noOfGuest>7</noOfGuest>
<bedType>Master</bedType>
<smoking>Y</smoking>
<startDate>121112</startDate>
<endDate>232333</endDate>
<wifi>Y</wifi>
<roomView>Y</roomView>
<availability>Reserved</availability>
<name>elaine</name>
<address>punggol</address>
<country>Singapore</country>
<gender>Female</gender>
<nationality>Singaporean</nationality>
<contact>12345672</contact>
<creditCardNo>1234123412341234</creditCardNo>
<creditCardCSV>123</creditCardCSV>
<creditCardExpDate>1212</creditCardExpDate>
<identity>S96777777777F</identity>
</reservation>
</reservation_list>
</data>

First, filtering using item() is zero-based ( starts from index 0 ), there is no item(3) in your file.
Second, you should always check that you are able to find a reservation for that position before you are trying to remove it. In your case, I think you're trying to do .getParentNode() on a null element which is why you're seeing the NullPointer.
Element element = (Element)doc.getElementsByTagName("reservation").item(position);
if ( null != element) {
element.getParentNode().removeChild(element);
//etc
}

Related

Extract all the recurring element of XML using java

My XML looks like below and I need to extract multiple ID element in
an output xml:-
<?xml version="1.0" encoding="utf-8"?>
<Stock>
<PIdentification>
<CatalogVersion></CatalogVersion>
<AccountID></AccountID>
<CustomerId></CustomerId>
</ProviderIdentification>
<Product>
<ArticleName>Monitors</ArticleName>
<BaseUnit></BaseUnit>
<Notes></Notes>
<ID>11f13e2e-ae97-45b5-a9a9-23fa7f6bb767</ID>
<ID>b22834c0-a570-4e6b-97c3-5067a14d118d</ID>
<ID>ed458593-5e1a-4dc1-94f0-a66eeef2dd79</ID>
<ID>d25584a9-1db2-48cf-9a70-9b81e5a7e7f2</ID>
</Product>
</Stock>
I have used "Nodelist" to extract "ID" but I am getting just one element
and not all 4, below is the part of the code:-
{
Node IDNode = element.getElementsByTagName("ID").item(0);
IDXml = toStringXml(IDNode , true);
}
I am not able to reiterate for look to get all the IDs, please let me
know how to get all ID, any help is appreciated.
private static String toStringXml(Node elt, boolean xmlDeclaration)
throws TransformerException {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
if(xmlDeclaration)
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DOMSource source = new DOMSource(elt);
StreamResult result = new StreamResult(new StringWriter());
transformer.transform(source, result);
return result.getWriter().toString();
}
You got all id's but you are only looking at first item with .item(id).
Method getElementsByTageName("ID") returns you NodeList so you can got trough all ids for example like that:
File xmlFile = new File("src/main/resources/example.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document element = dBuilder.parse(xmlFile);
NodeList list = element.getElementsByTagName("ID");
for (int i = 0; i < list.getLength(); i++){
Node specificIDNode = list.item(i);
System.out.println(specificIDNode.getTextContent());
}
You have malformed XML displayed in your question. Unclosed <PIdentification> tag on the row 3.
Correct XML code should look like that:
<?xml version="1.0" encoding="utf-8"?>
<Stock>
<ProviderIdentification>
<CatalogVersion></CatalogVersion>
<AccountID></AccountID>
<CustomerId></CustomerId>
</ProviderIdentification>
<Product>
<ArticleName>Monitors</ArticleName>
<BaseUnit></BaseUnit>
<Notes></Notes>
<ID>11f13e2e-ae97-45b5-a9a9-23fa7f6bb767</ID>
<ID>b22834c0-a570-4e6b-97c3-5067a14d118d</ID>
<ID>ed458593-5e1a-4dc1-94f0-a66eeef2dd79</ID>
<ID>d25584a9-1db2-48cf-9a70-9b81e5a7e7f2</ID>
</Product>
</Stock>
And in this case, code, provided by #Penguin74 displays all IDS from your xml (check the picture below).

How to create xml file using Java?

I am creating a xml file using Java Transformer.The root node has syntax like this:
<AUTO-RESPONSE-DOCUMENT xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://someurl">.
I am creating the root node like this:
Document doc = docBuilder.newDocument();
Element ele = doc.createElement("AUTO-RESPONSE-DOCUMENT");
doc.appendChild(ele);
How should i put the above urls in front of AUTO-RESPONSE-DOCUMENT node?
If you mean the namespace attributes: You can set them like all other atributes:
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
Element ele = doc.createElement("AUTO-RESPONSE-DOCUMENT");
//Add namespace attibutes
ele.setAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
ele.setAttribute("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
ele.setAttribute("xmlns", "http://someurl");
doc.appendChild(ele);
Put through this Document-To-Text code
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);
It creates that output:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<AUTO-RESPONSE-DOCUMENT xmlns="http://someurl"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
/**
* #param args
* #throws ParserConfigurationException
*/
public static void main(String[] args) throws Exception {
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = docBuilder.newDocument();
Element ele = doc.createElement("AUTO-RESPONSE-DOCUMENT");
doc.appendChild(ele);
ele.setAttribute("xmlns", "http://someurl");
ele.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
ele.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
TransformerFactory.newInstance().newTransformer().transform(new DOMSource(doc), new StreamResult(System.out));
}
Note the namespace for "xmlns" pefix must be exactly as shown.

Adding element to XML using javax parser without document modification

i am trying to add elements to xml document. Elements are added successfuly but problem is, that parser modifies original xml file in other places e.g it swaps namespace and id attributes or deletes duplicate namespace definitions. I need to get precisely the same document (same syntax, preserved whitespaces) only with specific elements added. I would greatly appreciate any suggestions. Here is my code:
public void appendTimestamp(String timestamp, String signedXMLFile, String timestampedXMLFile){
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
try{
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new File(signedXMLFile));
XPath xPath = XPathFactory.newInstance().newXPath();
NodeList list = (NodeList)xPath.evaluate("//*[local-name()='Signature']/*[local-name()='Object']/*[local-name()='QualifyingProperties']", doc, XPathConstants.NODESET);
if(list.getLength() != 1){
throw new Exception();
}
Node node = list.item(0);
Node unsignedProps = doc.createElement("xades:UnsignedProperties");
Node unsignedSignatureProps = doc.createElement("xzep:UnsignedSignatureProperties");
Node timestampNode = doc.createElement("xzep:SignatureTimeStamp");
timestampNode.appendChild(doc.createTextNode(timestamp));
unsignedSignatureProps.appendChild(timestampNode);
unsignedProps.appendChild(unsignedSignatureProps);
node.appendChild(unsignedProps);
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "no");
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
DOMSource source = new DOMSource(doc);
StringWriter writer = new StringWriter();
StreamResult stringWriter = new StreamResult(writer);
transformer.transform(source, stringWriter);
writer.flush();
System.out.println(writer.toString());
}catch(Exception e){
e.printStackTrace();
}
}
The original xml file:
...
<ds:Object Id="objectIdVerificationObject" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
...
Modified xml file:
...
<ds:Object xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="objectIdVerificationObject">
...
If you use the dom model, then the whole xml file is read, then represented in the memory as the node tree and then saved to xml in a way determined by the writer. So it is almost impossible to preserve the original xml format as you don't have the control over it and for example whitespaces are not represented at all in the node tree.
You need to read partially the original xml and ouptut its content to the new file preserving what was read, then in the "right" place you need to add your new content adn then continue simple coapying of the original.
For example you could use the XMLStreamWriter and XMLStreamReader to achieve that as they offer "the low" level operations.
But probably it would be much easier to just copy the xml as the text line by one till you recognize the insertion point, then create new xml portion and append it as text and continue with copying.

create and write file from XML

I have XML about article
<ARTICLE ID="74">
<ARTICLE_CATEGORY_ID>1</ARTICLE_CATEGORY_ID >
<ARTICLE_NAME>......</ARTICLE_NAME >
<ARTICLE_EXTENSION>pdf</ARTICLE_EXTENSION >
<ARTICLE_BYTE>[B#6d78f375</ARTICLE_BYTE >
<ARTICLE_DATE>2014-10-11 00:00:00.0</ARTICLE_DATE >
<ARTICLE_ACTIVE>1</ARTICLE_ACTIVE>
</MAKALE>
i want to create file ,and write ARTICLE_BYTE but i can't do it ,it seems, byte seems is String i quess so i don't know how can i do this ? Thank you for helping
//EDIT
Sorry i'm very new stackoverflow..
yes this is from a program that i've written.
That's part of code from the program
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
// XML Kok Ismi
Document doc = docBuilder.newDocument();
Element rootElement = doc.createElement("ARTICLES");
doc.appendChild(rootElement);
for (Nesne nesne : userList) {
// ARTICLE ELEMENT
Element ARTICLE_ID= doc.createElement("ARTICLE ");
rootElement.appendChild(ARTICLE_ID);
//ID
Attr attr = doc.createAttribute("ID");
attr.setValue(String.valueOf(nesne.getArticleID()));
MAKALE_ID.setAttributeNode(attr);
//ARTICLE_CATEGORY_ID
Element ARTICLE_CATEGORY_ID= doc.createElement("ARTICLE_CATEGORY_ID");
ARTICLE_CATEGORY_ID.appendChild(doc.createTextNode(String.valueOf(nesne.getARTICLE_CATEGORY_ID())));
ARTICLE_ID.appendChild(ARTICLE_CATEGORY_ID);
//[ARTICLE_NAME]
Element ARTICLE_NAME= doc.createElement("ARTICLE_NAME");
ARTICLE_NAME.appendChild(doc.createTextNode(nesne.getARTICLE_NAME()));
ARTICLE_ID.appendChild(ARTICLE_NAME);
//[ARTICLE_EXTENSION]
Element ARTICLE_EXTENSION= doc.createElement("ARTICLE_EXTENSION");
ARTICLE_EXTENSION.appendChild(doc.createTextNode(nesne.getARTICLE_EXTENSION()));
ARTICLE_ID.appendChild(ARTICLE_EXTENSION);
//[ARTICLE_BYTE]
Element ARTICLE_BYTE= doc.createElement("ARTICLE_BYTE");
ARTICLE_BYTE.appendChild(doc.createTextNode(nesne.getARTICLE_BYTE().toString()));
ARTICLE_ID.appendChild(ARTICLE_BYTE);
//[ARTICLE_DATE]
Element ARTICLE_DATE = doc.createElement("ARTICLE_DATE");
ARTICLE_DATE.appendChild(doc.createTextNode(nesne.getARTICLE_DATE()));
ARTICLE_ID.appendChild(ARTICLE_DATE);
//[ARTICLE_ACTIVE]
Element ARTICLE_ACTIVE= doc.createElement("ARTICLE_ACTIVE");
ARTICLE_ACTIVE.appendChild(doc.createTextNode(String.valueOf(nesne.getArticleActive())));
ARTICLE_ID.appendChild(ARTICLE_ACTIVE);
}
// write the content into xml file
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(new File("dosyalar.xml"));
// Output to console for testing
// StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
System.out.println("File saved!");
Your problem appears to be here:
nesne.getARTICLE_BYTE().toString()
I'm not familiar with your Nesne class, but I can tell that the method, getARTICLE_BYTE() returns a byte array, that calling toString() on it will return the useless information that you're currently seeing, and that if this needs to be stored, then you somehow need to store the entire array. Using a for loop and storing the array as the String representations of each byte would not be the most efficient thing to do and would lead to a super-large unreadable XML, so perhaps you could store it off of the XML and pass a reference to the byte array file in the XML. Or store in a database as a BLOB. Note that this is not something I do much of, and so I'm no expert.

Converting string to XMLDocument doesn't create text nodes

here's my situation.
I have a string containing XML data:
<tag>
<anotherTag> data </anotherTag>
</tag>
I take that string and I run it through this code to convert it to a Document:
try {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new InputSource(new StringReader(sXMLString)));
}
catch (Exception e) {
// Parser with specified options can't be built
ceLogger.logError("Unable to build a new XML Document from string provided:\t" + e.getMessage());
return null;
}
The resulting xml is almost perfect. Its missing the data however and looks like this:
<tag>
<anotherTag />
</tag>
How can I copy over the text when creating an XML Document and why is it removing the text in the first place?
Edit:
The actual problem ended up being something along the lines of this:
While parsing through the XML structure with my own function this line is there:
if (curChild.getNodeType()==Node.ELEMENT_NODE)
sResult.append(XMLToString((Element)children.item(i),attribute_mask));
But no such logic exists for TEXT nodes, so they are simply ignored.
Your code is correct. The only guess I can make is that you are outputting your code incorrectly. I've tested your code, and used the following method to output, and the XML was displayed correctly with the text node:
public static void outputXML(Document dom) throws TransformerException
{
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
//initialize StreamResult with File object to save to file
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(dom);
transformer.transform(source, result);
String xmlString = result.getWriter().toString();
System.out.println(xmlString);
}
The output was:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<tag> <anotherTag> data </anotherTag>
</tag>

Categories

Resources