[VIVO-1342] Use XML parser to generate valid GraphML files

This commit is contained in:
Graham Triggs 2017-07-14 14:57:16 +01:00
parent 38b95ccbd5
commit 9df0f009ed
2 changed files with 402 additions and 373 deletions

View file

@ -2,6 +2,8 @@
package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship; package edu.cornell.mannlib.vitro.webapp.visualization.coauthorship;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -16,44 +18,76 @@ import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.Collabo
import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaboratorComparator; import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaboratorComparator;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaboration; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaboration;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaborator; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaborator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
public class CoAuthorshipGraphMLWriter { public class CoAuthorshipGraphMLWriter {
private StringBuilder coAuthorshipGraphMLContent; private StringBuilder coAuthorshipGraphMLContent;
private final String GRAPHML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" private final String GRAPHML_NS = "http://graphml.graphdrawing.org/xmlns";
+ " <graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"\n"
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ " xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns\n"
+ " http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n\n";
private final String GRAPHML_FOOTER = "</graphml>";
public CoAuthorshipGraphMLWriter(CollaborationData visVOContainer) { public CoAuthorshipGraphMLWriter(CollaborationData visVOContainer) {
coAuthorshipGraphMLContent = createCoAuthorshipGraphMLContent(visVOContainer); coAuthorshipGraphMLContent = createCoAuthorshipGraphMLContent(visVOContainer);
} }
private StringBuilder createCoAuthorshipGraphMLContent( private StringBuilder createCoAuthorshipGraphMLContent(CollaborationData coAuthorshipData) {
CollaborationData coAuthorshipData) {
StringBuilder graphMLContent = new StringBuilder(); StringBuilder graphMLContent = new StringBuilder();
graphMLContent.append(GRAPHML_HEADER); try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
/* // root elements
* We are side-effecting "graphMLContent" object in this method since creating Document doc = docBuilder.newDocument();
* another String object to hold key definition data will be redundant & will doc.setXmlVersion("1.0");
* not serve the purpose. Element rootElement = doc.createElementNS(GRAPHML_NS, "graphml");
* */ doc.appendChild(rootElement);
generateKeyDefinitionContent(coAuthorshipData, graphMLContent);
/* /*
* Used to generate graph content. It will contain both the nodes & edge information. * We are side-effecting "graphMLContent" object in this method since creating
* We are side-effecting "graphMLContent". * another String object to hold key definition data will be redundant & will
* */ * not serve the purpose.
generateGraphContent(coAuthorshipData, graphMLContent); * */
generateKeyDefinitionContent(coAuthorshipData, rootElement);
graphMLContent.append(GRAPHML_FOOTER); /*
* Used to generate graph content. It will contain both the nodes & edge information.
* We are side-effecting "graphMLContent".
* */
generateGraphContent(coAuthorshipData, rootElement);
DOMSource source = new DOMSource(doc);
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
graphMLContent.append(writer.toString());
} catch (TransformerConfigurationException e) {
throw new IllegalStateException("XML error generating GraphML", e);
} catch (TransformerException e) {
throw new IllegalStateException("XML error generating GraphML", e);
} catch (ParserConfigurationException e) {
throw new IllegalStateException("XML error generating GraphML", e);
}
return graphMLContent; return graphMLContent;
} }
@ -62,118 +96,109 @@ public class CoAuthorshipGraphMLWriter {
return coAuthorshipGraphMLContent; return coAuthorshipGraphMLContent;
} }
private void generateGraphContent(CollaborationData coAuthorshipData, private void generateGraphContent(CollaborationData coAuthorshipData, Element rootElement) {
StringBuilder graphMLContent) { Document doc = rootElement.getOwnerDocument();
graphMLContent.append("\n<graph edgedefault=\"undirected\">\n"); Element graph = doc.createElementNS(GRAPHML_NS, "graph");
graph.setAttribute("edgedefault", "undirected");
rootElement.appendChild(graph);
if (coAuthorshipData.getCollaborators() != null if (coAuthorshipData.getCollaborators() != null && coAuthorshipData.getCollaborators().size() > 0) {
&& coAuthorshipData.getCollaborators().size() > 0) { generateNodeSectionContent(coAuthorshipData, graph);
generateNodeSectionContent(coAuthorshipData, graphMLContent);
} }
if (coAuthorshipData.getCollaborations() != null if (coAuthorshipData.getCollaborations() != null && coAuthorshipData.getCollaborations().size() > 0) {
&& coAuthorshipData.getCollaborations().size() > 0) { generateEdgeSectionContent(coAuthorshipData, graph);
generateEdgeSectionContent(coAuthorshipData, graphMLContent);
} }
graphMLContent.append("</graph>\n");
} }
private void generateEdgeSectionContent(CollaborationData coAuthorshipData, private void generateEdgeSectionContent(CollaborationData coAuthorshipData, Element graphElement) {
StringBuilder graphMLContent) { Document doc = graphElement.getOwnerDocument();
graphMLContent.append("<!-- edges -->\n"); graphElement.appendChild(doc.createComment("edges"));
Set<Collaboration> edges = coAuthorshipData.getCollaborations();
Set<Collaboration> edges = coAuthorshipData.getCollaborations();
List<Collaboration> orderedEdges = new ArrayList<Collaboration>(edges); List<Collaboration> orderedEdges = new ArrayList<Collaboration>(edges);
Collections.sort(orderedEdges, new CollaborationComparator()); Collections.sort(orderedEdges, new CollaborationComparator());
for (Collaboration currentEdge : orderedEdges) { for (Collaboration currentEdge : orderedEdges) {
/* /*
* This method actually creates the XML code for a single Collaboration. * This method actually creates the XML code for a single Collaboration.
* "graphMLContent" is being side-effected. * "graphMLContent" is being side-effected.
* */ * */
getEdgeContent(graphMLContent, currentEdge); getEdgeContent(graphElement, currentEdge);
} }
} }
private void getEdgeContent(StringBuilder graphMLContent, Collaboration currentEdge) { private void getEdgeContent(Element graphElement, Collaboration currentEdge) {
Document doc = graphElement.getOwnerDocument();
graphMLContent.append("<edge " Element edge = doc.createElementNS(GRAPHML_NS, "edge");
+ "id=\"" + currentEdge.getCollaborationID() + "\" " edge.setAttribute("id", String.valueOf(currentEdge.getCollaborationID()));
+ "source=\"" + currentEdge.getSourceCollaborator() edge.setAttribute("source", String.valueOf(currentEdge.getSourceCollaborator().getCollaboratorID()));
.getCollaboratorID() + "\" " edge.setAttribute("target", String.valueOf(currentEdge.getTargetCollaborator().getCollaboratorID()));
+ "target=\"" + currentEdge.getTargetCollaborator() graphElement.appendChild(edge);
.getCollaboratorID() + "\" "
+ ">\n");
graphMLContent.append("\t<data key=\"collaborator1\">" Element collaborator1 = doc.createElementNS(GRAPHML_NS, "data");
+ currentEdge.getSourceCollaborator().getCollaboratorName() collaborator1.setAttribute("key", "collaborator1");
+ "</data>\n"); collaborator1.setTextContent(currentEdge.getSourceCollaborator().getCollaboratorName());
edge.appendChild(collaborator1);
graphMLContent.append("\t<data key=\"collaborator2\">" Element collaborator2 = doc.createElementNS(GRAPHML_NS, "data");
+ currentEdge.getTargetCollaborator().getCollaboratorName() collaborator2.setAttribute("key", "collaborator2");
+ "</data>\n"); collaborator2.setTextContent(currentEdge.getTargetCollaborator().getCollaboratorName());
edge.appendChild(collaborator2);
graphMLContent.append("\t<data key=\"number_of_coauthored_works\">" Element works = doc.createElementNS(GRAPHML_NS, "data");
+ currentEdge.getNumOfCollaborations() works.setAttribute("key", "number_of_coauthored_works");
+ "</data>\n"); works.setTextContent(String.valueOf(currentEdge.getNumOfCollaborations()));
edge.appendChild(works);
if (currentEdge.getEarliestCollaborationYearCount() != null) { if (currentEdge.getEarliestCollaborationYearCount() != null) {
/* /*
* There is no clean way of getting the map contents in java even though * There is no clean way of getting the map contents in java even though
* we are sure to have only one entry on the map. So using the for loop. * we are sure to have only one entry on the map. So using the for loop.
* */ * */
for (Map.Entry<String, Integer> publicationInfo for (Map.Entry<String, Integer> publicationInfo : currentEdge.getEarliestCollaborationYearCount().entrySet()) {
: currentEdge.getEarliestCollaborationYearCount().entrySet()) {
graphMLContent.append("\t<data key=\"earliest_collaboration\">" Element earliest = doc.createElementNS(GRAPHML_NS, "data");
+ publicationInfo.getKey() earliest.setAttribute("key", "earliest_collaboration");
+ "</data>\n"); earliest.setTextContent(publicationInfo.getKey());
edge.appendChild(earliest);
graphMLContent.append("\t<data key=\"num_earliest_collaboration\">" Element earliestCount = doc.createElementNS(GRAPHML_NS, "data");
+ publicationInfo.getValue() earliestCount.setAttribute("key", "num_earliest_collaboration");
+ "</data>\n"); earliestCount.setTextContent(publicationInfo.getValue().toString());
edge.appendChild(earliestCount);
} }
} }
if (currentEdge.getLatestCollaborationYearCount() != null) { if (currentEdge.getLatestCollaborationYearCount() != null) {
for (Map.Entry<String, Integer> publicationInfo : currentEdge.getLatestCollaborationYearCount().entrySet()) {
Element latest = doc.createElementNS(GRAPHML_NS, "data");
latest.setAttribute("key", "latest_collaboration");
latest.setTextContent(publicationInfo.getKey());
edge.appendChild(latest);
for (Map.Entry<String, Integer> publicationInfo Element latestCount = doc.createElementNS(GRAPHML_NS, "data");
: currentEdge.getLatestCollaborationYearCount().entrySet()) { latestCount.setAttribute("key", "num_latest_collaboration");
latestCount.setTextContent(publicationInfo.getValue().toString());
graphMLContent.append("\t<data key=\"latest_collaboration\">" edge.appendChild(latestCount);
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_latest_collaboration\">"
+ publicationInfo.getValue()
+ "</data>\n");
} }
} }
if (currentEdge.getUnknownCollaborationYearCount() != null) { if (currentEdge.getUnknownCollaborationYearCount() != null) {
Element unknown = doc.createElementNS(GRAPHML_NS, "data");
graphMLContent.append("\t<data key=\"num_unknown_collaboration\">" unknown.setAttribute("key", "num_unknown_collaboration");
+ currentEdge.getUnknownCollaborationYearCount() unknown.setTextContent(String.valueOf(currentEdge.getUnknownCollaborationYearCount()));
+ "</data>\n"); edge.appendChild(unknown);
} }
graphMLContent.append("</edge>\n");
} }
private void generateNodeSectionContent(CollaborationData coAuthorshipData, private void generateNodeSectionContent(CollaborationData coAuthorshipData, Element graphElement) {
StringBuilder graphMLContent) { Document doc = graphElement.getOwnerDocument();
graphMLContent.append("<!-- nodes -->\n"); graphElement.appendChild(doc.createComment("nodes"));
Collaborator egoNode = coAuthorshipData.getEgoCollaborator(); Collaborator egoNode = coAuthorshipData.getEgoCollaborator();
Set<Collaborator> authorNodes = coAuthorshipData.getCollaborators(); Set<Collaborator> authorNodes = coAuthorshipData.getCollaborators();
@ -184,142 +209,130 @@ public class CoAuthorshipGraphMLWriter {
* of the co-author vis. Ego should always come first. * of the co-author vis. Ego should always come first.
* *
* */ * */
getNodeContent(graphMLContent, egoNode); getNodeContent(graphElement, egoNode);
List<Collaborator> orderedAuthorNodes = new ArrayList<Collaborator>(authorNodes); List<Collaborator> orderedAuthorNodes = new ArrayList<Collaborator>(authorNodes);
orderedAuthorNodes.remove(egoNode); orderedAuthorNodes.remove(egoNode);
Collections.sort(orderedAuthorNodes, new CollaboratorComparator()); Collections.sort(orderedAuthorNodes, new CollaboratorComparator());
for (Collaborator currNode : orderedAuthorNodes) { for (Collaborator currNode : orderedAuthorNodes) {
/* /*
* We have already printed the Ego Collaborator info. * We have already printed the Ego Collaborator info.
* */ * */
if (currNode != egoNode) { if (currNode != egoNode) {
getNodeContent(graphElement, currNode);
getNodeContent(graphMLContent, currNode);
} }
} }
} }
private void getNodeContent(StringBuilder graphMLContent, Collaborator node) { private void getNodeContent(Element graphElement, Collaborator collaborator) {
Document doc = graphElement.getOwnerDocument();
ParamMap individualProfileURLParams = ParamMap individualProfileURLParams =
new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, new ParamMap(VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, collaborator.getCollaboratorURI());
node.getCollaboratorURI());
String profileURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX, String profileURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX, individualProfileURLParams);
individualProfileURLParams);
graphMLContent.append("<node id=\"" + node.getCollaboratorID() + "\">\n"); Element node = doc.createElementNS(GRAPHML_NS, "node");
graphMLContent.append("\t<data key=\"url\">" + node.getCollaboratorURI() + "</data>\n"); node.setAttribute("id", String.valueOf(collaborator.getCollaboratorID()));
graphMLContent.append("\t<data key=\"label\">" + node.getCollaboratorName() + "</data>\n"); graphElement.appendChild(node);
Element url = doc.createElementNS(GRAPHML_NS, "data");
url.setAttribute("key", "url");
url.setTextContent(collaborator.getCollaboratorURI());
node.appendChild(url);
Element label = doc.createElementNS(GRAPHML_NS, "data");
label.setAttribute("key", "label");
label.setTextContent(collaborator.getCollaboratorName());
node.appendChild(label);
if (profileURL != null) { if (profileURL != null) {
graphMLContent.append("\t<data key=\"profile_url\">" + profileURL + "</data>\n"); Element profile = doc.createElementNS(GRAPHML_NS, "data");
profile.setAttribute("key", "profile_url");
profile.setTextContent(profileURL);
node.appendChild(profile);
} }
Element works = doc.createElementNS(GRAPHML_NS, "data");
works.setAttribute("key", "number_of_authored_works");
works.setTextContent(String.valueOf(collaborator.getNumOfActivities()));
node.appendChild(works);
graphMLContent.append("\t<data key=\"number_of_authored_works\">" if (collaborator.getEarliestActivityYearCount() != null) {
+ node.getNumOfActivities()
+ "</data>\n");
if (node.getEarliestActivityYearCount() != null) {
/* /*
* There is no clean way of getting the map contents in java even though * There is no clean way of getting the map contents in java even though
* we are sure to have only one entry on the map. So using the for loop. * we are sure to have only one entry on the map. So using the for loop.
* I am feeling dirty just about now. * I am feeling dirty just about now.
* */ * */
for (Map.Entry<String, Integer> publicationInfo for (Map.Entry<String, Integer> publicationInfo : collaborator.getEarliestActivityYearCount().entrySet()) {
: node.getEarliestActivityYearCount().entrySet()) { Element earliest = doc.createElementNS(GRAPHML_NS, "data");
earliest.setAttribute("key", "earliest_publication");
earliest.setTextContent(publicationInfo.getKey());
node.appendChild(earliest);
graphMLContent.append("\t<data key=\"earliest_publication\">" Element earliestCount = doc.createElementNS(GRAPHML_NS, "data");
+ publicationInfo.getKey() earliestCount.setAttribute("key", "num_earliest_publication");
+ "</data>\n"); earliestCount.setTextContent(publicationInfo.getValue().toString());
node.appendChild(earliestCount);
graphMLContent.append("\t<data key=\"num_earliest_publication\">"
+ publicationInfo.getValue()
+ "</data>\n");
} }
} }
if (node.getLatestActivityYearCount() != null) { if (collaborator.getLatestActivityYearCount() != null) {
for (Map.Entry<String, Integer> publicationInfo : collaborator.getLatestActivityYearCount().entrySet()) {
Element latest = doc.createElementNS(GRAPHML_NS, "data");
latest.setAttribute("key", "latest_publication");
latest.setTextContent(publicationInfo.getKey());
node.appendChild(latest);
for (Map.Entry<String, Integer> publicationInfo Element latestCount = doc.createElementNS(GRAPHML_NS, "data");
: node.getLatestActivityYearCount().entrySet()) { latestCount.setAttribute("key", "num_latest_publication");
latestCount.setTextContent(publicationInfo.getValue().toString());
graphMLContent.append("\t<data key=\"latest_publication\">" node.appendChild(latestCount);
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_latest_publication\">"
+ publicationInfo.getValue()
+ "</data>\n");
} }
} }
if (node.getUnknownActivityYearCount() != null) { if (collaborator.getUnknownActivityYearCount() != null) {
Element unknown = doc.createElementNS(GRAPHML_NS, "data");
graphMLContent.append("\t<data key=\"num_unknown_publication\">" unknown.setAttribute("key", "num_unknown_publication");
+ node.getUnknownActivityYearCount() unknown.setTextContent(String.valueOf(collaborator.getUnknownActivityYearCount()));
+ "</data>\n"); node.appendChild(unknown);
} }
graphMLContent.append("</node>\n");
} }
private void generateKeyDefinitionContent(CollaborationData visVOContainer, private void generateKeyDefinitionContent(CollaborationData visVOContainer, Element rootElement) {
StringBuilder graphMLContent) {
/* /*
* Generate the key definition content for node. * Generate the key definition content for node.
* */ * */
getKeyDefinitionFromSchema(visVOContainer.getNodeSchema(), graphMLContent); getKeyDefinitionFromSchema(visVOContainer.getNodeSchema(), rootElement);
/* /*
* Generate the key definition content for edge. * Generate the key definition content for edge.
* */ * */
getKeyDefinitionFromSchema(visVOContainer.getEdgeSchema(), graphMLContent); getKeyDefinitionFromSchema(visVOContainer.getEdgeSchema(), rootElement);
} }
private void getKeyDefinitionFromSchema(Set<Map<String, String>> schema, private void getKeyDefinitionFromSchema(Set<Map<String, String>> schema, Element rootElement) {
StringBuilder graphMLContent) { Document doc = rootElement.getOwnerDocument();
for (Map<String, String> currentNodeSchemaAttribute : schema) { for (Map<String, String> currentNodeSchemaAttribute : schema) {
Element key = doc.createElementNS(GRAPHML_NS, "key");
graphMLContent.append("\n<key "); for (Map.Entry<String, String> currentAttributeKey : currentNodeSchemaAttribute.entrySet()) {
key.setAttribute(currentAttributeKey.getKey(), currentAttributeKey.getValue());
for (Map.Entry<String, String> currentAttributeKey
: currentNodeSchemaAttribute.entrySet()) {
graphMLContent.append(currentAttributeKey.getKey()
+ "=\"" + currentAttributeKey.getValue()
+ "\" ");
} }
if (currentNodeSchemaAttribute.containsKey("default")) { if (currentNodeSchemaAttribute.containsKey("default")) {
Element def = doc.createElementNS(GRAPHML_NS, "default");
graphMLContent.append(">\n"); def.setTextContent(currentNodeSchemaAttribute.get("default"));
graphMLContent.append("<default>"); key.appendChild(def);
graphMLContent.append(currentNodeSchemaAttribute.get("default"));
graphMLContent.append("</default>\n");
graphMLContent.append("</key>\n");
} else {
graphMLContent.append("/>\n");
} }
rootElement.appendChild(key);
} }
} }
} }

