View Javadoc
1   /*
2    * Copyright (c) 2008, The JUNG Authors
3    *
4    * All rights reserved.
5    *
6    * This software is open-source under the BSD license; see either
7    * "license.txt" or
8    * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
9    */
10  
11  package edu.uci.ics.jung.io.graphml.parser;
12  
13  import java.util.ArrayList;
14  import java.util.Collection;
15  import java.util.HashMap;
16  import java.util.Iterator;
17  import java.util.LinkedList;
18  import java.util.List;
19  import java.util.Map;
20  
21  import javax.xml.stream.XMLEventReader;
22  import javax.xml.stream.events.Attribute;
23  import javax.xml.stream.events.EndElement;
24  import javax.xml.stream.events.StartElement;
25  import javax.xml.stream.events.XMLEvent;
26  
27  import edu.uci.ics.jung.graph.Graph;
28  import edu.uci.ics.jung.graph.Hypergraph;
29  import edu.uci.ics.jung.graph.util.EdgeType;
30  import edu.uci.ics.jung.graph.util.Pair;
31  import edu.uci.ics.jung.io.GraphIOException;
32  import edu.uci.ics.jung.io.graphml.*;
33  import edu.uci.ics.jung.io.graphml.GraphMetadata.EdgeDefault;
34  
35  /**
36   * Parses graph elements.
37   *
38   * @author Nathan Mittler - nathan.mittler@gmail.com
39   */
40  public class GraphElementParser<G extends Hypergraph<V,E>,V,E> extends AbstractElementParser<G,V,E> {
41  
42      public GraphElementParser(ParserContext<G,V,E> parserContext) {
43          super(parserContext);
44      }
45  
46      public GraphMetadata parse(XMLEventReader xmlEventReader, StartElement start)
47              throws GraphIOException {
48  
49          try {
50              // Create the new graph.
51              GraphMetadata graphMetadata = new GraphMetadata();
52  
53              // Parse the attributes.
54              @SuppressWarnings("unchecked")
55              Iterator<Attribute> iterator = start.getAttributes();
56              while (iterator.hasNext()) {
57                  Attribute attribute = iterator.next();
58                  String name = attribute.getName().getLocalPart();
59                  String value = attribute.getValue();
60                  if (graphMetadata.getId() == null
61                          && GraphMLConstants.ID_NAME.equals(name)) {
62                      
63                      graphMetadata.setId(value);
64                  } else if (graphMetadata.getEdgeDefault() == null
65                          && GraphMLConstants.EDGEDEFAULT_NAME.equals(name)) {
66                      
67                      graphMetadata.setEdgeDefault(GraphMLConstants.DIRECTED_NAME
68                              .equals(value) ? EdgeDefault.DIRECTED
69                              : EdgeDefault.UNDIRECTED);
70                  } else {
71                      graphMetadata.setProperty(name, value);
72                  }
73              }
74  
75              // Make sure the graphdefault has been set.
76              if (graphMetadata.getEdgeDefault() == null) {
77                  throw new GraphIOException(
78                          "Element 'graph' is missing attribute 'edgedefault'");
79              }
80              
81              Map<String, V> idToVertexMap = new HashMap<String, V>();
82              Collection<EdgeMetadata> edgeMetadata = new LinkedList<EdgeMetadata>();
83              Collection<HyperEdgeMetadata> hyperEdgeMetadata = new LinkedList<HyperEdgeMetadata>();
84  
85              while (xmlEventReader.hasNext()) {
86  
87                  XMLEvent event = xmlEventReader.nextEvent();
88                  if (event.isStartElement()) {
89                      StartElement element = (StartElement) event;
90  
91                      String name = element.getName().getLocalPart();
92                      if (GraphMLConstants.DESC_NAME.equals(name)) {
93                          
94                          // Parse the description and set it in the graph.
95                          String desc = (String) getParser(name).parse(
96                                  xmlEventReader, element);
97                          graphMetadata.setDescription(desc);
98                          
99                      } else if (GraphMLConstants.DATA_NAME.equals(name)) {
100                         
101                         // Parse the data element and store the property in the graph.
102                         DataMetadata data = (DataMetadata) getParser(name).parse(
103                                 xmlEventReader, element);
104                         graphMetadata.addData(data);
105                         
106                     } else if (GraphMLConstants.NODE_NAME.equals(name)) {
107                         
108                         // Parse the node metadata
109                         NodeMetadata metadata = (NodeMetadata) getParser(name).parse(
110                                 xmlEventReader, element);
111                         
112                         // Create the vertex object and store it in the metadata
113                         V vertex = getParserContext().createVertex(metadata);
114                         metadata.setVertex(vertex);
115                         idToVertexMap.put(metadata.getId(), vertex);
116                         
117                         // Add it to the graph
118                         graphMetadata.addNodeMetadata(vertex, metadata);
119                         
120                     } else if (GraphMLConstants.EDGE_NAME.equals(name)) {
121                         
122                         // Parse the edge metadata
123                         EdgeMetadata metadata = (EdgeMetadata) getParser(name).parse(
124                                 xmlEventReader, element);
125                         
126                         // Set the directed property if not overridden.
127                         if (metadata.isDirected() == null) {
128                             metadata.setDirected(graphMetadata.getEdgeDefault() == EdgeDefault.DIRECTED);
129                         }
130                         
131                         // Create the edge object and store it in the metadata
132                         E edge = getParserContext().createEdge(metadata);
133                         edgeMetadata.add(metadata);
134                         metadata.setEdge(edge);
135                         
136                         // Add it to the graph.
137                         graphMetadata.addEdgeMetadata(edge, metadata);
138                         
139                     } else if (GraphMLConstants.HYPEREDGE_NAME.equals(name)) {
140                         
141                         // Parse the edge metadata
142                         HyperEdgeMetadata metadata = (HyperEdgeMetadata) getParser(name).parse(
143                                 xmlEventReader, element);
144                         
145                         // Create the edge object and store it in the metadata
146                         E edge = getParserContext().createHyperEdge(metadata);
147                         hyperEdgeMetadata.add(metadata);
148                         metadata.setEdge(edge);
149                         
150                         // Add it to the graph
151                         graphMetadata.addHyperEdgeMetadata(edge, metadata);
152                         
153                     } else {
154 
155                         // Treat anything else as unknown
156                         getUnknownParser().parse(xmlEventReader, element);
157                     }
158 
159                 }
160                 if (event.isEndElement()) {
161                     EndElement end = (EndElement) event;
162                     verifyMatch(start, end);
163                     break;
164                 }
165             }
166             
167             // Apply the keys to this object.
168             applyKeys(graphMetadata);   
169             
170             // Create the graph object and store it in the metadata
171             G graph = getParserContext().createGraph(graphMetadata);
172             graphMetadata.setGraph(graph);
173             
174             // Add all of the vertices to the graph object.
175             addVerticesToGraph(graph, idToVertexMap.values());
176             
177             // Add the edges to the graph object.
178             addEdgesToGraph(graph, edgeMetadata, idToVertexMap);
179             addHyperEdgesToGraph(graph, hyperEdgeMetadata, idToVertexMap);
180 
181             return graphMetadata;
182 
183         } catch (Exception e) {
184             ExceptionConverter.convert(e);
185         }
186 
187         return null;
188     }
189     
190     private void addVerticesToGraph(G graph, Collection<V> vertices) {
191         
192         for (V vertex : vertices) {
193             graph.addVertex(vertex);
194         }
195     }
196     
197     @SuppressWarnings("unchecked")
198     private void addEdgesToGraph(G graph, Collection<EdgeMetadata> metadata, 
199             Map<String,V> idToVertexMap) throws GraphIOException {
200         
201         for (EdgeMetadata emd : metadata) {
202 
203             // Get the edge out of the metadata
204             E edge = (E)emd.getEdge();
205             
206             // Get the verticies.
207             V source = idToVertexMap.get(emd.getSource());
208             V target = idToVertexMap.get(emd.getTarget());
209             if (source == null || target == null) {
210                 throw new GraphIOException(
211                         "edge references undefined source or target vertex. "
212                                 + "Source: " + emd.getSource()
213                                 + ", Target: " + emd.getTarget());
214             }
215 
216             // Add it to the graph.
217             if (graph instanceof Graph) {
218                 ((Graph<V, E>) graph).addEdge(edge, source, target, emd
219                         .isDirected() ? EdgeType.DIRECTED
220                         : EdgeType.UNDIRECTED);
221             } else {
222                 graph.addEdge(edge, new Pair<V>(source, target));
223             }
224         }
225     }
226     
227     @SuppressWarnings("unchecked")
228     private void addHyperEdgesToGraph(G graph, Collection<HyperEdgeMetadata> metadata, 
229             Map<String,V> idToVertexMap) throws GraphIOException {
230         
231         for (HyperEdgeMetadata emd : metadata) {
232 
233             // Get the edge out of the metadata
234             E edge = (E)emd.getEdge();
235             
236             // Add the verticies to a list.
237             List<V> verticies = new ArrayList<V>();
238             List<EndpointMetadata> endpoints = emd.getEndpoints();
239             for (EndpointMetadata ep : endpoints) {
240                 V v = idToVertexMap.get(ep.getNode());
241                 if (v == null) {
242                     throw new GraphIOException(
243                             "hyperedge references undefined vertex: "
244                                     + ep.getNode());
245                 }
246                 verticies.add(v);
247             }
248 
249             // Add it to the graph.
250             graph.addEdge(edge, verticies);
251         }
252     }
253 }