1
2
3
4
5
6
7
8
9
10
11
12 package edu.uci.ics.jung.io;
13
14 import java.io.BufferedWriter;
15 import java.io.IOException;
16 import java.io.Writer;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.HashMap;
20 import java.util.Map;
21
22 import com.google.common.base.Function;
23 import com.google.common.base.Functions;
24
25 import edu.uci.ics.jung.graph.Graph;
26 import edu.uci.ics.jung.graph.Hypergraph;
27 import edu.uci.ics.jung.graph.UndirectedGraph;
28 import edu.uci.ics.jung.graph.util.EdgeType;
29 import edu.uci.ics.jung.graph.util.Pair;
30
31
32
33
34
35
36
37
38
39
40
41 public class GraphMLWriter<V,E>
42 {
43 protected Function<? super V, String> vertex_ids;
44 protected Function<? super E, String> edge_ids;
45 protected Map<String, GraphMLMetadata<Hypergraph<V,E>>> graph_data;
46 protected Map<String, GraphMLMetadata<V>> vertex_data;
47 protected Map<String, GraphMLMetadata<E>> edge_data;
48 protected Function<? super V, String> vertex_desc;
49 protected Function<? super E, String> edge_desc;
50 protected Function<? super Hypergraph<V,E>, String> graph_desc;
51 protected boolean directed;
52 protected int nest_level;
53
54 public GraphMLWriter()
55 {
56 vertex_ids = new Function<V,String>()
57 {
58 public String apply(V v)
59 {
60 return v.toString();
61 }
62 };
63 edge_ids = Functions.constant(null);
64 graph_data = Collections.emptyMap();
65 vertex_data = Collections.emptyMap();
66 edge_data = Collections.emptyMap();
67 vertex_desc = Functions.constant(null);
68 edge_desc = Functions.constant(null);
69 graph_desc = Functions.constant(null);
70 nest_level = 0;
71 }
72
73
74
75
76
77
78
79
80 public void save(Hypergraph<V,E> graph, Writer w) throws IOException
81 {
82 BufferedWriter bw = new BufferedWriter(w);
83
84
85 bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
86 bw.write("<graphml xmlns=\"http://graphml.graphdrawing.org/xmlns/graphml\"\n" +
87 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n");
88 bw.write("xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns/graphml\">\n");
89
90
91 for (String key : graph_data.keySet())
92 writeKeySpecification(key, "graph", graph_data.get(key), bw);
93 for (String key : vertex_data.keySet())
94 writeKeySpecification(key, "node", vertex_data.get(key), bw);
95 for (String key : edge_data.keySet())
96 writeKeySpecification(key, "edge", edge_data.get(key), bw);
97
98
99
100 bw.write("<graph edgedefault=\"");
101 directed = !(graph instanceof UndirectedGraph);
102 if (directed)
103 bw.write("directed\">\n");
104 else
105 bw.write("undirected\">\n");
106
107
108 String desc = graph_desc.apply(graph);
109 if (desc != null)
110 bw.write("<desc>" + desc + "</desc>\n");
111
112
113 for (String key : graph_data.keySet())
114 {
115 Function<Hypergraph<V,E>, ?> t = graph_data.get(key).transformer;
116 Object value = t.apply(graph);
117 if (value != null)
118 bw.write(format("data", "key", key, value.toString()) + "\n");
119 }
120
121
122 writeVertexData(graph, bw);
123
124
125 writeEdgeData(graph, bw);
126
127
128 bw.write("</graph>\n");
129 bw.write("</graphml>\n");
130 bw.flush();
131
132 bw.close();
133 }
134
135
136
137
138
139
140 protected void writeIndentedText(BufferedWriter w, String to_write) throws IOException
141 {
142 for (int i = 0; i < nest_level; i++)
143 w.write(" ");
144 w.write(to_write);
145 }
146
147 protected void writeVertexData(Hypergraph<V,E> graph, BufferedWriter w) throws IOException
148 {
149 for (V v: graph.getVertices())
150 {
151 String v_string = String.format("<node id=\"%s\"", vertex_ids.apply(v));
152 boolean closed = false;
153
154 String desc = vertex_desc.apply(v);
155 if (desc != null)
156 {
157 w.write(v_string + ">\n");
158 closed = true;
159 w.write("<desc>" + desc + "</desc>\n");
160 }
161
162 for (String key : vertex_data.keySet())
163 {
164 Function<V, ?> t = vertex_data.get(key).transformer;
165 if (t != null)
166 {
167 Object value = t.apply(v);
168 if (value != null)
169 {
170 if (!closed)
171 {
172 w.write(v_string + ">\n");
173 closed = true;
174 }
175 w.write(format("data", "key", key, value.toString()) + "\n");
176 }
177 }
178 }
179 if (!closed)
180 w.write(v_string + "/>\n");
181 else
182 w.write("</node>\n");
183 }
184 }
185
186 protected void writeEdgeData(Hypergraph<V,E> g, Writer w) throws IOException
187 {
188 for (E e: g.getEdges())
189 {
190 Collection<V> vertices = g.getIncidentVertices(e);
191 String id = edge_ids.apply(e);
192 String e_string;
193 boolean is_hyperedge = !(g instanceof Graph);
194 if (is_hyperedge)
195 {
196 e_string = "<hyperedge ";
197
198 if (id != null)
199 e_string += "id=\"" + id + "\" ";
200 }
201 else
202 {
203 Pair<V> endpoints = new Pair<V>(vertices);
204 V v1 = endpoints.getFirst();
205 V v2 = endpoints.getSecond();
206 e_string = "<edge ";
207
208 if (id != null)
209 e_string += "id=\"" + id + "\" ";
210
211 EdgeType edge_type = g.getEdgeType(e);
212 if (directed && edge_type == EdgeType.UNDIRECTED)
213 e_string += "directed=\"false\" ";
214 if (!directed && edge_type == EdgeType.DIRECTED)
215 e_string += "directed=\"true\" ";
216 e_string += "source=\"" + vertex_ids.apply(v1) +
217 "\" target=\"" + vertex_ids.apply(v2) + "\"";
218 }
219
220 boolean closed = false;
221
222 String desc = edge_desc.apply(e);
223 if (desc != null)
224 {
225 w.write(e_string + ">\n");
226 closed = true;
227 w.write("<desc>" + desc + "</desc>\n");
228 }
229
230 for (String key : edge_data.keySet())
231 {
232 Function<E, ?> t = edge_data.get(key).transformer;
233 Object value = t.apply(e);
234 if (value != null)
235 {
236 if (!closed)
237 {
238 w.write(e_string + ">\n");
239 closed = true;
240 }
241 w.write(format("data", "key", key, value.toString()) + "\n");
242 }
243 }
244
245 if (is_hyperedge)
246 {
247 for (V v : vertices)
248 {
249 if (!closed)
250 {
251 w.write(e_string + ">\n");
252 closed = true;
253 }
254 w.write("<endpoint node=\"" + vertex_ids.apply(v) + "\"/>\n");
255 }
256 }
257
258 if (!closed)
259 w.write(e_string + "/>\n");
260 else
261 if (is_hyperedge)
262 w.write("</hyperedge>\n");
263 else
264 w.write("</edge>\n");
265 }
266 }
267
268 protected void writeKeySpecification(String key, String type,
269 GraphMLMetadata<?> ds, BufferedWriter bw) throws IOException
270 {
271 bw.write("<key id=\"" + key + "\" for=\"" + type + "\"");
272 boolean closed = false;
273
274 String desc = ds.description;
275 if (desc != null)
276 {
277 if (!closed)
278 {
279 bw.write(">\n");
280 closed = true;
281 }
282 bw.write("<desc>" + desc + "</desc>\n");
283 }
284
285 Object def = ds.default_value;
286 if (def != null)
287 {
288 if (!closed)
289 {
290 bw.write(">\n");
291 closed = true;
292 }
293 bw.write("<default>" + def.toString() + "</default>\n");
294 }
295 if (!closed)
296 bw.write("/>\n");
297 else
298 bw.write("</key>\n");
299 }
300
301 protected String format(String type, String attr, String value, String contents)
302 {
303 return String.format("<%s %s=\"%s\">%s</%s>",
304 type, attr, value, contents, type);
305 }
306
307
308
309
310
311
312
313
314
315 public void setVertexIDs(Function<V, String> vertex_ids)
316 {
317 this.vertex_ids = vertex_ids;
318 }
319
320
321
322
323
324
325
326
327
328 public void setEdgeIDs(Function<E, String> edge_ids)
329 {
330 this.edge_ids = edge_ids;
331 }
332
333
334
335
336
337
338 public void setGraphData(Map<String, GraphMLMetadata<Hypergraph<V,E>>> graph_map)
339 {
340 graph_data = graph_map;
341 }
342
343
344
345
346
347
348 public void setVertexData(Map<String, GraphMLMetadata<V>> vertex_map)
349 {
350 vertex_data = vertex_map;
351 }
352
353
354
355
356
357
358 public void setEdgeData(Map<String, GraphMLMetadata<E>> edge_map)
359 {
360 edge_data = edge_map;
361 }
362
363
364
365
366
367
368
369
370
371 public void addGraphData(String id, String description, String default_value,
372 Function<Hypergraph<V,E>, String> graph_transformer)
373 {
374 if (graph_data.equals(Collections.EMPTY_MAP))
375 graph_data = new HashMap<String, GraphMLMetadata<Hypergraph<V,E>>>();
376 graph_data.put(id, new GraphMLMetadata<Hypergraph<V,E>>(description,
377 default_value, graph_transformer));
378 }
379
380
381
382
383
384
385
386
387
388 public void addVertexData(String id, String description, String default_value,
389 Function<V, String> vertex_transformer)
390 {
391 if (vertex_data.equals(Collections.EMPTY_MAP))
392 vertex_data = new HashMap<String, GraphMLMetadata<V>>();
393 vertex_data.put(id, new GraphMLMetadata<V>(description, default_value,
394 vertex_transformer));
395 }
396
397
398
399
400
401
402
403
404
405 public void addEdgeData(String id, String description, String default_value,
406 Function<E, String> edge_transformer)
407 {
408 if (edge_data.equals(Collections.EMPTY_MAP))
409 edge_data = new HashMap<String, GraphMLMetadata<E>>();
410 edge_data.put(id, new GraphMLMetadata<E>(description, default_value,
411 edge_transformer));
412 }
413
414
415
416
417
418 public void setVertexDescriptions(Function<V, String> vertex_desc)
419 {
420 this.vertex_desc = vertex_desc;
421 }
422
423
424
425
426
427 public void setEdgeDescriptions(Function<E, String> edge_desc)
428 {
429 this.edge_desc = edge_desc;
430 }
431
432
433
434
435
436 public void setGraphDescriptions(Function<Hypergraph<V,E>, String> graph_desc)
437 {
438 this.graph_desc = graph_desc;
439 }
440 }