FileDocCategorySizeDatePackage
SimpleXPathViewer.javaAPI DocExample9334Sat Sep 01 16:10:14 BST 2001javaxml2

SimpleXPathViewer.java

/*-- 

 Copyright (C) 2001 Brett McLaughlin.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:
 
 1. Redistributions of source code must retain the above copyright
    notice, this list of conditions, and the following disclaimer.
 
 2. Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions, and the disclaimer that follows 
    these conditions in the documentation and/or other materials 
    provided with the distribution.

 3. The name "Java and XML" must not be used to endorse or promote products
    derived from this software without prior written permission.  For
    written permission, please contact brett@newInstance.com.
 
 In addition, we request (but do not require) that you include in the 
 end-user documentation provided with the redistribution and/or in the 
 software itself an acknowledgement equivalent to the following:
     "This product includes software developed for the
      'Java and XML' book, by Brett McLaughlin (O'Reilly & Associates)."

 THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 SUCH DAMAGE.

 */
package javaxml2;

import java.awt.*;
import java.io.File;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.util.Iterator;

// JDOM imports
import org.jdom.*;
import org.jdom.input.SAXBuilder;

/**
 * This displays the XML document given on the command line in 
 *   a JTree. When a user clicks on a node, this displays the 
 *   XPath text that is related to that node according to the 
 *   following specification:
 *
 * Element   - XPath statement that will uniquely select the node
 * Attribute - XPath statement that will select any element with that
 *             attribute and value
 * Text      - XPath statement that will return the selected text
 * others    - (currently) ignored
 */
public class SimpleXPathViewer extends JFrame {

    /** The event handler inner class */
    EventHandler eventHandler = new EventHandler();

    /** A text field for displaying the XPath for the selectected node */
    private JTextField statusText;

    /** The JTree used to display the nodes of the xml document */
    private JTree jdomTree;

    /** The selection model used to determine which node was clicked */
    private DefaultTreeSelectionModel selectionModel;

    /** The filename containing the xml file to view */
    private String filename;

    /** Temporary hack to get around the lack of a text node */
    private static Element lastElement;

    /**
     * Simple inner class to handle various ui events and delegate them
     * to the appropriate methods
     */	   
    class EventHandler implements TreeSelectionListener {

        public void valueChanged(TreeSelectionEvent e) {
            TreePath path= selectionModel.getLeadSelectionPath();

            // If you are just collapsing the tree, you may not have a new path
            if (path != null) {
                JDOMNode selection=
                    (JDOMNode) ((DefaultMutableTreeNode)path.getLastPathComponent())
                        .getUserObject();
                buildXPath(selection);
            }
        };
    };

    /**
     * <p>Construct an instance of the viewer.</p>
     *
     * @param fileName file to use as input
     */
    public SimpleXPathViewer(String fileName) throws Exception {
        super();
        this.filename = fileName;
        setSize(600, 450);
        initialize();
    }

    /**
     * <p>Initialize the class, load and display the xml document.</p>
     */
    private void initialize() throws Exception {
        setTitle("Simple XPath Viewer");

        // Setup the UI
        initConnections();
		
        // Load the JDOM Document
        Document doc = loadDocument(filename);

        // Create the initial JDOMNode from the Factory method
        JDOMNode root = createNode(doc.getRootElement());
			
        // Create the root node of the JTree and build it from the JDOM Document
        DefaultMutableTreeNode treeNode = 
            new DefaultMutableTreeNode("Document: " + filename);
        buildTree(root, treeNode);

        // Add the node to the tree's model
        ((DefaultTreeModel)jdomTree.getModel()).setRoot(treeNode);
    }

    /**
     * <p>This initializes connections between swing components, models 
     *   and event handlers.</p>
     */
    private void initConnections() {
        setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);

        // Setup the JTree and a pane to display it in
        jdomTree = new JTree();
        jdomTree.setName("JDOM Tree");
        jdomTree.addTreeSelectionListener(eventHandler);
        selectionModel = (DefaultTreeSelectionModel)jdomTree.getSelectionModel();
        getContentPane().add(new JScrollPane(jdomTree), BorderLayout.CENTER);

        // Setup a text box for use in a status bar
        statusText = new JTextField("Click on an element to view xpath");
        JPanel statusBarPane= new JPanel();
        statusBarPane.setLayout(new BorderLayout());
        statusBarPane.add(statusText, BorderLayout.CENTER );
        getContentPane().add(statusBarPane, BorderLayout.SOUTH);
    }
	
    /**
     * <p>Load the given xml file for display.</p>
     *
     * @param filename XML file to load.
     * @return <code>Document</code> - JDOM XML representation.
     */
    private Document loadDocument(String filename) throws JDOMException {
        SAXBuilder builder = new SAXBuilder();
        builder.setIgnoringElementContentWhitespace(true);
        return builder.build(new File(filename));
    }

    /**
     * <p>Factory method to create nodes according to the type of
     *   the given object.</p>
     * 
     * @param node object to wrap.
     * @return <code>JDOMNode</code> - created node.
     */
    private JDOMNode createNode(Object node) {
        if (node instanceof Element) {
            lastElement = (Element)node;
            return new ElementNode((Element)node);
        }

        if (node instanceof Attribute) {
            return new AttributeNode((Attribute)node);
        }

        if (node instanceof String) {
            return new TextNode((String)node).setParent(lastElement);
        }

        // All other nodes are not implemented
        return null;
    }
	
    /**
     * Recursively build the JTree from nodes of the JDOM Document
     * 
     * @param node JDOMNode
     * @param treeNode javax.swing.tree.DefaultMutableTreeNode
     */
    private void buildTree(JDOMNode node, DefaultMutableTreeNode treeNode) {
        // If this is a whitespace node or unhandled node, ignore it
        if ((node == null) || (node.toString().trim().equals(""))) {
            return;
        }

        DefaultMutableTreeNode newTreeNode = new DefaultMutableTreeNode(node);
		
        // Walk over the children of the node 
        Iterator i = node.iterator();
        while (i.hasNext()) {
            // Create JDOMNodes on the children and add to the tree
            JDOMNode newNode = createNode(i.next());
            buildTree(newNode, newTreeNode);
        }

        // After all the children have been added, connect to the tree
        treeNode.add(newTreeNode);
    }
	
    /**
     * Put the xpath path to the selected node in the status bar
     * 
     * @param node JDOMNode
     */
    private void buildXPath(JDOMNode node) {
        statusText.setText(new XPathDisplayNode(node).getXPath());
    }
	
    /**
     * <p>Static entry point</p>
     */
    public static void main(java.lang.String[] args) {
        try {
            if (args.length != 1) {
                System.out.println("Usage: java javaxml2.SimpleXPathViewer " + 
                    "[XML Document filename]");
                return;
            }

            /* Create the frame */
            SimpleXPathViewer viewer= new SimpleXPathViewer(args[0]);

            /* Add a windowListener for the windowClosedEvent */
            viewer.addWindowListener(new java.awt.event.WindowAdapter() {
                    public void windowClosed(java.awt.event.WindowEvent e) {
                        System.exit(0);
                    };
                });
            viewer.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}