Louis Etienne
Louis Etienne

Reputation: 1371

Independent method for exporting classes to XML

I have a class Container:

public class Container implements Exportable {
    private Node root;
    private String name;

    public void exportXML(Element target, Document document) {
        target.setAttribute("name", name);

        root.exportXML(target, document);
    }
}

Which implements the interface Exportable which defines two abstracts methods, one for importing, one for exporting. The objective is to export my classes to XML format.
As you can see, the class Container take a Node which is the root of a Node tree. This is the Node class:

public class Node implements Exportable {
    private ArrayList<Node> children = new ArrayList<>();
    private String name;

    public void exportXML(Element target, Document document) {
        Element node = document.createElement("node");
        target.appendChild(node);
        node.setAttribute("name", name);

        if (children.size() > 0) {
            Element nodes = document.createElement("nodes");
            node.appendChild(nodes);

            for (Node child : children) {
                child.exportXML(nodes, document);
            }
        }
    }
}

I use a SaveManager class for exporting the Container object:

public class SaveManager {
    public static void exportContainer(Container container, String pathname) {
        try {
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();

            Document document = documentBuilder.newDocument();
            Element projectNode = document.createElement("container");
            document.appendChild(projectNode);

            container.exportXML(projectNode, document);

            TransformerFactory transformerFactory = TransformerFactory.newInstance();
            Transformer transformer = transformerFactory.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");

            DOMSource source = new DOMSource(document);
            StreamResult result = new StreamResult(new File(pathname));

            transformer.transform(source, result);

        } catch (ParserConfigurationException | TransformerException e) {
            e.printStackTrace();
        }
    }
}

I need to be able to export the Node alone, without a Container. For example, if I call nodeA.exportXML(), the nodeA will be the root of the tree.

The problem is that I will have two methods in my SaveManager doing exactly the same thing (ie call exportXML() on an object and save the result into an XML file) and I will have to create to methods exportXML() in my Node class, one where the Node is a child and one where it's the root. I did exactly the same thing in C++ using pugixml and it was much easier because the document itself was a node, so I just had to give it to the exportXML() method if I wanted anything to be a root otherwise.

Is it possible to have a generic exportXML() method with the Java XML implementation?

Upvotes: 4

Views: 281

Answers (1)

df778899
df778899

Reputation: 10931

Sticking with the DOM approach, it looks like the simplest way to do this would be to let the Container create its own element. Both Node and Container would then be able to add themselves to whatever parent Document or Element was passed in.

(We're about to have to deal with two Node classes here unfortunately, but ...) The trick to doing this is to use a org.w3c.dom.Node as the first parameter in exportXML() - this is the superinterface for both Document and Element, so can handle the root or child being passed in:

public class Container implements Exportable {
    private Node root;
    private String name;

    @Override
    public void exportXML(org.w3c.dom.Node target, Document document) {
        Element node = document.createElement("container");
        document.appendChild(node);
        node.setAttribute("name", name);

        root.exportXML(target, document);
    }
}

SaveManager can then just pass the Document in at the start:

        Document document = documentBuilder.newDocument();
        //Element projectNode = document.createElement("container");
        //document.appendChild(projectNode);

        container.exportXML(document, document);

And your Node class should work unchanged, just with a org.w3c.dom.Node target passed in now.

But agree with the earlier comments about XStream or JAX-B. For example most of the XML being generated so far would be well with the capabilities of a few @XmlElement and @XmlAttribute annotations.

Upvotes: 2

Related Questions