Laodao
Laodao

Reputation: 1689

Java XML update issue - appendchild() not sucessfully append element

I have an issue when I append a new node to xml dom. The following code is the dom saving code in xmlFactory.java.

import java.io.File;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;

import com.ism.msgmgt.domain.Post;
import com.ism.msgmgt.domain.User;


public class XmlFactory {

    private static Document userdom;
    private static Document postdom;

    private static File userfile = new File(User.class.getResource("User.xml").getPath());

    static {

        try{
            DocumentBuilderFactory dbuf = DocumentBuilderFactory.newInstance();
            DocumentBuilder dbu = dbuf.newDocumentBuilder();
            userdom = dbu.parse(userfile);
            DocumentBuilderFactory dbpf = DocumentBuilderFactory.newInstance();
            DocumentBuilder dbp = dbpf.newDocumentBuilder();
            postdom = dbp.parse(postfile);
        } catch (Exception e){
            e.printStackTrace();
        }
    }

    public static Document getUserDom(){
        return userdom;
    }

    public static void saveUserDom(){
        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer trans = tf.newTransformer();
            System.out.println(userdom.getFirstChild()+"|"+userdom.getFirstChild().getFirstChild());
            DOMSource ds = new DOMSource(userdom);
            StreamResult sr = new StreamResult(userfile);
            trans.transform(ds, sr);
        } catch (Exception e){
            throw new RuntimeException(e.getMessage(),e);
        }
    }


}

Note that the printed output is [users: null]|[#text: ]. Next, it is the code in the UserDao.java.

public class UserDao {

    public static Element currentUser = null;
    public static Document userdom = XmlFactory.getUserDom();

    public static void reg(User u){
        clrLogin();
        u.setUserid(UidUtil.getUid());
        u.setPassword(PwdUtil.encode(u.getPassword()));
        Element e = userdom.createElement("user");

        e.setAttribute("id", u.getUserid());
        e.setAttribute("username", u.getUsername());
        e.setAttribute("password", u.getPassword());
        e.setAttribute("login", u.getLogin());

        userdom.getFirstChild().appendChild(e);
        System.out.println(e);
        System.out.println(userdom.getFirstChild()+"|"+userdom.getFirstChild().getFirstChild());
        XmlFactory.saveUserDom();
        currentUser = e;
    }
}

Note that in this code, I printed the node I want to add, which is [user: null]. Next, I printed the expecting added node. However, I got the result [users: null]|[#text: ], which is the same as the output printed from above code. So it looks like appendChild() didn't add e to the dom's first node. Please help. Thanks.

XML File

<?xml version="1.0" encoding="UTF-8"?>
<users>

</users>

Upvotes: 0

Views: 1342

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347214

There's too much context missing from your question, for one, we don't know how the userdom is actually created...

Let me demonstrate, with the following code...

import java.io.ByteArrayOutputStream;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class Test1 {

    public static Document userdom;

    public static void main(String[] args) {
        try {
            userdom = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            Element root = userdom.createElement("users");
            Node adoptNode = userdom.adoptNode(root);
            userdom.appendChild(adoptNode);

            reg();
        } catch (ParserConfigurationException | DOMException exp) {
            exp.printStackTrace();
        }
    }

    public static void reg() {
        Element e = userdom.createElement("user");

        e.setAttribute("id", "blah");
        e.setAttribute("username", "kermit");
        e.setAttribute("password", "bunnies in the air");
        e.setAttribute("login", "kermmi");

        userdom.getFirstChild().appendChild(e);
        System.out.println(e);
        System.out.println(userdom.getFirstChild() + "|" + userdom.getFirstChild().getFirstChild());
        saveUserDom();
    }

    public static void saveUserDom() {
        try {
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer trans = tf.newTransformer();
            System.out.println(userdom.getFirstChild() + "|" + userdom.getFirstChild().getFirstChild());
            DOMSource ds = new DOMSource(userdom);

            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                StreamResult sr = new StreamResult(baos);
                trans.transform(ds, sr);

                System.out.println(new String(baos.toByteArray()));
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
}

I get the following output...

[user: null]
[users: null]|[user: null]
[users: null]|[user: null]
<?xml version="1.0" encoding="UTF-8" standalone="no"?><users><user id="blah" login="kermmi" password="bunnies in the air" username="kermit"/></users>

Which clearly demonstrates that the appendChild method is working fine.

An immediate concern is the relationship between...

public static Document userdom = XmlFactory.getUserDom();

and

DOMSource ds = new DOMSource(userdom);

One has to ask, are they the same reference (of userdom)?

Updated

This...

 private static File userfile = new File(User.class.getResource("User.xml").getPath());

coupled with this...

 StreamResult sr = new StreamResult(userfile);

Are your problems...

First, you are loading an internal resource and you should NEVER wrap these in File entry, internal/embedded resources are not accessible from a File context and need to be loaded in a different way, instead, maitain the URL refernce that getResource results...

 private static URL userfile = User.class.getResource("User.xml");

The next line, (StreamResult sr = new StreamResult(userfile);) is trying to write the resulting DOM back to an embedded resource...embedded resources can not be written to in this fashion, hence the reason it would fail in a normal running environment (it might work in your IDE, but that's a different issue).

Basically, you can't maintain this information as an embedded resource, you need to externalise the file onto the disk.

FYI:

If you did use the URL of the resource properly, you would need to change the way you are loading the XML document to something like...

try (InputStream is = userfile.openStream()) {
    userdom = dbu.parse(is);
}

Upvotes: 1

Related Questions