/** * Copyright (c) 2004-2006 Regents of the University of California. * See "license-prefuse.txt" for licensing terms. */ package prefuse.data.io; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Date; import java.util.HashMap; import prefuse.data.Graph; import prefuse.data.Node; import prefuse.data.Schema; import prefuse.util.io.XMLWriter; /** * GraphWriter instance that writes a tree file formatted using the * TreeML file format. TreeML is an XML format originally created for * the 2003 InfoVis conference contest. A DTD (Document Type Definition) for * TreeML is * <a href="http://www.nomencurator.org/InfoVis2003/download/treeml.dtd"> * available online</a>. * * <p>The GraphML spec only supports the data types <code>Int</code>, * <code>Long</code>, <code>Float</code>, <code>Real</code> (double), * <code>Boolean</code>, <code>String</code>, and <code>Date</code>. * An exception will be thrown if a data type outside these allowed * types is encountered.</p> * * @author <a href="http://jheer.org">jeffrey heer</a> */ public class TreeMLWriter extends AbstractGraphWriter { /** * String tokens used in the TreeML format. */ public interface Tokens extends TreeMLReader.Tokens {} /** * Map containing legal data types and their names in the GraphML spec */ private static final HashMap TYPES = new HashMap(); static { TYPES.put(int.class, Tokens.INT); TYPES.put(long.class, Tokens.LONG); TYPES.put(float.class, Tokens.FLOAT); TYPES.put(double.class, Tokens.REAL); TYPES.put(boolean.class, Tokens.BOOLEAN); TYPES.put(String.class, Tokens.STRING); TYPES.put(Date.class, Tokens.DATE); } /** * @see prefuse.data.io.GraphWriter#writeGraph(prefuse.data.Graph, java.io.OutputStream) */ public void writeGraph(Graph graph, OutputStream os) throws DataIOException { // first, check the schemas to ensure GraphML compatibility Schema ns = graph.getNodeTable().getSchema(); checkTreeMLSchema(ns); XMLWriter xml = new XMLWriter(new PrintWriter(os)); xml.begin(); xml.comment("prefuse TreeML Writer | " + new Date(System.currentTimeMillis())); // print the tree contents xml.start(Tokens.TREE); // print the tree node schema xml.start(Tokens.DECLS); String[] attr = new String[] {Tokens.NAME, Tokens.TYPE }; String[] vals = new String[2]; for ( int i=0; i<ns.getColumnCount(); ++i ) { vals[0] = ns.getColumnName(i); vals[1] = (String)TYPES.get(ns.getColumnType(i)); xml.tag(Tokens.DECL, attr, vals, 2); } xml.end(); xml.println(); // print the tree nodes attr[0] = Tokens.NAME; attr[1] = Tokens.VALUE; Node n = graph.getSpanningTree().getRoot(); while ( n != null ) { boolean leaf = (n.getChildCount() == 0); if ( leaf ) { xml.start(Tokens.LEAF); } else { xml.start(Tokens.BRANCH); } if ( ns.getColumnCount() > 0 ) { for ( int i=0; i<ns.getColumnCount(); ++i ) { vals[0] = ns.getColumnName(i); vals[1] = n.getString(vals[0]); if (vals[1] != null) { xml.tag(Tokens.ATTR, attr, vals, 2); } } } n = nextNode(n, xml); } // finish writing file xml.end(); xml.finish(); } /** * Find the next node in the depth first iteration, closing off open * branch tags as needed. * @param x the current node * @param xml the XMLWriter * @return the next node */ private Node nextNode(Node x, XMLWriter xml) { Node n, c; if ( (c=x.getChild(0)) != null ) { // do nothing } else if ( (c=x.getNextSibling()) != null ) { xml.end(); } else { c = x.getParent(); xml.end(); while ( c != null ) { if ( (n=c.getNextSibling()) != null ) { c = n; xml.end(); break; } c = c.getParent(); xml.end(); } } return c; } /** * Checks if all Schema types are compatible with the TreeML specification. * The TreeML spec only allows the types <code>int</code>, * <code>long</code>, <code>float</code>, <code>double</code>, * <code>boolean</code>, <code>string</code>, and <code>date</code>. * @param s the Schema to check */ private void checkTreeMLSchema(Schema s) throws DataIOException { for ( int i=0; i<s.getColumnCount(); ++i ) { Class type = s.getColumnType(i); if ( TYPES.get(type) == null ) { throw new DataIOException("Data type unsupported by the " + "TreeML format: " + type.getName()); } } } } // end of class GraphMLWriter