XmlPull
The XmlPull API was a predecessor to the StAX specification. It defines a simple API similar to the StAX cursor API. Full information about the XmlPull API can be found at http://www.xmlpull.org. The advantage the XmlPull API has over StAX is that because it's a much smaller API, it's suitable for memory-constrained environments, such as mobile devices. One implementation of XmlPull is available in a 9 KB JAR file. The API JAR file from the StAX specification is more than 25 KB alone. If you're building a server app, this difference is irrelevant, but if you're developing a game to be run on a mobile phone where the JAR file must be under 100 KB, this is a big difference. Example 8-23 contains a version of the Tree Builder app writing with the XmlPull API.
Example XmlPullTreeViewer
package javaxml3; import java.awt.BorderLayout; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import javax.swing.JFrame; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; public class XmlPullTreeViewer extends JFrame { /** The base tree to render */ private JTree jTree; /** Tree model to use */ DefaultTreeModel defaultTreeModel; public XmlPullTreeViewer( ) { // Handle Swing setup super("XmlPull Tree Viewer"); setSize(800, 450); // setSize(600, 200); } public void init(File file) throws XmlPullParserException, IOException { DefaultMutableTreeNode base = new DefaultMutableTreeNode( "XML Document: " + file.getAbsolutePath( )); // Build the tree model defaultTreeModel = new DefaultTreeModel(base); jTree = new JTree(defaultTreeModel); // Construct the tree hierarchy buildTree(defaultTreeModel, base, file); // Display the results getContentPane( ).add(new JScrollPane(jTree), BorderLayout.CENTER); } // Swing-related variables and methods, including // setting up a JTree and basic content pane public static void main(String[] args) { try { if (args.length != 1) { System.out.println("Usage: java javaxml3.XmlPullTreeViewer " + "[XML Document]"); return; } XmlPullTreeViewer viewer = new XmlPullTreeViewer( ); File f = new File(args[0]); viewer.init(f); viewer.setVisible(true); } catch (Exception e) { e.printStackTrace( ); } } public void buildTree(DefaultTreeModel treeModel, DefaultMutableTreeNode current, File file) throws XmlPullParserException, IOException { FileInputStream inputStream = new FileInputStream(file); XmlPullParserFactory factory = XmlPullParserFactory.newInstance( ); factory.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); XmlPullParser parser = factory.newPullParser( ); parser.setInput(inputStream, null); parseRestOfDocument(parser, current); } private void parseRestOfDocument(XmlPullParser parser, DefaultMutableTreeNode current) throws XmlPullParserException, IOException { int type = parser.getEventType( ); while (type != XmlPullParser.END_DOCUMENT) { switch (type) { case XmlPullParser.START_TAG: DefaultMutableTreeNode element = new DefaultMutableTreeNode( "Element: " + parser.getName( )); current.add(element); current = element; // Determine namespace if (parser.getNamespace( ) != null) { String prefix = parser.getPrefix( ); if (!"".equals(prefix)) { prefix = "[None]"; } DefaultMutableTreeNode namespace = new DefaultMutableTreeNode( "Namespace: prefix = '" + prefix + "', URI = '" + parser.getNamespace( ) + "'"); current.add(namespace); } if (parser.getAttributeCount( ) > 0) { for (int i = 0; i < parser.getAttributeCount( ); i++) { DefaultMutableTreeNode attrib = new DefaultMutableTreeNode( "Attribute (name = '" + parser.getAttributeName(i) + "', value = '" + parser.getAttributeValue(i) + "')"); String attURI = parser.getAttributeNamespace(i); if (!"".equals(attURI)) { String attPrefix = parser.getAttributePrefix(i); if (attPrefix == null || attPrefix.equals("")) { attPrefix = "[None]"; } DefaultMutableTreeNode an = new DefaultMutableTreeNode( "Namespace: prefix = '" + attPrefix + "', URI = '" + attURI + "'"); attrib.add(an); } current.add(attrib); } } break; case XmlPullParser.END_TAG: current = (DefaultMutableTreeNode) current.getParent( ); break; case XmlPullParser.TEXT: if (!parser.isWhitespace( )) { DefaultMutableTreeNode data = new DefaultMutableTreeNode( "Character Data: '" + parser.getText( ) + "'"); current.add(data); } break; case XmlPullParser.IGNORABLE_WHITESPACE: // let's ignore this break; case XmlPullParser.COMMENT: DefaultMutableTreeNode comment = new DefaultMutableTreeNode( "Comment: '" + parser.getText( ) + "'"); current.add(comment); break; default: System.out.println(type); } type = parser.next( ); } } } |
As you can see, this is very similar to the StAX cursor API but with far fewer imports. Unlike StAX, implementations of XmlPullParser do not process namespaces by default. As a result, in Example 8-23, we enable the namespace processing feature to best emulate the behavior of the StAX version of this app .