Roll Your Own Swing-based XML Editor (Part II)

Roll Your Own Swing-based XML Editor (Part II)

Editor’s note: This is the second of a three-part series about how to build your own XML editor.

f you’ve been looking for a cross-platform, open-source, XML editor, you’ve likely come up short. In this three-part series of articles I will walk you through the development of a simple, no-frills XML editor, utilizing several of the most common Java 2 Swing components. This series will be beneficial to anyone wanting to write their own XML editor, or just to those of you looking to learn or brush up on Swing.

This is the second article in the series. In the first article, we briefly discussed XML and why a tree structure is appropriate to display XML, how to handle XML data, how to work with the JTree Swing component, and we built a reusable component that is capable of parsing an XML document and displaying its data in a JTree.

In this article, we will create the framework for our XML editor. In order to do so, we will cover a variety of Swing components (including JSplitPane, JScrollPane, JButton, and JTextArea).

How can I create an XML text editor that has a text view and a graphical view, and updates the graphical view based upon changes I make to the text?

Create a JFrame object that contains a JButton and a JSplitPane. Then have the JSplitPane contain two JScrollPanes. One will house the graphical view (the xTree class) and the other will house the textual view (a JTextArea). The JButton will manage the graphical view refresh.

Enhance the XTree class
In the previous article, we developed the XTree class, a reusable component derived from the JTree class and capable of displaying XML data as a graphical tree. We will now enhance that class by providing it with a default XML tree to display in the event that an XML file is not supplied at the command-line. Additionally, we will also add some exception-handling logic so that the program will not crash due to invalid XML.

The first step is to create a method called buildTree():

private DefaultTreeModel buildTree( String text )  {   DefaultMutableTreeNode  treeNode;	Node				 newNode;

// Take the DOM root node and convert it to a Tree model
newNode = parseXml( text );

if ( newNode != null ) { treeNode = createTreeNode( newNode ); return new DefaultTreeModel( treeNode ); } else return null; } //end buildTree()

This method takes the XML text string passed to it, parses the XML and constructs a DefaultTreeModel that can then be used to construct the graphical tree structure from that data. This functionality had originally been contained in the XTree() constructor, but by taking it out and placing it in a separate method, we have the flexibility to create a default graphical tree. That is exactly what we will do next.

The next step is to create a method called buildWelcomeTree(). This method builds a DefaultTreeModel one piece at a time, rather than by parsing an existing string of XML text. This DefaultTreeModel will be displayed if the user starts the application without specifying an XML document.

Next we need to add a new constructor to facilitate this default display functionality. We will change the main constructor, so that it does not accept any arguments, and create a new constructor that accepts a single String of XML text. This way, the default XTree object will be created if no XML text will be displayed, and a unique XTree object will be created if the XML text is displayed. Both constructors can be seen in Listing 2.

Create the XmlEditor Class
The XmlEditor class serves the same purpose as the XTreeTester class did in the previous article. The difference is that the XmlEditor will include a JTextArea that will allow you to manipulate a text version of the XML. After that, you can click the “Refresh” button and see the changes reflected in the XTree component.

If you’re modifying the code from the last article, you will have a much easier time if you rename the file to (be sure and modify the constructor) and use that as a template.

The first thing to do is to add the following Swing components: another JScrollPane, a JSplitPane, a JTextArea, and a JButton. Start by declaring all of these with the other component declarations. (See Listing 3.)

First, we’ll create and add the “Refresh” button. This button will be used to indicate that the XTree component should be refreshed with the current XML text. We’ll also need to register it with an ActionListener. (See Listing 4.) In order to intercept button events, we will need to have this class also implement ActionListener, and we will need to create an actionPerformed() method. (See Listing 5.)

Next, we’ll create the new JScrollPane and the JTextArea and add the JTextArea to the JScrollPane. Thus, we will have the original JScrollPane containing the XTree component and the new JScrollPane containing the JTextArea component. There is one modification to make to the original XTree constructor. We will remove the String parameter that we previously passed into this method. (That functionality is handled by the other XmlEditor() constructor that we will build next.) We’ll put both of these panes in a JSplitPane, which is a component that has a divider and can house one component on either side of the divider. (See Listing 6.)

Now we need to modify the constructors to handle the no-XML file scenario. Remove the second String parameter that the current constructor is expecting. This constructor will now be the default constructor. Instead, we will create a new constructor that accepts a single string parameter. It will first call the default constructor, and then process the parameter. (See Listing 7.) Also, the main() method must be changed so that in the event that no XML file is provided, a default XmlEditor object will still be created. (See Listing 8.)

There is one last change necessary in order to handle the JTextArea data easily. Rather than treating the text contained within it as one long string, we will treat it as a series of strings, with each line representing a string contained within an ArrayList. This will require modifying the parameter accepted by our constructor, as well as modifying any calls within the main() method that previously passed this data as a String. This will also require importing the java.util package. (See Listing 8.)

Testing the Application
Finally, we must add a bit of exception handling to the XTree class. If you were to run the application as this point and enter invalid XML data in the JTextArea, the program would crash. We don’t want that to happen. For now, we will have the error message print to the command line. In the next article, we will have the error message display in a graphical dialogue box.

If invalid or non-well-formed XML data is entered into the JTextArea and the “Refresh” button pushed, then the parser will spit out an error. The current exception handling contained in the parseXML() method will immediately exit in this case. Instead, we want the program to report the error and return a null value to indicate that the parsing was unsuccessful. (See Listing 9.) You may have noticed that both the “buildTree()” and “refresh()” methods in the XTree class have a conditional statement that avoids processing a null value. This is because they too would report exceptions if they tried to process a null value. This chain of events keeps the program flow going and the XTree model stable.

Finally, we are ready to test the application. You should see something like this: (See Figure 1.)

Congratulations! We’ll put the finishing touches to this tool in the third and final article.


About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist