Java XML Transformer Only Outputs XML Header - java

I'm working on a bit of a project for my own amusement that involves outputting the contents of several variables to an XML file. However, when I put the program, the transformer only outputs the first line (the XML header) and nothing else. The saveData() method is called before writeFile(), and I've outputted the value of the variables to the console before calling writeFile() so I know they have a value.
Code below:
public class Output {
private static double citySizeMiles;
private static double citySizeAcres;
private CityType type;
private static int gpLimit;
private static long totalWealth;
private static long cityPopulation;
public static void saveData() {
cityPopulation = CityGenerator.cityPop;
citySizeMiles = City.getCitySizeMiles(cityPopulation);
citySizeAcres = City.getCitySizeAcres(cityPopulation);
gpLimit = City.getGoldLimit();
totalWealth = CityGenerator.cityWealth;
}
public static void writefile() {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = docFactory.newDocumentBuilder();
// Root Elements
Document doc = builder.newDocument();
Element root = doc.createElement("data");
// Data Element
Element data = doc.createElement("City");
root.appendChild(data);
Attr attr = doc.createAttribute("name");
attr.setValue("Test");
data.setAttributeNode(attr);
// City size (sq miles)
Element sizeMi = doc.createElement("sizeMiles");
sizeMi.appendChild(doc.createTextNode(String.valueOf(citySizeMiles)));
data.appendChild(sizeMi);
// City size (acres)
Element sizeAc = doc.createElement("sizeAcres");
sizeAc.appendChild(doc.createTextNode(String.valueOf(citySizeAcres)));
data.appendChild(sizeAc);
// Population
Element pop = doc.createElement("population");
pop.appendChild(doc.createTextNode(String.valueOf(cityPopulation)));
data.appendChild(pop);
// GP limit
Element gpLim = doc.createElement("gpLimit");
gpLim.appendChild(doc.createTextNode(String.valueOf(gpLimit)));
data.appendChild(gpLim);
// Total fluid wealth
Element wealth = doc.createElement("totalWealth");
wealth.appendChild(doc.createTextNode(String.valueOf(totalWealth)));
data.appendChild(wealth);
// Write to XML file
TransformerFactory tf = TransformerFactory.newInstance();
tf.setAttribute("indent-number", 4);
Transformer trans = tf.newTransformer();
trans.setOutputProperty(OutputKeys.INDENT, "yes");
trans.setOutputProperty(OutputKeys.METHOD, "xml");
DOMSource source = new DOMSource(doc);
//StreamResult result = new StreamResult(new File("D:\\test.xml"));
StreamResult result = new StreamResult(System.out);
trans.transform(source, result);
} catch(ParserConfigurationException pce) {
pce.printStackTrace();
} catch(TransformerException tfe) {
tfe.printStackTrace();
}
}
}

I'm no expert on DOM (I avoid it like the plague, and encourage everyone else to do likewise) but I think you have failed to connect the root element to the document node.

Related

My XML is not exporting elements. Why?