View file

@ -2,6 +2,7 @@
package edu.cornell.mannlib.vitro.webapp.visualization.coprincipalinvestigator; package edu.cornell.mannlib.vitro.webapp.visualization.coprincipalinvestigator;
import java.io.StringWriter;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -16,6 +17,20 @@ import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.Collabo
import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaboratorComparator; import edu.cornell.mannlib.vitro.webapp.visualization.collaborationutils.CollaboratorComparator;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaboration; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaboration;
import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaborator; import edu.cornell.mannlib.vitro.webapp.visualization.valueobjects.Collaborator;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
/** /**
* @author bkoniden * @author bkoniden
* Deepak Konidena * Deepak Konidena
@ -24,38 +39,57 @@ public class CoPIGraphMLWriter {
private StringBuilder coPIGraphMLContent; private StringBuilder coPIGraphMLContent;
private final String GRAPHML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" private final String GRAPHML_NS = "http://graphml.graphdrawing.org/xmlns";
+ " <graphml xmlns=\"http://graphml.graphdrawing.org/xmlns\"\n"
+ " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n"
+ " xsi:schemaLocation=\"http://graphml.graphdrawing.org/xmlns\n"
+ " http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd\">\n\n";
private final String GRAPHML_FOOTER = "</graphml>";
public CoPIGraphMLWriter(CollaborationData coPIData) { public CoPIGraphMLWriter(CollaborationData coPIData) {
coPIGraphMLContent = createCoPIGraphMLContent(coPIData); coPIGraphMLContent = createCoPIGraphMLContent(coPIData);
} }
private StringBuilder createCoPIGraphMLContent(CollaborationData coPIData) { private StringBuilder createCoPIGraphMLContent(CollaborationData coPIData) {
StringBuilder graphMLContent = new StringBuilder(); StringBuilder graphMLContent = new StringBuilder();
graphMLContent.append(GRAPHML_HEADER); try {
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setNamespaceAware(true);
DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
/* // root elements
* We are side-effecting "graphMLContent" object in this method since creating Document doc = docBuilder.newDocument();
* another String object to hold key definition data will be redundant & will doc.setXmlVersion("1.0");
* not serve the purpose. Element rootElement = doc.createElementNS(GRAPHML_NS, "graphml");
* */ doc.appendChild(rootElement);
generateKeyDefinitionContent(coPIData, graphMLContent);
/* /*
* Used to generate graph content. It will contain both the nodes & edge information. * We are side-effecting "graphMLContent" object in this method since creating
* We are side-effecting "graphMLContent". * another String object to hold key definition data will be redundant & will
* */ * not serve the purpose.
generateGraphContent(coPIData, graphMLContent); * */
generateKeyDefinitionContent(coPIData, rootElement);
graphMLContent.append(GRAPHML_FOOTER); /*
* Used to generate graph content. It will contain both the nodes & edge information.
* We are side-effecting "graphMLContent".
* */
generateGraphContent(coPIData, rootElement);
DOMSource source = new DOMSource(doc);
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StringWriter writer = new StringWriter();
StreamResult result = new StreamResult(writer);
transformer.transform(source, result);
graphMLContent.append(writer.toString());
} catch (TransformerConfigurationException e) {
throw new IllegalStateException("XML error generating GraphML", e);
} catch (TransformerException e) {
throw new IllegalStateException("XML error generating GraphML", e);
} catch (ParserConfigurationException e) {
throw new IllegalStateException("XML error generating GraphML", e);
}
return graphMLContent; return graphMLContent;
} }
@ -64,117 +98,111 @@ public class CoPIGraphMLWriter {
return coPIGraphMLContent; return coPIGraphMLContent;
} }
private void generateGraphContent(CollaborationData coPIData, private void generateGraphContent(CollaborationData coPIData, Element rootElement) {
StringBuilder graphMLContent) { Document doc = rootElement.getOwnerDocument();
graphMLContent.append("\n<graph edgedefault=\"undirected\">\n"); Element graph = doc.createElementNS(GRAPHML_NS, "graph");
graph.setAttribute("edgedefault", "undirected");
rootElement.appendChild(graph);
if (coPIData.getCollaborators() != null & coPIData.getCollaborators().size() > 0) { if (coPIData.getCollaborators() != null & coPIData.getCollaborators().size() > 0) {
generateNodeSectionContent(coPIData, graphMLContent); generateNodeSectionContent(coPIData, graph);
} }
if (coPIData.getCollaborations() != null & coPIData.getCollaborations().size() > 0) { if (coPIData.getCollaborations() != null & coPIData.getCollaborations().size() > 0) {
generateEdgeSectionContent(coPIData, graphMLContent); generateEdgeSectionContent(coPIData, graph);
} }
graphMLContent.append("</graph>\n");
} }
private void generateEdgeSectionContent(CollaborationData coPIData, private void generateEdgeSectionContent(CollaborationData coPIData, Element graphElement) {
StringBuilder graphMLContent) { Document doc = graphElement.getOwnerDocument();
graphMLContent.append("<!-- edges -->\n"); graphElement.appendChild(doc.createComment("edges"));
Set<Collaboration> edges = coPIData.getCollaborations(); Set<Collaboration> edges = coPIData.getCollaborations();
List<Collaboration> orderedEdges = new ArrayList<Collaboration>(edges); List<Collaboration> orderedEdges = new ArrayList<Collaboration>(edges);
Collections.sort(orderedEdges, new CollaborationComparator()); Collections.sort(orderedEdges, new CollaborationComparator());
for (Collaboration currentEdge : orderedEdges) { for (Collaboration currentEdge : orderedEdges) {
/* /*
* This method actually creates the XML code for a single edge. "graphMLContent" * This method actually creates the XML code for a single edge. "graphMLContent"
* is being side-effected. * is being side-effected.
* */ * */
getEdgeContent(graphMLContent, currentEdge); getEdgeContent(graphElement, currentEdge);
} }
} }
private void getEdgeContent(StringBuilder graphMLContent, Collaboration currentEdge) { private void getEdgeContent(Element graphElement, Collaboration currentEdge) {
Document doc = graphElement.getOwnerDocument();
graphMLContent.append("<edge " Element edge = doc.createElementNS(GRAPHML_NS, "edge");
+ "id=\"" + currentEdge.getCollaborationID() + "\" " edge.setAttribute("id", String.valueOf(currentEdge.getCollaborationID()));
+ "source=\"" + currentEdge.getSourceCollaborator() edge.setAttribute("source", String.valueOf(currentEdge.getSourceCollaborator().getCollaboratorID()));
.getCollaboratorID() + "\" " edge.setAttribute("target", String.valueOf(currentEdge.getTargetCollaborator().getCollaboratorID()));
+ "target=\"" + currentEdge.getTargetCollaborator() graphElement.appendChild(edge);
.getCollaboratorID() + "\" "
+ ">\n");
graphMLContent.append("\t<data key=\"collaborator1\">" Element collaborator1 = doc.createElementNS(GRAPHML_NS, "data");
+ currentEdge.getSourceCollaborator().getCollaboratorName() collaborator1.setAttribute("key", "collaborator1");
+ "</data>\n"); collaborator1.setTextContent(currentEdge.getSourceCollaborator().getCollaboratorName());
edge.appendChild(collaborator1);
graphMLContent.append("\t<data key=\"collaborator2\">" Element collaborator2 = doc.createElementNS(GRAPHML_NS, "data");
+ currentEdge.getTargetCollaborator().getCollaboratorName() collaborator2.setAttribute("key", "collaborator2");
+ "</data>\n"); collaborator2.setTextContent(currentEdge.getTargetCollaborator().getCollaboratorName());
edge.appendChild(collaborator2);
graphMLContent.append("\t<data key=\"number_of_coinvestigated_grants\">" Element works = doc.createElementNS(GRAPHML_NS, "data");
+ currentEdge.getNumOfCollaborations() works.setAttribute("key", "number_of_coinvestigated_grants");
+ "</data>\n"); works.setTextContent(String.valueOf(currentEdge.getNumOfCollaborations()));
edge.appendChild(works);
if (currentEdge.getEarliestCollaborationYearCount() != null) { if (currentEdge.getEarliestCollaborationYearCount() != null) {
/* /*
* There is no clean way of getting the map contents in java even though * There is no clean way of getting the map contents in java even though
* we are sure to have only one entry on the map. So using the for loop. * we are sure to have only one entry on the map. So using the for loop.
* */ * */
for (Map.Entry<String, Integer> publicationInfo for (Map.Entry<String, Integer> publicationInfo : currentEdge.getEarliestCollaborationYearCount().entrySet()) {
: currentEdge.getEarliestCollaborationYearCount().entrySet()) {
graphMLContent.append("\t<data key=\"earliest_collaboration\">" Element earliest = doc.createElementNS(GRAPHML_NS, "data");
+ publicationInfo.getKey() earliest.setAttribute("key", "earliest_collaboration");
+ "</data>\n"); earliest.setTextContent(publicationInfo.getKey());
edge.appendChild(earliest);
graphMLContent.append("\t<data key=\"num_earliest_collaboration\">" Element earliestCount = doc.createElementNS(GRAPHML_NS, "data");
+ publicationInfo.getValue() earliestCount.setAttribute("key", "num_earliest_collaboration");
+ "</data>\n"); earliestCount.setTextContent(publicationInfo.getValue().toString());
edge.appendChild(earliestCount);
} }
} }
if (currentEdge.getLatestCollaborationYearCount() != null) { if (currentEdge.getLatestCollaborationYearCount() != null) {
for (Map.Entry<String, Integer> publicationInfo : currentEdge.getLatestCollaborationYearCount().entrySet()) {
Element latest = doc.createElementNS(GRAPHML_NS, "data");
latest.setAttribute("key", "latest_collaboration");
latest.setTextContent(publicationInfo.getKey());
edge.appendChild(latest);
for (Map.Entry<String, Integer> publicationInfo Element latestCount = doc.createElementNS(GRAPHML_NS, "data");
: currentEdge.getLatestCollaborationYearCount().entrySet()) { latestCount.setAttribute("key", "num_latest_collaboration");
latestCount.setTextContent(publicationInfo.getValue().toString());
graphMLContent.append("\t<data key=\"latest_collaboration\">" edge.appendChild(latestCount);
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_latest_collaboration\">"
+ publicationInfo.getValue()
+ "</data>\n");
} }
} }
if (currentEdge.getUnknownCollaborationYearCount() != null) { if (currentEdge.getUnknownCollaborationYearCount() != null) {
Element unknown = doc.createElementNS(GRAPHML_NS, "data");
graphMLContent.append("\t<data key=\"num_unknown_collaboration\">" unknown.setAttribute("key", "num_unknown_collaboration");
+ currentEdge.getUnknownCollaborationYearCount() unknown.setTextContent(String.valueOf(currentEdge.getUnknownCollaborationYearCount()));
+ "</data>\n"); edge.appendChild(unknown);
} }
graphMLContent.append("</edge>\n");
} }
private void generateNodeSectionContent(CollaborationData coPIData, Element graphElement) {
Document doc = graphElement.getOwnerDocument();
private void generateNodeSectionContent(CollaborationData coPIData, graphElement.appendChild(doc.createComment("nodes"));
StringBuilder graphMLContent) {
graphMLContent.append("<!-- nodes -->\n");
Collaborator egoNode = coPIData.getEgoCollaborator(); Collaborator egoNode = coPIData.getEgoCollaborator();
Set<Collaborator> piNodes = coPIData.getCollaborators(); Set<Collaborator> piNodes = coPIData.getCollaborators();
@ -185,7 +213,7 @@ public class CoPIGraphMLWriter {
* of the co-pi vis. Ego should always come first. * of the co-pi vis. Ego should always come first.
* *
* */ * */
getNodeContent(graphMLContent, egoNode); getNodeContent(graphElement, egoNode);
List<Collaborator> orderedPINodes = new ArrayList<Collaborator>(piNodes); List<Collaborator> orderedPINodes = new ArrayList<Collaborator>(piNodes);
orderedPINodes.remove(egoNode); orderedPINodes.remove(egoNode);
@ -194,131 +222,119 @@ public class CoPIGraphMLWriter {
for (Collaborator currNode : orderedPINodes) { for (Collaborator currNode : orderedPINodes) {
/* /*
* We have already printed the Ego Node info. * We have already printed the Ego Node info.
* */ * */
if (currNode != egoNode) { if (currNode != egoNode) {
getNodeContent(graphElement, currNode);
getNodeContent(graphMLContent, currNode);
} }
} }
} }
private void getNodeContent(StringBuilder graphMLContent, Collaborator node) { private void getNodeContent(Element graphElement, Collaborator collaborator) {
Document doc = graphElement.getOwnerDocument();
ParamMap individualProfileURLParams = new ParamMap( ParamMap individualProfileURLParams = new ParamMap(
VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, VisualizationFrameworkConstants.INDIVIDUAL_URI_KEY, collaborator.getCollaboratorURI());
node.getCollaboratorURI());
String profileURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX, String profileURL = UrlBuilder.getUrl(VisualizationFrameworkConstants.INDIVIDUAL_URL_PREFIX, individualProfileURLParams);
individualProfileURLParams);
graphMLContent.append("<node id=\"" + node.getCollaboratorID() + "\">\n"); Element node = doc.createElementNS(GRAPHML_NS, "node");
graphMLContent.append("\t<data key=\"url\">" + node.getCollaboratorURI() + "</data>\n"); node.setAttribute("id", String.valueOf(collaborator.getCollaboratorID()));
graphMLContent.append("\t<data key=\"label\">" + node.getCollaboratorName() + "</data>\n"); graphElement.appendChild(node);
Element url = doc.createElementNS(GRAPHML_NS, "data");
url.setAttribute("key", "url");
url.setTextContent(collaborator.getCollaboratorURI());
node.appendChild(url);
Element label = doc.createElementNS(GRAPHML_NS, "data");
label.setAttribute("key", "label");
label.setTextContent(collaborator.getCollaboratorName());
node.appendChild(label);
if (profileURL != null) { if (profileURL != null) {
graphMLContent.append("\t<data key=\"profile_url\">" + profileURL + "</data>\n"); Element profile = doc.createElementNS(GRAPHML_NS, "data");
profile.setAttribute("key", "profile_url");
profile.setTextContent(profileURL);
node.appendChild(profile);
} }
Element works = doc.createElementNS(GRAPHML_NS, "data");
works.setAttribute("key", "number_of_investigated_grants");
works.setTextContent(String.valueOf(collaborator.getNumOfActivities()));
node.appendChild(works);
graphMLContent.append("\t<data key=\"number_of_investigated_grants\">" if (collaborator.getEarliestActivityYearCount() != null) {
+ node.getNumOfActivities()
+ "</data>\n");
if (node.getEarliestActivityYearCount() != null) {
/* /*
* There is no clean way of getting the map contents in java even though * There is no clean way of getting the map contents in java even though
* we are sure to have only one entry on the map. So using the for loop. * we are sure to have only one entry on the map. So using the for loop.
* I am feeling dirty just about now. * I am feeling dirty just about now.
* */ * */
for (Map.Entry<String, Integer> publicationInfo for (Map.Entry<String, Integer> publicationInfo : collaborator.getEarliestActivityYearCount().entrySet()) {
: node.getEarliestActivityYearCount().entrySet()) { Element earliest = doc.createElementNS(GRAPHML_NS, "data");
earliest.setAttribute("key", "earliest_grant");
earliest.setTextContent(publicationInfo.getKey());
node.appendChild(earliest);
graphMLContent.append("\t<data key=\"earliest_grant\">" Element earliestCount = doc.createElementNS(GRAPHML_NS, "data");
+ publicationInfo.getKey() earliestCount.setAttribute("key", "num_earliest_grant");
+ "</data>\n"); earliestCount.setTextContent(publicationInfo.getValue().toString());
node.appendChild(earliestCount);
graphMLContent.append("\t<data key=\"num_earliest_grant\">"
+ publicationInfo.getValue()
+ "</data>\n");
} }
} }
if (node.getLatestActivityYearCount() != null) { if (collaborator.getLatestActivityYearCount() != null) {
for (Map.Entry<String, Integer> publicationInfo : collaborator.getLatestActivityYearCount().entrySet()) {
Element latest = doc.createElementNS(GRAPHML_NS, "data");
latest.setAttribute("key", "latest_grant");
latest.setTextContent(publicationInfo.getKey());
node.appendChild(latest);
for (Map.Entry<String, Integer> publicationInfo Element latestCount = doc.createElementNS(GRAPHML_NS, "data");
: node.getLatestActivityYearCount().entrySet()) { latestCount.setAttribute("key", "num_latest_grant");
latestCount.setTextContent(publicationInfo.getValue().toString());
graphMLContent.append("\t<data key=\"latest_grant\">" node.appendChild(latestCount);
+ publicationInfo.getKey()
+ "</data>\n");
graphMLContent.append("\t<data key=\"num_latest_grant\">"
+ publicationInfo.getValue()
+ "</data>\n");
} }
} }
if (node.getUnknownActivityYearCount() != null) { if (collaborator.getUnknownActivityYearCount() != null) {
Element unknown = doc.createElementNS(GRAPHML_NS, "data");
graphMLContent.append("\t<data key=\"num_unknown_grant\">" unknown.setAttribute("key", "num_unknown_grant");
+ node.getUnknownActivityYearCount() unknown.setTextContent(String.valueOf(collaborator.getUnknownActivityYearCount()));
+ "</data>\n"); node.appendChild(unknown);
} }
graphMLContent.append("</node>\n");
} }
private void generateKeyDefinitionContent(CollaborationData coPIData, private void generateKeyDefinitionContent(CollaborationData coPIData, Element rootElement) {
StringBuilder graphMLContent) {
/* /*
* Generate the key definition content for node. * Generate the key definition content for node.
* */ * */
getKeyDefinitionFromSchema(coPIData.getNodeSchema(), graphMLContent); getKeyDefinitionFromSchema(coPIData.getNodeSchema(), rootElement);
/* /*
* Generate the key definition content for edge. * Generate the key definition content for edge.
* */ * */
getKeyDefinitionFromSchema(coPIData.getEdgeSchema(), graphMLContent); getKeyDefinitionFromSchema(coPIData.getEdgeSchema(), rootElement);
} }
private void getKeyDefinitionFromSchema(Set<Map<String, String>> schema, private void getKeyDefinitionFromSchema(Set<Map<String, String>> schema, Element rootElement) {
StringBuilder graphMLContent) { Document doc = rootElement.getOwnerDocument();
for (Map<String, String> currentNodeSchemaAttribute : schema) { for (Map<String, String> currentNodeSchemaAttribute : schema) {
Element key = doc.createElementNS(GRAPHML_NS, "key");
graphMLContent.append("\n<key "); for (Map.Entry<String, String> currentAttributeKey : currentNodeSchemaAttribute.entrySet()) {
key.setAttribute(currentAttributeKey.getKey(), currentAttributeKey.getValue());
for (Map.Entry<String, String> currentAttributeKey
: currentNodeSchemaAttribute.entrySet()) {
graphMLContent.append(currentAttributeKey.getKey()
+ "=\"" + currentAttributeKey.getValue()
+ "\" ");
} }
if (currentNodeSchemaAttribute.containsKey("default")) { if (currentNodeSchemaAttribute.containsKey("default")) {
Element def = doc.createElementNS(GRAPHML_NS, "default");
graphMLContent.append(">\n"); def.setTextContent(currentNodeSchemaAttribute.get("default"));
graphMLContent.append("<default>"); key.appendChild(def);
graphMLContent.append(currentNodeSchemaAttribute.get("default"));
graphMLContent.append("</default>\n");
graphMLContent.append("</key>\n");
} else {
graphMLContent.append("/>\n");
} }
rootElement.appendChild(key);
} }
} }
} }