1 package prefuse.data.io; 2 3 import java.io.InputStream ; 4 import java.util.Date ; 5 import java.util.HashMap ; 6 7 import javax.xml.parsers.SAXParser ; 8 import javax.xml.parsers.SAXParserFactory ; 9 10 import org.xml.sax.Attributes ; 11 import org.xml.sax.SAXException ; 12 import org.xml.sax.helpers.DefaultHandler ; 13 14 import prefuse.data.Graph; 15 import prefuse.data.Schema; 16 import prefuse.data.Table; 17 import prefuse.data.parser.DataParseException; 18 import prefuse.data.parser.DataParser; 19 import prefuse.data.parser.ParserFactory; 20 import prefuse.util.collections.IntIterator; 21 22 23 32 public class GraphMLReader extends AbstractGraphReader implements GraphReader { 33 34 37 public Graph readGraph(InputStream is) throws DataIOException { 38 try { 39 SAXParserFactory factory = SAXParserFactory.newInstance(); 40 SAXParser saxParser = factory.newSAXParser(); 41 42 GraphMLHandler handler = new GraphMLHandler(); 43 saxParser.parse(is, handler); 44 return handler.getGraph(); 45 } catch ( Exception e ) { 46 if ( e instanceof DataIOException ) { 47 throw (DataIOException)e; 48 } else { 49 throw new DataIOException(e); 50 } 51 } 52 } 53 54 57 public interface Tokens { 58 public static final String ID = "id"; 59 public static final String GRAPH = "graph"; 60 public static final String EDGEDEF = "edgedefault"; 61 public static final String DIRECTED = "directed"; 62 public static final String UNDIRECTED = "undirected"; 63 64 public static final String KEY = "key"; 65 public static final String FOR = "for"; 66 public static final String ALL = "all"; 67 public static final String ATTRNAME = "attr.name"; 68 public static final String ATTRTYPE = "attr.type"; 69 public static final String DEFAULT = "default"; 70 71 public static final String NODE = "node"; 72 public static final String EDGE = "edge"; 73 public static final String SOURCE = "source"; 74 public static final String TARGET = "target"; 75 public static final String DATA = "data"; 76 public static final String TYPE = "type"; 77 78 public static final String INT = "int"; 79 public static final String INTEGER = "integer"; 80 public static final String LONG = "long"; 81 public static final String FLOAT = "float"; 82 public static final String DOUBLE = "double"; 83 public static final String REAL = "real"; 84 public static final String BOOLEAN = "boolean"; 85 public static final String STRING = "string"; 86 public static final String DATE = "date"; 87 } 88 89 92 public static class GraphMLHandler extends DefaultHandler implements Tokens 93 { 94 protected ParserFactory m_pf = ParserFactory.getDefaultFactory(); 95 96 protected static final String SRC = Graph.DEFAULT_SOURCE_KEY; 97 protected static final String TRG = Graph.DEFAULT_TARGET_KEY; 98 protected static final String SRCID = SRC+'_'+ID; 99 protected static final String TRGID = TRG+'_'+ID; 100 101 protected Schema m_nsch = new Schema(); 102 protected Schema m_esch = new Schema(); 103 104 protected String m_graphid; 105 protected Graph m_graph = null; 106 protected Table m_nodes; 107 protected Table m_edges; 108 109 protected String m_id; 111 protected String m_for; 112 protected String m_name; 113 protected String m_type; 114 protected String m_dflt; 115 116 protected StringBuffer m_sbuf = new StringBuffer (); 117 118 private String m_key; 120 private int m_row = -1; 121 private Table m_table = null; 122 protected HashMap m_nodeMap = new HashMap (); 123 protected HashMap m_idMap = new HashMap (); 124 125 private boolean m_directed = false; 126 private boolean inSchema; 127 128 public void startDocument() { 129 m_nodeMap.clear(); 130 inSchema = true; 131 132 m_esch.addColumn(SRC, int.class); 133 m_esch.addColumn(TRG, int.class); 134 m_esch.addColumn(SRCID, String .class); 135 m_esch.addColumn(TRGID, String .class); 136 } 137 138 public void endDocument() throws SAXException { 139 IntIterator rows = m_edges.rows(); 141 while (rows.hasNext()) { 142 int r = rows.nextInt(); 143 144 String src = m_edges.getString(r, SRCID); 145 if (!m_nodeMap.containsKey(src)) { 146 throw new SAXException ( 147 "Tried to create edge with source node id=" + src 148 + " which does not exist."); 149 } 150 int s = ((Integer ) m_nodeMap.get(src)).intValue(); 151 m_edges.setInt(r, SRC, s); 152 153 String trg = m_edges.getString(r, TRGID); 154 if (!m_nodeMap.containsKey(trg)) { 155 throw new SAXException ( 156 "Tried to create edge with target node id=" + trg 157 + " which does not exist."); 158 } 159 int t = ((Integer ) m_nodeMap.get(trg)).intValue(); 160 m_edges.setInt(r, TRG, t); 161 } 162 m_edges.removeColumn(SRCID); 163 m_edges.removeColumn(TRGID); 164 165 m_graph = new Graph(m_nodes, m_edges, m_directed); 167 if (m_graphid != null) 168 m_graph.putClientProperty(ID, m_graphid); 169 } 170 171 public void startElement(String namespaceURI, String localName, 172 String qName, Attributes atts) 173 { 174 m_sbuf.delete(0, m_sbuf.length()); 176 177 if ( qName.equals(GRAPH) ) 178 { 179 String edef = atts.getValue(EDGEDEF); 181 m_directed = DIRECTED.equalsIgnoreCase(edef); 182 m_graphid = atts.getValue(ID); 183 } 184 else if ( qName.equals(KEY) ) 185 { 186 if ( !inSchema ) { 187 error("\""+KEY+"\" elements can not" 188 + " occur after the first node or edge declaration."); 189 } 190 m_for = atts.getValue(FOR); 191 m_id = atts.getValue(ID); 192 m_name = atts.getValue(ATTRNAME); 193 m_type = atts.getValue(ATTRTYPE); 194 } 195 else if ( qName.equals(NODE) ) 196 { 197 schemaCheck(); 198 199 m_row = m_nodes.addRow(); 200 201 String id = atts.getValue(ID); 202 m_nodeMap.put(id, new Integer (m_row)); 203 m_table = m_nodes; 204 } 205 else if ( qName.equals(EDGE) ) 206 { 207 schemaCheck(); 208 209 m_row = m_edges.addRow(); 210 211 m_edges.setString(m_row, SRCID, atts.getValue(SRC)); 219 m_edges.setString(m_row, TRGID, atts.getValue(TRG)); 220 221 m_table = m_edges; 230 } 231 else if ( qName.equals(DATA) ) 232 { 233 m_key = atts.getValue(KEY); 234 } 235 } 236 237 public void endElement(String namespaceURI, 238 String localName, String qName) 239 { 240 if ( qName.equals(DEFAULT) ) { 241 m_dflt = m_sbuf.toString(); 243 } 244 else if ( qName.equals(KEY) ) { 245 addToSchema(); 247 } 248 else if ( qName.equals(DATA) ) { 249 String value = m_sbuf.toString(); 251 String name = (String )m_idMap.get(m_key); 252 Class type = m_table.getColumnType(name); 253 try { 254 Object val = parse(value, type); 255 m_table.set(m_row, name, val); 256 } catch ( DataParseException dpe ) { 257 error(dpe); 258 } 259 } 260 else if ( qName.equals(NODE) || qName.equals(EDGE) ) { 261 m_row = -1; 262 m_table = null; 263 } 264 } 265 266 public void characters(char[] ch, int start, int length) throws SAXException { 267 m_sbuf.append(ch, start, length); 268 } 269 270 272 protected void schemaCheck() { 273 if ( inSchema ) { 274 m_nsch.lockSchema(); 275 m_esch.lockSchema(); 276 m_nodes = m_nsch.instantiate(); 277 m_edges = m_esch.instantiate(); 278 inSchema = false; 279 } 280 } 281 282 protected void addToSchema() { 283 if ( m_name == null || m_name.length() == 0 ) 284 error("Empty "+KEY+" name."); 285 if ( m_type == null || m_type.length() == 0 ) 286 error("Empty "+KEY+" type."); 287 288 try { 289 Class type = parseType(m_type); 290 Object dflt = m_dflt==null ? null : parse(m_dflt, type); 291 292 if ( m_for == null || m_for.equals(ALL) ) { 293 m_nsch.addColumn(m_name, type, dflt); 294 m_esch.addColumn(m_name, type, dflt); 295 } else if ( m_for.equals(NODE) ) { 296 m_nsch.addColumn(m_name, type, dflt); 297 } else if ( m_for.equals(EDGE) ) { 298 m_esch.addColumn(m_name, type, dflt); 299 } else { 300 error("Unrecognized \""+FOR+"\" value: "+ m_for); 301 } 302 m_idMap.put(m_id, m_name); 303 304 m_dflt = null; 305 } catch ( DataParseException dpe ) { 306 error(dpe); 307 } 308 } 309 310 protected Class parseType(String type) { 311 type = type.toLowerCase(); 312 if ( type.equals(INT) || type.equals(INTEGER) ) { 313 return int.class; 314 } else if ( type.equals(LONG) ) { 315 return long.class; 316 } else if ( type.equals(FLOAT) ) { 317 return float.class; 318 } else if ( type.equals(DOUBLE) || type.equals(REAL)) { 319 return double.class; 320 } else if ( type.equals(BOOLEAN) ) { 321 return boolean.class; 322 } else if ( type.equals(STRING) ) { 323 return String .class; 324 } else if ( type.equals(DATE) ) { 325 return Date .class; 326 } else { 327 error("Unrecognized data type: "+type); 328 return null; 329 } 330 } 331 332 protected Object parse(String s, Class type) 333 throws DataParseException 334 { 335 DataParser dp = m_pf.getParser(type); 336 return dp.parse(s); 337 } 338 339 public Graph getGraph() { 340 return m_graph; 341 } 342 343 protected void error(String s) { 344 throw new RuntimeException (s); 345 } 346 347 protected void error(Exception e) { 348 throw new RuntimeException (e); 349 } 350 351 } 353 } | Popular Tags |