All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.io.GraphMLExporter Maven / Gradle / Ivy

There is a newer version: 1.5.2
Show newest version
/*
 * (C) Copyright 2006-2017, by Trevor Harmon, Dimitrios Michail and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * This program and the accompanying materials are dual-licensed under
 * either
 *
 * (a) the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation, or (at your option) any
 * later version.
 *
 * or (per the licensee's choosing)
 *
 * (b) the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation.
 */
package org.jgrapht.io;

import java.io.*;
import java.util.*;
import java.util.Map.*;

import javax.xml.transform.*;
import javax.xml.transform.sax.*;
import javax.xml.transform.stream.*;

import org.jgrapht.*;
import org.xml.sax.*;
import org.xml.sax.helpers.*;

/**
 * Exports a graph as GraphML.
 *
 * 

* For a description of the format see * http://en.wikipedia.org/wiki/ GraphML. *

* * @param the graph vertex type * @param the graph edge type * * @author Trevor Harmon * @author Dimitrios Michail */ public class GraphMLExporter extends AbstractBaseExporter implements GraphExporter { // providers private ComponentNameProvider vertexLabelProvider; private ComponentNameProvider edgeLabelProvider; private ComponentAttributeProvider vertexAttributeProvider; private ComponentAttributeProvider edgeAttributeProvider; // registered attributes private Map registeredAttributes = new LinkedHashMap<>(); private static final String ATTRIBUTE_KEY_PREFIX = "key"; private int totalAttributes = 0; // special attributes private static final String VERTEX_LABEL_DEFAULT_ATTRIBUTE_NAME = "VertexLabel"; private static final String EDGE_WEIGHT_DEFAULT_ATTRIBUTE_NAME = "weight"; private static final String EDGE_LABEL_DEFAULT_ATTRIBUTE_NAME = "EdgeLabel"; private String vertexLabelAttributeName = VERTEX_LABEL_DEFAULT_ATTRIBUTE_NAME; private String edgeWeightAttributeName = EDGE_WEIGHT_DEFAULT_ATTRIBUTE_NAME; private String edgeLabelAttributeName = EDGE_LABEL_DEFAULT_ATTRIBUTE_NAME; /** * Whether to print edge weights in case the graph is weighted. */ private boolean exportEdgeWeights = false; /** * Constructs a new GraphMLExporter with integer name providers for the vertex and edge * identifiers. */ public GraphMLExporter() { this( new IntegerComponentNameProvider<>(), null, null, new IntegerComponentNameProvider<>(), null, null); } /** * Constructs a new GraphMLExporter. * * @param vertexIDProvider for generating vertex identifiers. Must not be null. * @param vertexLabelProvider for generating vertex labels. If null, vertex labels will not * exported. * @param edgeIDProvider for generating edge identifiers. Must not be null. * @param edgeLabelProvider for generating edge labels. If null, edge labels will not be * exported. */ public GraphMLExporter( ComponentNameProvider vertexIDProvider, ComponentNameProvider vertexLabelProvider, ComponentNameProvider edgeIDProvider, ComponentNameProvider edgeLabelProvider) { this(vertexIDProvider, vertexLabelProvider, null, edgeIDProvider, edgeLabelProvider, null); } /** * Constructs a new GraphMLExporter. * * @param vertexIDProvider for generating vertex identifiers. Must not be null. * @param vertexLabelProvider for generating vertex labels. If null, vertex labels will not * exported. * @param vertexAttributeProvider for generating vertex attributes. If null, no additional * attributes will be exported. * @param edgeIDProvider for generating edge identifiers. Must not be null. * @param edgeLabelProvider for generating edge labels. If null, edge labels will not be * exported. * @param edgeAttributeProvider for generating edge attributes. If null, no additional * attributes will be exported. */ public GraphMLExporter( ComponentNameProvider vertexIDProvider, ComponentNameProvider vertexLabelProvider, ComponentAttributeProvider vertexAttributeProvider, ComponentNameProvider edgeIDProvider, ComponentNameProvider edgeLabelProvider, ComponentAttributeProvider edgeAttributeProvider) { super( vertexIDProvider, Objects.requireNonNull(edgeIDProvider, "Edge ID provider must not be null")); this.vertexLabelProvider = vertexLabelProvider; this.vertexAttributeProvider = vertexAttributeProvider; this.edgeLabelProvider = edgeLabelProvider; this.edgeAttributeProvider = edgeAttributeProvider; } /** * Denotes the category of a GraphML-Attribute. */ public enum AttributeCategory { GRAPH("graph"), NODE("node"), EDGE("edge"), ALL("all"); private String name; private AttributeCategory(String name) { this.name = name; } /** * Get a string representation of the attribute category * * @return the string representation of the attribute category */ public String toString() { return name; } } /** * Register a GraphML-Attribute * * @param name the attribute name * @param category the attribute category * @param type the attribute type */ public void registerAttribute(String name, AttributeCategory category, AttributeType type) { registerAttribute(name, category, type, null); } /** * Register a GraphML-Attribute * * @param name the attribute name * @param category the attribute category * @param type the attribute type * @param defaultValue default value */ public void registerAttribute( String name, AttributeCategory category, AttributeType type, String defaultValue) { if (name == null) { throw new IllegalArgumentException("Attribute name cannot be null"); } if (name.equals(vertexLabelAttributeName) || name.equals(edgeWeightAttributeName) || name.equals(edgeLabelAttributeName)) { throw new IllegalArgumentException("Reserved attribute name"); } if (category == null) { throw new IllegalArgumentException( "Attribute category must be one of node, edge, graph or all"); } String nextKey = ATTRIBUTE_KEY_PREFIX + (totalAttributes++); registeredAttributes.put(name, new AttributeDetails(nextKey, category, type, defaultValue)); } /** * Unregister a GraphML-Attribute * * @param name the attribute name */ public void unregisterAttribute(String name) { if (name == null) { throw new IllegalArgumentException("Attribute name cannot be null"); } if (name.equals(vertexLabelAttributeName) || name.equals(edgeWeightAttributeName) || name.equals(edgeLabelAttributeName)) { throw new IllegalArgumentException("Reserved attribute name"); } registeredAttributes.remove(name); } /** * Whether the exporter will print edge weights. * * @return {@code true} if the exporter prints edge weights, {@code false} otherwise */ public boolean isExportEdgeWeights() { return exportEdgeWeights; } /** * Set whether the exporter will print edge weights. * * @param exportEdgeWeights value to set */ public void setExportEdgeWeights(boolean exportEdgeWeights) { this.exportEdgeWeights = exportEdgeWeights; } /** * Get the attribute name for vertex labels * * @return the attribute name */ public String getVertexLabelAttributeName() { return vertexLabelAttributeName; } /** * Set the attribute name to use for vertex labels. * * @param vertexLabelAttributeName the attribute name */ public void setVertexLabelAttributeName(String vertexLabelAttributeName) { if (vertexLabelAttributeName == null) { throw new IllegalArgumentException("Vertex label attribute name cannot be null"); } String key = vertexLabelAttributeName.trim(); if (registeredAttributes.containsKey(key)) { throw new IllegalArgumentException("Reserved attribute name"); } this.vertexLabelAttributeName = key; } /** * Get the attribute name for edge labels * * @return the attribute name */ public String getEdgeLabelAttributeName() { return edgeLabelAttributeName; } /** * Set the attribute name to use for edge labels. * * @param edgeLabelAttributeName the attribute name */ public void setEdgeLabelAttributeName(String edgeLabelAttributeName) { if (edgeLabelAttributeName == null) { throw new IllegalArgumentException("Edge label attribute name cannot be null"); } String key = edgeLabelAttributeName.trim(); if (registeredAttributes.containsKey(key)) { throw new IllegalArgumentException("Reserved attribute name"); } this.edgeLabelAttributeName = key; } /** * Get the attribute name for edge weights * * @return the attribute name */ public String getEdgeWeightAttributeName() { return edgeWeightAttributeName; } /** * Set the attribute name to use for edge weights. * * @param edgeWeightAttributeName the attribute name */ public void setEdgeWeightAttributeName(String edgeWeightAttributeName) { if (edgeWeightAttributeName == null) { throw new IllegalArgumentException("Edge weight attribute name cannot be null"); } String key = edgeWeightAttributeName.trim(); if (registeredAttributes.containsKey(key)) { throw new IllegalArgumentException("Reserved attribute name"); } this.edgeWeightAttributeName = key; } /** * Get the vertex label provider * * @return the vertex label provider */ public ComponentNameProvider getVertexLabelProvider() { return vertexLabelProvider; } /** * Set the vertex label provider. * * @param vertexLabelProvider the vertex label provider to set */ public void setVertexLabelProvider(ComponentNameProvider vertexLabelProvider) { this.vertexLabelProvider = vertexLabelProvider; } /** * Get the edge label provider * * @return the edge label provider */ public ComponentNameProvider getEdgeLabelProvider() { return edgeLabelProvider; } /** * Set the edge label provider. * * @param edgeLabelProvider the edge label provider to set */ public void setEdgeLabelProvider(ComponentNameProvider edgeLabelProvider) { this.edgeLabelProvider = edgeLabelProvider; } /** * Get the vertex attribute provider * * @return the vertex attribute provider */ public ComponentAttributeProvider getVertexAttributeProvider() { return vertexAttributeProvider; } /** * Set the vertex attribute provider. * * @param vertexAttributeProvider the vertex attribute provider to set */ public void setVertexAttributeProvider(ComponentAttributeProvider vertexAttributeProvider) { this.vertexAttributeProvider = vertexAttributeProvider; } /** * Get the edge attribute provider * * @return the edge attribute provider */ public ComponentAttributeProvider getEdgeAttributeProvider() { return edgeAttributeProvider; } /** * Set the edge attribute provider. * * @param edgeAttributeProvider the edge attribute provider to set */ public void setEdgeAttributeProvider(ComponentAttributeProvider edgeAttributeProvider) { this.edgeAttributeProvider = edgeAttributeProvider; } /** * Exports a graph in GraphML format. * * @param g the graph * @param writer the writer to export the graph * @throws ExportException in case any error occurs during export */ @Override public void exportGraph(Graph g, Writer writer) throws ExportException { try { // Prepare an XML file to receive the GraphML data SAXTransformerFactory factory = (SAXTransformerFactory) SAXTransformerFactory.newInstance(); TransformerHandler handler = factory.newTransformerHandler(); handler.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8"); handler.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes"); handler.setResult(new StreamResult(new PrintWriter(writer))); // export handler.startDocument(); writeHeader(handler); writeKeys(handler); writeGraphStart(handler, g); writeNodes(handler, g); writeEdges(handler, g); writeGraphEnd(handler); writeFooter(handler); handler.endDocument(); // flush writer.flush(); } catch (Exception e) { throw new ExportException("Failed to export as GraphML", e); } } private void writeHeader(TransformerHandler handler) throws SAXException { handler.startPrefixMapping("xsi", "http://www.w3.org/2001/XMLSchema-instance"); handler.endPrefixMapping("xsi"); AttributesImpl attr = new AttributesImpl(); attr.addAttribute( "", "", "xsi:schemaLocation", "CDATA", "http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd"); handler.startElement("http://graphml.graphdrawing.org/xmlns", "", "graphml", attr); } private void writeGraphStart(TransformerHandler handler, Graph g) throws SAXException { // AttributesImpl attr = new AttributesImpl(); attr.addAttribute( "", "", "edgedefault", "CDATA", g.getType().isDirected() ? "directed" : "undirected"); handler.startElement("", "", "graph", attr); } private void writeGraphEnd(TransformerHandler handler) throws SAXException { handler.endElement("", "", "graph"); } private void writeFooter(TransformerHandler handler) throws SAXException { handler.endElement("", "", "graphml"); } private void writeKeys(TransformerHandler handler) throws SAXException { if (vertexLabelProvider != null) { writeAttribute( handler, vertexLabelAttributeName, new AttributeDetails( "vertex_label_key", AttributeCategory.NODE, AttributeType.STRING, null)); } if (edgeLabelProvider != null) { writeAttribute( handler, edgeLabelAttributeName, new AttributeDetails( "edge_label_key", AttributeCategory.EDGE, AttributeType.STRING, null)); } if (exportEdgeWeights) { writeAttribute( handler, edgeWeightAttributeName, new AttributeDetails( "edge_weight_key", AttributeCategory.EDGE, AttributeType.DOUBLE, Double.toString(Graph.DEFAULT_EDGE_WEIGHT))); } for (String attributeName : registeredAttributes.keySet()) { AttributeDetails details = registeredAttributes.get(attributeName); writeAttribute(handler, attributeName, details); } } private void writeData(TransformerHandler handler, String key, String value) throws SAXException { AttributesImpl attr = new AttributesImpl(); attr.addAttribute("", "", "key", "CDATA", key); handler.startElement("", "", "data", attr); handler.characters(value.toCharArray(), 0, value.length()); handler.endElement("", "", "data"); } private void writeAttribute(TransformerHandler handler, String name, AttributeDetails details) throws SAXException { AttributesImpl attr = new AttributesImpl(); attr.addAttribute("", "", "id", "CDATA", details.key); attr.addAttribute("", "", "for", "CDATA", details.category.toString()); attr.addAttribute("", "", "attr.name", "CDATA", name); attr.addAttribute("", "", "attr.type", "CDATA", details.type.toString()); handler.startElement("", "", "key", attr); if (details.defaultValue != null) { handler.startElement("", "", "default", null); handler .characters(details.defaultValue.toCharArray(), 0, details.defaultValue.length()); handler.endElement("", "", "default"); } handler.endElement("", "", "key"); } private void writeNodes(TransformerHandler handler, Graph g) throws SAXException { // Add all the vertices as elements... for (V v : g.vertexSet()) { // AttributesImpl attr = new AttributesImpl(); attr.addAttribute("", "", "id", "CDATA", vertexIDProvider.getName(v)); handler.startElement("", "", "node", attr); if (vertexLabelProvider != null) { String vertexLabel = vertexLabelProvider.getName(v); if (vertexLabel != null) { writeData(handler, "vertex_label_key", vertexLabel); } } // find vertex attributes Map vertexAttributes = null; if (vertexAttributeProvider != null) { vertexAttributes = vertexAttributeProvider.getComponentAttributes(v); } if (vertexAttributes == null) { vertexAttributes = Collections.emptyMap(); } // check all registered for (Entry e : registeredAttributes.entrySet()) { AttributeDetails details = e.getValue(); if (details.category.equals(AttributeCategory.NODE) || details.category.equals(AttributeCategory.ALL)) { String name = e.getKey(); String defaultValue = details.defaultValue; if (vertexAttributes.containsKey(name)) { Attribute attribute = vertexAttributes.get(name); String value = attribute.getValue(); if (defaultValue == null || !defaultValue.equals(value)) { if (value != null) { writeData(handler, details.key, value); } } } } } handler.endElement("", "", "node"); } } private void writeEdges(TransformerHandler handler, Graph g) throws SAXException { // Add all the edges as elements... for (E e : g.edgeSet()) { // AttributesImpl attr = new AttributesImpl(); attr.addAttribute("", "", "id", "CDATA", edgeIDProvider.getName(e)); attr.addAttribute( "", "", "source", "CDATA", vertexIDProvider.getName(g.getEdgeSource(e))); attr.addAttribute( "", "", "target", "CDATA", vertexIDProvider.getName(g.getEdgeTarget(e))); handler.startElement("", "", "edge", attr); if (edgeLabelProvider != null) { String edgeLabel = edgeLabelProvider.getName(e); if (edgeLabel != null) { writeData(handler, "edge_label_key", edgeLabel); } } if (exportEdgeWeights) { Double weight = g.getEdgeWeight(e); if (!weight.equals(Graph.DEFAULT_EDGE_WEIGHT)) { // not // default // value writeData(handler, "edge_weight_key", String.valueOf(weight)); } } // find edge attributes Map edgeAttributes = null; if (edgeAttributeProvider != null) { edgeAttributes = edgeAttributeProvider.getComponentAttributes(e); } if (edgeAttributes == null) { edgeAttributes = Collections.emptyMap(); } // check all registered for (Entry entry : registeredAttributes.entrySet()) { AttributeDetails details = entry.getValue(); if (details.category.equals(AttributeCategory.EDGE) || details.category.equals(AttributeCategory.ALL)) { String name = entry.getKey(); String defaultValue = details.defaultValue; if (edgeAttributes.containsKey(name)) { Attribute attribute = edgeAttributes.get(name); String value = attribute.getValue(); if (defaultValue == null || !defaultValue.equals(value)) { if (value != null) { writeData(handler, details.key, value); } } } } } handler.endElement("", "", "edge"); } } private class AttributeDetails { public String key; public AttributeCategory category; public AttributeType type; public String defaultValue; public AttributeDetails( String key, AttributeCategory category, AttributeType type, String defaultValue) { this.key = key; this.category = category; this.type = type; this.defaultValue = defaultValue; } } } // End GraphMLExporter.java




© 2015 - 2024 Weber Informatics LLC | Privacy Policy