Search code examples
javaxmlswingtreejtree

JTree: How to add attributes of nodes as their own leaves?


I'm visualizing XML files with javax.swing.JTree. Having used code from this and this question, I got stuck at adding attributes from a node as leaves to it.

This simple XML:

<?xml version="1.0" encoding="utf-8"?>
<!-- comment -->
<MYXML xmlns="">
    <Header id=""></Header>
    <Product id="" name="">
        <Description>Some text</Description>
        <Ref id=""></Ref>
        <Data id="">
            <Ref id=""></Ref>
        </Data>
        <Form id=""></Form>
    </Product>
</MYXML>

is being parsed to org.w3c.dom.Document and passed as org.w3c.dom.Node to recursively build a JTree:

private DefaultMutableTreeNode buildTreeNode(Node rootNode) {
    DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(
            rootNode.getNodeName());
    NodeList children = rootNode.getChildNodes();

    for (int i = 0; i < children.getLength(); i++) {
        Node node = children.item(i);
        short nodeType = node.getNodeType();

        if (nodeType == Node.ELEMENT_NODE) {
            treeNode.add(buildTreeNode(node));

            // FIXME attributes should be leaves of their nodes
            if (node.hasAttributes()) {
                NamedNodeMap attributes = node.getAttributes();
                for (int j = 0; j < attributes.getLength(); j++) {
                    Node attr = attributes.item(j);
                    treeNode.add(new DefaultMutableTreeNode("@" + attr));
                }
            }
        } else if (nodeType == Node.TEXT_NODE) {
            String text = node.getTextContent().trim();
            if (!text.equals("")) {
                treeNode.add(new DefaultMutableTreeNode(text));
            }
        } else if (nodeType == Node.COMMENT_NODE) {
            String comment = node.getNodeValue().trim();
            treeNode.add(new DefaultMutableTreeNode("#" + comment));
        }
    }
    return treeNode;
}

The result is not what I wanted:

result

The leaves "Header", "Ref" and "Form" should be nodes and all attributes (marked @) should be the leaves of their nodes. How can I achieve this with my recursive approach?

Here is my working example on Gist.

EDIT: I figured it out and answered my question below.


Solution

  • Well, I finally sorted it out, thanks to Krzysztof's hints. Now the nodes with children are handled correctly and attribute leaves are where they should be:

    private DefaultMutableTreeNode buildTreeNode(Node rootNode) {
        DefaultMutableTreeNode treeNode = new DefaultMutableTreeNode(
                rootNode.getNodeName());
    
        if (rootNode.hasAttributes()) {
            NamedNodeMap attributes = rootNode.getAttributes();
    
            for (int j = 0; j < attributes.getLength(); j++) {
                String attr = attributes.item(j).toString();
                treeNode.add(new DefaultMutableTreeNode("@" + attr));
            }
        }
    
        if (rootNode.hasChildNodes()) {
            NodeList children = rootNode.getChildNodes();
    
            for (int i = 0; i < children.getLength(); i++) {
                Node node = children.item(i);
                short nodeType = node.getNodeType();
    
                if (nodeType == Node.ELEMENT_NODE)
                    treeNode.add(buildTreeNode(node));
    
                else if (nodeType == Node.TEXT_NODE) {
                    String text = node.getTextContent().trim();
                    if (!text.equals(""))
                        treeNode.add(new DefaultMutableTreeNode(text));
    
                } else if (nodeType == Node.COMMENT_NODE) {
                    String comment = node.getNodeValue().trim();
                    treeNode.add(new DefaultMutableTreeNode("#" + comment));
                }
            }
        }
        return treeNode;
    

    Which produces what I wanted:

    enter image description here

    For completion, the corrected example on Gist.