SAXTreeViewer
uses Swing to graphically
* display an XML document.
*/
public class SAXTreeViewer extends JFrame {
/** Default parser to use */
private String vendorParserClass =
"org.apache.xerces.parsers.SAXParser";
/** The base tree to render */
private JTree jTree;
/** Tree model to use */
DefaultTreeModel defaultTreeModel;
/**
* This initializes the needed Swing settings.
*/ public SAXTreeViewer() { // Handle Swing setup super("SAX Tree Viewer"); setSize(600, 450); } /** *This will construct the tree using Swing.
* * @param filenameString
path to XML document.
*/
public void init(String xmlURI) throws IOException, SAXException {
DefaultMutableTreeNode base =
new DefaultMutableTreeNode("XML Document: " +
xmlURI);
// Build the tree model
defaultTreeModel = new DefaultTreeModel(base);
jTree = new JTree(defaultTreeModel);
// Construct the tree hierarchy
buildTree(defaultTreeModel, base, xmlURI);
// Display the results
getContentPane().add(new JScrollPane(jTree),
BorderLayout.CENTER);
}
/**
* This handles building the Swing UI tree.
* * @param treeModel Swing component to build upon. * @param base tree node to build on. * @param xmlURI URI to build XML document from. * @throwsIOException
- when reading the XML URI fails.
* @throws SAXException
- when errors in parsing occur.
*/
public void buildTree(DefaultTreeModel treeModel,
DefaultMutableTreeNode base, String xmlURI)
throws IOException, SAXException {
// Create instances needed for parsing
XMLReader reader =
XMLReaderFactory.createXMLReader(vendorParserClass);
ContentHandler jTreeContentHandler =
new JTreeContentHandler(treeModel, base);
ErrorHandler jTreeErrorHandler = new JTreeErrorHandler();
// Register content handler
reader.setContentHandler(jTreeContentHandler);
// Register error handler
reader.setErrorHandler(jTreeErrorHandler);
// Parse
InputSource inputSource =
new InputSource(xmlURI);
reader.parse(inputSource);
}
/**
* Static entry point for running the viewer.
*/ public static void main(String[] args) { try { if (args.length != 1) { System.out.println( "Usage: java SAXTreeViewer " + "[XML Document URI]"); System.exit(0); } SAXTreeViewer viewer = new SAXTreeViewer(); viewer.init(args[0]); viewer.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } } /** *JTreeContentHandler
implements the SAX
* ContentHandler
interface and defines callback
* behavior for the SAX callbacks associated with an XML
* document's content, bulding up JTree nodes.
*/
class JTreeContentHandler implements ContentHandler {
/** Hold onto the locator for location information */
private Locator locator;
/** Store URI to prefix mappings */
private Map namespaceMappings;
/** Tree Model to add nodes to */
private DefaultTreeModel treeModel;
/** Current node to add sub-nodes to */
private DefaultMutableTreeNode current;
/**
* Set up for working with the JTree.
* * @param treeModel tree to add nodes to. * @param base node to start adding sub-nodes to. */ public JTreeContentHandler(DefaultTreeModel treeModel, DefaultMutableTreeNode base) { this.treeModel = treeModel; this.current = base; this.namespaceMappings = new HashMap(); } /** *
* Provide reference to Locator
which provides
* information about where in a document callbacks occur.
*
Locator
object tied to callback
* process
*/
public void setDocumentLocator(Locator locator) {
// Save this for later use
this.locator = locator;
}
/**
*
* This indicates the start of a Document parse-this precedes
* all callbacks in all SAX Handlers with the sole exception
* of {@link #setDocumentLocator}
.
*
SAXException
when things go wrong
*/
public void startDocument() throws SAXException {
// No visual events occur here
}
/**
* * This indicates the end of a Document parse-this occurs after * all callbacks in all SAX Handlers.. *
* * @throwsSAXException
when things go wrong
*/
public void endDocument() throws SAXException {
// No visual events occur here
}
/**
* * This indicates that a processing instruction (other than * the XML declaration) has been encountered. *
* * @param targetString
target of PI
* @param data String
SAXException when things go wrong
*/
public void processingInstruction(String target, String data)
throws SAXException {
DefaultMutableTreeNode pi =
new DefaultMutableTreeNode("PI (target = '" + target +
"', data = '" + data + "')");
current.add(pi);
}
/**
*
* This indicates the beginning of an XML Namespace prefix
* mapping. Although this typically occurs within the root element
* of an XML document, it can occur at any point within the
* document. Note that a prefix mapping on an element triggers
* this callback before the callback for the actual element
* itself ({@link #startElement}
) occurs.
*
String
prefix used for the namespace
* being reported
* @param uri String
URI for the namespace
* being reported
* @throws SAXException
when things go wrong
*/
public void startPrefixMapping(String prefix, String uri) {
// No visual events occur here.
namespaceMappings.put(uri, prefix);
}
/**
*
* This indicates the end of a prefix mapping, when the namespace
* reported in a {@link #startPrefixMapping}
callback
* is no longer available.
*
String
of namespace being reported
* @throws SAXException
when things go wrong
*/
public void endPrefixMapping(String prefix) {
// No visual events occur here.
for (Iterator i = namespaceMappings.keySet().iterator();
i.hasNext(); ) {
String uri = (String)i.next();
String thisPrefix = (String)namespaceMappings.get(uri);
if (prefix.equals(thisPrefix)) {
namespaceMappings.remove(uri);
break;
}
}
}
/**
*
* This reports the occurrence of an actual element. It includes
* the element's attributes, with the exception of XML vocabulary
* specific attributes, such as
* xmlns:[namespace prefix]
and
* xsi:schemaLocation
.
*
String
namespace URI this element
* is associated with, or an empty String
* @param localName String
name of element (with no
* namespace prefix, if one is present)
* @param qName String
XML 1.0 version of element name:
* [namespace prefix]:[localName]
* @param atts Attributes
list for this element
* @throws SAXException
when things go wrong
*/
public void startElement(String namespaceURI, String localName,
String qName, Attributes atts)
throws SAXException {
DefaultMutableTreeNode element =
new DefaultMutableTreeNode("Element: " + localName);
current.add(element);
current = element;
// Determine namespace
if (namespaceURI.length() > 0) {
String prefix =
(String)namespaceMappings.get(namespaceURI);
if (prefix.equals("")) {
prefix = "[None]";
}
DefaultMutableTreeNode namespace =
new DefaultMutableTreeNode("Namespace: prefix = '" +
prefix + "', URI = '" + namespaceURI + "'");
current.add(namespace);
}
// Process attributes
for (int i=0; i
* Indicates the end of an element
* (</[element name]>
) is reached. Note that
* the parser does not distinguish between empty
* elements and non-empty elements, so this occurs uniformly.
*
String
URI of namespace this
* element is associated with
* @param localName String
name of element without prefix
* @param qName String
name of element in XML 1.0 form
* @throws SAXException
when things go wrong
*/
public void endElement(String namespaceURI, String localName,
String qName)
throws SAXException {
// Walk back up the tree
current = (DefaultMutableTreeNode)current.getParent();
}
/**
* * This reports character data (within an element). *
* * @param chchar[]
character array with character data
* @param start int
index in array where data starts.
* @param length int
index in array where data ends.
* @throws SAXException
when things go wrong
*/
public void characters(char[] ch, int start, int length)
throws SAXException {
String s = new String(ch, start, length);
DefaultMutableTreeNode data =
new DefaultMutableTreeNode("Character Data: '" + s + "'");
current.add(data);
}
/**
* * This reports whitespace that can be ignored in the * originating document. This is typically invoked only when * validation is ocurring in the parsing process. *
* * @param chchar[]
character array with character data
* @param start int
index in array where data starts.
* @param end int
index in array where data ends.
* @throws SAXException
when things go wrong
*/
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
// This is ignorable, so don't display it
}
/**
* * This reports an entity that is skipped by the parser. This * should only occur for non-validating parsers, and then is still * implementation-dependent behavior. *
* * @param nameString
name of entity being skipped
* @throws SAXException
when things go wrong
*/
public void skippedEntity(String name) throws SAXException {
DefaultMutableTreeNode skipped =
new DefaultMutableTreeNode("Skipped Entity: '" + name + "'");
current.add(skipped);
}
}
/**
* JTreeErrorHandler
implements the SAX
* ErrorHandler
interface and defines callback
* behavior for the SAX callbacks associated with an XML
* document's warnings and errors.
*/
class JTreeErrorHandler implements ErrorHandler {
/**
* * This will report a warning that has occurred; this indicates * that while no XML rules were "broken", something appears * to be incorrect or missing. *
* * @param exceptionSAXParseException
that occurred.
* @throws SAXException
when things go wrong
*/
public void warning(SAXParseException exception)
throws SAXException {
System.out.println("**Parsing Warning**\n" +
" Line: " +
exception.getLineNumber() + "\n" +
" URI: " +
exception.getSystemId() + "\n" +
" Message: " +
exception.getMessage());
throw new SAXException("Warning encountered");
}
/**
* * This will report an error that has occurred; this indicates * that a rule was broken, typically in validation, but that * parsing can reasonably continue. *
* * @param exceptionSAXParseException
that occurred.
* @throws SAXException
when things go wrong
*/
public void error(SAXParseException exception)
throws SAXException {
System.out.println("**Parsing Error**\n" +
" Line: " +
exception.getLineNumber() + "\n" +
" URI: " +
exception.getSystemId() + "\n" +
" Message: " +
exception.getMessage());
throw new SAXException("Error encountered");
}
/**
* * This will report a fatal error that has occurred; this indicates * that a rule has been broken that makes continued parsing either * impossible or an almost certain waste of time. *
* * @param exceptionSAXParseException
that occurred.
* @throws SAXException
when things go wrong
*/
public void fatalError(SAXParseException exception)
throws SAXException {
System.out.println("**Parsing Fatal Error**\n" +
" Line: " +
exception.getLineNumber() + "\n" +
" URI: " +
exception.getSystemId() + "\n" +
" Message: " +
exception.getMessage());
throw new SAXException("Fatal Error encountered");
}
}
// Demo file: book.xml
/*