I've been working on a tool to convert data into the Collada .DAE format, which is XML based. Unfortunately, one thing has been stopping me: My exported XML doesn't have any of my elements!
Here's the code. I've made it easy-to-read so that you don't have to go through as much of the trouble of reading it.
public class DAEExport {
private static boolean alreadyConstructed = false;
private static Document doc = null;
private static Element root = null;
private static Element lib_images_base_element = null;
private static Element lib_geometry_base_element = null;
private static Element lib_control_base_element = null;
private static Element lib_visual_scene_base_element = null;
public static void AppendData() {
//Normally this method would have the data to append as its args, but I'm not worried about that right now.
//Furthermore, ASSUME THIS RUNS ONLY ONCE (It runs once in the test code I'm using to run this method)! I know that it won't work if called multiple times, as the below variables for the document builder and such wouldn't exist the second time around
try {
if (!alreadyConstructed) {
alreadyConstructed = true;
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document document = docBuilder.newDocument();
Element rootElement = document.createElement("SomeGenericElement");
rootElement.appendChild(document.createTextNode("Generic test contents");
document.appendChild(rootElement);
doc = document;
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void Build(File _out) {
try {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(doc);
StreamResult result = new StreamResult(System.out);
transformer.transform(source, result);
alreadyConstructed = false;
doc = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
Ok so here's my problem: Despite adding those elements to the document by calling AppendData(), then calling Build() to print the data, I only get the following data:
<?xml version="1.0" encoding="UTF-8"?> - No elements. Just the basic header. This is it.
I don't know if it's because of some silly mistake that I've been oblivious to for the past amount of time, or something else. Any answers as to why my elements disappeared?
Currently, your doc object is not being passed from AppendData() method to Build() method. All Build() uses is an empty doc from declaration: doc = null. Hence, your outcome is empty of nodes (TransformFactory adds the XML header).
Consider returning the doc object from AppendData() to be available at class level for other method (do note you change the void to returned object type). You then redefine doc and pass it into Build():
public static Document AppendData() {
...
doc = document
return(doc)
}
Alternatively, call Build() inside AppendData, passing doc as a parameter:
public static void AppendData() {
...
doc = document
Build(doc, outfile)
}
public static void Build(Document doc, File _out) {
...
}

After making changes in XML file, old data is loading in Java application

I am making some changes to an embedded XML file in my Java application. I have some fields, a LOAD button and a SAVE button. After clicking the save button I can see the XML file updating, but after clicking the load button the old values are being loaded to the fields.
Here is my code:
public class MyLoad_SaveSampleProject {
public String field1 = "";
public String field2 = "";
public void loadSampleProject() {
InputStream file = MyLoad_SaveSampleProject.class.getResourceAsStream("/main/resources/otherClasses/projects/SampleProject.xml");
try {
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
Document Doc = DocBuilder.parse(file);
NodeList list = Doc.getElementsByTagName("*"); //create a list with the elements of the xml file
for (int i=0; i<list.getLength(); i++) {
Element element = (Element)list.item(i);
if (element.getNodeName().equals("field1")) {
field1 = element.getChildNodes().item(0).getNodeValue().toString();
} else if (element.getNodeName().equals("field2")) {
field2 = element.getChildNodes().item(0).getNodeValue().toString();
}
}
} catch (Exception e) {
System.out.println(e);
}
}
public void saveSampleProject(String field1Str, String field2Str) {
InputStream file = MyLoad_SaveSampleProject.class.getResourceAsStream("/main/resources/otherClasses/projects/SampleProject.xml");
try {
DocumentBuilderFactory DocBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder DocBuilder = DocBuilderFactory.newDocumentBuilder();
Document Doc = DocBuilder.parse(file);
NodeList list = Doc.getElementsByTagName("*"); //create a list with the elements of the xml file
for (int i=0; i<list.getLength(); i++) {
Node thisAttribute = list.item(i);
if (thisAttribute.getNodeName().equals("field1")) {
thisAttribute.setTextContent(field1Str);
} else if (thisAttribute.getNodeName().equals("field2")) {
thisAttribute.setTextContent(field2Str);
}
}
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(Doc);
StreamResult result = new StreamResult(new File("src/main/resources/otherClasses/projects/SampleProject.xml"));
transformer.transform(source, result);
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (SAXException sae) {
sae.printStackTrace();
}
}
public String returnField1() {
return field1;
}
public String returnField2() {
return field2;
}
}
And this is my default XML file:
<?xml version="1.0" encoding="UTF-8" standalone="no"?><Strings>
<field1>string1</field1>
<field2>string2</field2>
</Strings>
When the save button is pressed I am using the saveSampleProject method. When the load button is pressed I am using the loadSampleProject method and then I am getting the field values with the returnField1 and returnField2 methods.
I have no idea of what could be wrong with what I'm doing. I would appreciate any suggestions.
Most probably that calling method getResourceAsStream() leads to resource caching. Since you are using File() in save method try to get InputStream on data load using File object, and not as resource.

How to Print String object Line by Line

I have the following code to convert text file to xml.:-
**
public static void main (String args[]) {
new ToXML().doit();
}
public void doit () {
try{
in = new BufferedReader(new FileReader("D:/sample.txt"));
out = new StreamResult("D:/data.xml");
initXML();
String str;
while ((str = in.readLine()) != null)
{
process(str);
}
in.close();
writeXML();
}
catch (Exception e) { e.printStackTrace(); }
}
public void initXML() throws ParserConfigurationException{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
DOMImplementation impl = builder.getDOMImplementation();
xmldoc = impl.createDocument(null, "AIRLINE_INFO", null);
root = xmldoc.getDocumentElement();
}
public void process(String s) {
String elements = s;
Element e1 = xmldoc.createElement("Supplier_Name");
Node n1 = xmldoc.createTextNode(elements);
e1.appendChild(n1);
Element e2 = xmldoc.createElement("E-Mail_Address");
Node n2 = xmldoc.createTextNode(elements);
e2.appendChild(n2);
e0.appendChild(e1);
e0.appendChild(e2);
root.appendChild(e0);
}
public void writeXML() throws TransformerConfigurationException,
TransformerException {
DOMSource domSource = new DOMSource(xmldoc);
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING,"ISO-8859-1");
transformer.setOutputProperty
("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.transform(domSource, out);
}
}
**
The output which is Expected is:
**
<AIRLINE_INFO>
<AIRTICKET>
<Supplier_Name>SpiceJet Ltd, 319, Udyog Vihar, Phase IV, Gurgaon - 122016 Haryana, India</Supplier_Name>
<E-Mail_Address>E-Mail: custrelations#spicejet.com</E-Mail_Address>
</AIRTICKET>
</AIRLINE_INFO>
**
But Currently While Excuting the code i am getting the following output
**
<AIRLINE_INFO>
<AIRTICKET>
<Supplier_Name>SpiceJet Ltd, 319, Udyog Vihar, Phase IV, Gurgaon - 122016 Haryana, India</Supplier_Name>
<E-Mail_Address>SpiceJet Ltd, 319, Udyog Vihar, Phase IV, Gurgaon - 122016 Haryana, India</E-Mail_Address>
</AIRTICKET>
<AIRTICKET>
<Supplier_Name>E-Mail: custrelations#spicejet.com</Supplier_Name>
<E-Mail_Address>E-Mail: custrelations#spicejet.com</E-Mail_Address>
</AIRTICKET>
</AIRLINE_INFO>
**
Please help how can i break the object in order to achieve the Expected output.
You use two times the same string for the text nodes here:
String elements = s;
Element e1 = xmldoc.createElement("Supplier_Name");
Node n1 = xmldoc.createTextNode(elements);
e1.appendChild(n1);
Element e2 = xmldoc.createElement("E-Mail_Address");
Node n2 = xmldoc.createTextNode(elements);
e2.appendChild(n2);
To fix that, you need to read two lines, and then create one air ticket node with that information.

doc.createElement() forgot the opening "<"

I was working on a Java Application and I have to map lots of data then generate an XML output.
All the output Looks good, except this 1 random element. As you can see in the image below all the "Value" tags look good, except the 1 highlighted.
http://i.stack.imgur.com/3TgIG.png
Code used to generate XML:
private void generateXML() {
try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
doc = docBuilder.newDocument();
//Add Root Element
Element rootElement = doc.createElement("Request");
rootElement.setAttribute("request_id", requestID);
doc.appendChild(rootElement);
//Add Experiment Element
Element experimentElement = doc.createElement("Experiment");
experimentElement.setAttribute("name", mappedData.getFileName()); //Change to experiment name
experimentElement.setAttribute("insert_method", "Insert");
experimentElement.setAttribute("notebook", "BioELN");
experimentElement.setAttribute("researcher", webFormPostData.get("Researchers")[0]);
experimentElement.setAttribute("project", getExcelTypeData.get("project"));
experimentElement.setAttribute("comments", webFormPostData.get("comments")[0]);
experimentElement.setAttribute("expt_date", getCurrentDate());
experimentElement.setAttribute("protocol_name", getExcelTypeData.get("protocolName"));
experimentElement.setAttribute("protocol_version", getExcelTypeData.get("protocolVersion"));
rootElement.appendChild(experimentElement);
//Add Data to Experiment
List<Element> experimentDataElements = generateExperimentDataElements();
for(Element dataElement : experimentDataElements) {
experimentElement.appendChild(dataElement);
}
Element attachmentElement = doc.createElement("Attachment");
attachmentElement.setAttribute("filename", mappedData.getFilePath());
experimentElement.appendChild(attachmentElement);
} catch(Exception e) {
logger.log("Error: " + e);
e.printStackTrace();
}
}
private List<Element> generateExperimentDataElements() {
//Loop through output_mapping mapped data and see if values are found in the mappedData.getMappedData();
List<Element> dataElements = new ArrayList<Element>();
for(int i=0; i < mappedData.getMappedData().size(); i++) { //Cycle Through all Mapped Data Rows
for(Map.Entry<String, Map<String, String>> entry : outputMappedFields.entrySet()) { //Get Required Fields
Element itemElement, valueElement, dataElement;
String mappedVarName = entry.getKey();
String vName = entry.getValue().get("variableName");
String variableType = entry.getValue().get("variableType");
itemElement = doc.createElement("VGItem");
itemElement.setAttribute("row_id", String.valueOf(i+1));
itemElement.setAttribute("table_name", "Results");
itemElement.setAttribute("variable_name", vName);
itemElement.setAttribute("parent_table_name", "Plate");
itemElement.setAttribute("parent_row_id", "plate");
valueElement = doc.createElement("Value");
dataElement = doc.createElement(variableType+"_value");
if(mappedData.getMappedData().get(i).containsKey(mappedVarName)) {
dataElement.setTextContent(mappedData.getMappedData().get(i).get(mappedVarName)); //Get field from Mapped Data
}
valueElement.appendChild(dataElement);
itemElement.appendChild(valueElement);
dataElements.add(itemElement);
}
}
return dataElements;
}
#Override
public String toString() {
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer transformer = tf.newTransformer();
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(writer));
String output = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + writer.getBuffer().toString().replaceAll("\n|\r", "");
return output;
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
XML FILE: http://paste.strictfp.com/38339

How to append to xml table with java?

Okay so I'm creating a users class which asks for input then stores it in an XML file using java. I figured out to create the original XML file I think but I'm have trouble figuring out how to add a new user with the attribute "id" of one more then the previous User entry.
Here is the code I have so far:
/*imports */
public class CreateUser {
static Scanner input = new Scanner(System.in);
/* object names*/
String name;
String age;
String bday;
String gender;
String location;
String orientation;
String relationship;
String hobbies;
String choice;
String username;
String password;
public void makeUser(){
/*left out code to get user entries here
seemed irrelevant/*
/*checks for file if it doesn't exist then it creates it else it should append
the user to the xml document with a id increase of one.
The appending part I'm not sure how to do.*/
File f = new File("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml");
if(f.exists()) {
try {
/* need help here*/
}
}
else{
try{
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
Document users = docBuilder.newDocument();
Element user = users.createElement("user");
users.appendChild(user);
Attr attr = users.createAttribute("id");
attr.setValue("0");
user.setAttributeNode(attr);
Element dname = users.createElement("name");
dname.appendChild(users.createTextNode(name));
user.appendChild(dname);
Element dgender = users.createElement("gender");
dgender.appendChild(users.createTextNode(gender));
user.appendChild(dgender);
Element dlocation = users.createElement("location");
dlocation.appendChild(users.createTextNode(location);
user.appendChild(dlocation);
Element dorientation = users.createElement("orientation");
dorientation.appendChild(users.createTextNode(orientation));
user.appendChild(dorientation);
Element drelationship = users.createElement("relationship");
drelationship.appendChild(users.createTextNode(relationship));
drelationship.appendChild(drelationship);
Element dhobbies = users.createElement("hobbies");
dhobbies.appendChild(users.createTextNode(hobbies));
dhobbies.appendChild(dhobbies);
Element dchoice = users.createElement("choice");
dchoice.appendChild(users.createTextNode(choice));
dchoice.appendChild(dchoice);
Element dusername = users.createElement("username");
dusername.appendChild(users.createTextNode(username));
dusername.appendChild(dusername);
Element dpassword = users.createElement("password");
dpassword.appendChild(users.createTextNode(password));
dpassword.appendChild(dpassword);
Element dbday = users.createElement("birthday");
dbday.appendChild(users.createTextNode(bday));
dbday.appendChild(dbday);
Element dage = users.createElement("age");
dage.appendChild(users.createTextNode(age));
dage.appendChild(dage);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
DOMSource source = new DOMSource(users);
StreamResult result = new StreamResult(new File("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml"));
StreamResult test = new StreamResult(System.out);
transformer.transform(source, result);
} catch (ParserConfigurationException pce) {
pce.printStackTrace();
} catch (TransformerException tfe) {
tfe.printStackTrace();
}
}
}
I know its a lot of code to look through and I don't want an exact coded answer but maybe just how to append the user with the attribute value one more then the previous entry. Or a point in a the direction of a helpful website. Anything really I've been perplexed for a little and I feel like I should get something this simple. Thanks in advance for any help
In your first section(if block), I think you can open your file in append mode as below to add an user, assuming user node is not wrapped in another node.
StreamResult result = new StreamResult(
new FileWriter("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml", true));
There are two changes in above statement:
Using FileWriter in place of File
Using a second parameter true, which open the file in append mode.
EDIT: To get the max existing ID, you need to read file and look for ID tag as below:
File xmlFile = new File("C:\\Users\\Steven\\Workspace\\twitter\\src\\users.xml");
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(xmlFile);
doc.getDocumentElement().normalize();
NodeList nList = doc.getElementsByTagName("userId");//use the id tag name
int maxId = 0;
for(Node node: nList){
if(Integer.parseInt(node.getTextContent()) > maxId ){
maxId = Integer.parseInt(node.getTextContent());
}
}
int newId = maxId +1; //use this ID
xmlFile.close();//close the file
Consider JAXB, here is a working example to start with:
static class Users {
private List<User> user = new ArrayList<>();
public List<User> getUsers() {
return user;
}
public void setUsers(List<User> users) {
this.user = users;
}
}
static class User {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static void main(String[] args) throws Exception {
User user = new User();
user.setName("user1");
Users users = new Users();
users.setUsers(Arrays.asList(user));
JAXB.marshal(users, new File("users.xml"));
users = JAXB.unmarshal(new File("users.xml"), Users.class);
User user2 = new User();
user2.setName("user2");
users.getUsers().add(user2);
JAXB.marshal(users, System.out);
}
Consider SAX, unlike DOM it's fast and has no size limit. Here's a basic example:
public static void main(String[] args) throws Exception {
String xml = "<users><user><name>user1</name></user></users>";
XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) {
#Override
public void endElement(String uri, String localName, String qName) throws SAXException {
if (qName.equals("users")) {
addUser();
}
super.endElement(uri, localName, qName);
}
private void addUser() throws SAXException {
super.startElement("", "", "user", null);
addFileld("name", "user2");
super.endElement("", "", "user");
}
private void addFileld(String name, String value) throws SAXException {
super.startElement("", "", name, null);
super.characters(value.toCharArray(), 0, value.length());
super.endElement("", "", name);
}
};
Source src = new SAXSource(xr, new InputSource(new StringReader(xml)));
Result res = new StreamResult(System.out);
TransformerFactory.newInstance().newTransformer().transform(src, res);
}
output:
<users><user><name>user1</name></user><user><name>user2</name></user></users>

Categories

Resources