import java.io.*; import java.awt.*; import java.net.*; import java.awt.event.*; import org.xml.sax.*; import org.w3c.dom.*; import com.sun.xml.parser.*; import com.sun.xml.tree.*; import org.xml.sax.helpers.*; /* * XmlView2 - a small AWT GUI program that illustrates use * of the Javasoft "Project X" XML document interface. * To use this program, simply run it, then enter the URL * of an XML file in the text field at the top. */ public class XmlView2 extends Frame implements ActionListener { List contents; Label caption; TextField filename; Button goButton; TextArea status; // Names of types from org.w3c.dom.Node. public static final String [] typeNames = { "unknown", "element", "attr", "text", "CDATASection", "EntityReference", "Entity", "ProcessingInstruction", "Comment", "Document", "DocumentType", "DocumentFragment", "Notation", }; /** * Constructor - create the AWT interface. */ public XmlView2() { super("XmlView2 - DOM"); contents = new List(); caption = new Label("XML Source URL:", Label.RIGHT); filename = new TextField(); goButton = new Button("PARSE"); Panel npanel = new Panel(); npanel.setLayout(new BorderLayout(2,2)); Panel topPanel = new Panel(); topPanel.setLayout(new BorderLayout(2,0)); topPanel.add("West",caption); topPanel.add("Center",filename); topPanel.add("East", goButton); npanel.add("North", topPanel); add("Center", contents); status = new TextArea(4,40); npanel.add("South", status); contents.setBackground(Color.white); add("North", npanel); setSize(490,620); setLocation(140,60); goButton.addActionListener(this); filename.addActionListener(this); } /** * Log a message to the scrolling text area. */ private void logMessage(String s) { status.append(s); status.append("\n"); try { Thread.sleep(40); } catch (InterruptedException ie) { } } /** * Prepend indentation onto the front of a string, return * result as a StringBuffer. */ private StringBuffer indent(int depth, String t) { StringBuffer s = new StringBuffer(depth + t.length()); for(int i = 0; i < depth; i++) s.append(" "); s.append(t); return s; } /** * Recursively dump an XmlDocument or other Node into * the AWT List contents. * The parameter depth is the indentation amount, not * strictly the tree depth. */ public void dumpXmlNode(Node n, int depth) { StringBuffer sb; NamedNodeMap attrs = n.getAttributes(); if (n instanceof XmlDocument) { sb = indent(depth, "Document Start (type="); DocumentType dt = ((XmlDocument)n).getDoctype(); if (dt == null) sb.append("unknown"); else sb.append(dt.getName()); sb.append(")"); contents.add(sb.toString()); } else { sb = indent(depth, "Node: "); sb.append(n.getNodeName()); sb.append(" (type="); int typ = n.getNodeType(); if (typ >= 0 && typ < typeNames.length) sb.append(typeNames[typ] + ")"); else sb.append(typ + ")"); sb.append(" (attrs="); sb.append(((attrs==null)?(0):(attrs.getLength())) + ")"); String val = n.getNodeValue(); if (val != null) { sb.append(" - "); sb.append(val); } contents.add(sb.toString()); } if (attrs != null && attrs.getLength() > 0) { Node nc; int d = depth + 3; for(int i = 0; i < attrs.getLength(); i++) { nc = attrs.item(i); dumpXmlNode(nc, d); } } if (n.hasChildNodes()) { Node nc; int d = depth + 1; for(nc = n.getFirstChild(); nc != null; nc = nc.getNextSibling()) { dumpXmlNode(nc, d); } } } /** * React to the user telling us to do the parsing. */ boolean running = false; public synchronized void actionPerformed(ActionEvent e) { if (running) { logMessage("Already busy, please wait..."); return; } String fn = filename.getText(); ParThread pt = new ParThread(fn); running = true; pt.setPriority(Thread.NORM_PRIORITY - 1); pt.start(); } /** * This thread class does all the actual parsing and * displaying. Good thing AWT List is thread-safe! */ class ParThread extends Thread { String fn; ParThread(String f) { fn = f; } /** * Open the URL, parse the contents into a XmlDocument, * then dump the document into the List. Log lots of * messages to the scrolling text area. */ public void run() { URL u2 = null; long stime = System.currentTimeMillis(); try { URL u1; File f = new File("."); u1 = new URL("file:" + f.getAbsolutePath()); u2 = new URL(u1, fn); } catch (MalformedURLException mue) { logMessage("Bad URL: " + u2); synchronized (XmlView2.this) { running = false; } return; } logMessage("Clearing list.."); contents.removeAll(); XmlDocument doc = null; try { logMessage("Creating document..."); try { doc = XmlDocument.createXmlDocument(u2.toString(), true); logMessage("Parsing with validation succeeded!"); } catch (SAXException sep) { logMessage("Validating parse failed: " + sep); logMessage(" --- trying non-validating."); doc = null; } if (doc == null) { doc = XmlDocument.createXmlDocument(u2.toString(), false); logMessage("Parsing without validation succeeded."); } long etime = System.currentTimeMillis(); logMessage("Parsing done, time = " + (etime - stime) + "ms."); logMessage("Dumping structure to List window..."); dumpXmlNode(doc,0); logMessage("Total nodes in document: " + contents.getItemCount()); } catch (Exception se) { logMessage("Parsing exception: " + se); contents.add("Parsing Exception Thrown!!!"); // se.printStackTrace(); } long ftime = System.currentTimeMillis(); logMessage("Done with " + u2.toString() + "\n total time = " + (ftime - stime) + "ms."); synchronized (XmlView2.this) { running = false; } } } /** * Main routine to kick off the program. Simply creates the * XmlView2 object and shows it. */ public static void main(String args[]) { XmlView2 v2 = new XmlView2(); v2.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.out.println("All done. Bye."); System.exit(0); } } ); v2.show(); } }