package edu.neu.ccs.task.rdf;
import java.io.Writer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import com.hp.hpl.jena.rdf.model.AnonId;
import com.hp.hpl.jena.rdf.model.Literal;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.RDFNode;
import com.hp.hpl.jena.rdf.model.RDFVisitor;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.rdf.model.Statement;
import com.hp.hpl.jena.rdf.model.StmtIterator;
class GraphML {
private GraphML() {}
public static void write(Writer out, Model model)
throws XMLStreamException {
XMLOutputFactory xof = XMLOutputFactory.newInstance();
XMLStreamWriter xw = xof.createXMLStreamWriter(out);
xw.writeStartDocument("UTF-8", "1.0");
xw.writeStartElement("graphml");
xw.writeDefaultNamespace("http://graphml.graphdrawing.org/xmlns");
xw.writeStartElement("graph");
xw.writeAttribute("id", "G");
xw.writeAttribute("edgedefault", "directed");
// HACK! Flare's GraphML parser doesn't handle "all" attributes
// This output is not quite valid GraphML (duplicate keys)
writeKey(xw, "kval", "node", "value", "string");
writeKey(xw, "klval", "node", "longValue", "string");
writeKey(xw, "kval", "edge", "value", "string");
writeKey(xw, "klval", "edge", "longValue", "string");
//writeKey(xw, "kval", "all", "value", "string");
//writeKey(xw, "klval", "all", "longValue", "string");
writeKey(xw, "kkind", "node", "kind", "string");
Map<RDFNode, Integer> nodeIds = new HashMap<RDFNode, Integer>();
for (RDFNode node : allNodes(model)) {
xw.writeStartElement("node");
xw.writeAttribute("id", graphId(nodeIds, node));
writeData(xw, "kkind", (String) node.visitWith(KIND_VISITOR));
writeValue(xw, node);
xw.writeEndElement();
}
int edgeId = 0;
for (StmtIterator it = model.listStatements(); it.hasNext();) {
Statement s = it.next();
xw.writeStartElement("edge");
xw.writeAttribute("id", "e"+edgeId);
xw.writeAttribute("source", graphId(nodeIds, s.getSubject()));
xw.writeAttribute("target", graphId(nodeIds, s.getObject()));
writeValue(xw, s.getPredicate());
xw.writeEndElement();
edgeId++;
}
xw.writeEndElement();
xw.writeEndElement();
xw.writeEndDocument();
xw.flush();
}
private static void writeKey(XMLStreamWriter xw,
String id, String target,
String name, String type)
throws XMLStreamException {
xw.writeEmptyElement("key");
xw.writeAttribute("id", id);
xw.writeAttribute("for", target);
xw.writeAttribute("attr.name", name);
xw.writeAttribute("attr.type", type);
}
private static void writeValue(XMLStreamWriter xw, RDFNode node)
throws XMLStreamException {
writeData(xw, "kval", (String) node.visitWith(VALUE_VISITOR));
writeData(xw, "klval", (String) node.visitWith(LVALUE_VISITOR));
}
private static void writeData(XMLStreamWriter xw, String key, String value)
throws XMLStreamException {
xw.writeStartElement("data");
xw.writeAttribute("key", key);
xw.writeCharacters(value);
xw.writeEndElement();
}
private static final RDFVisitor KIND_VISITOR = new RDFVisitor() {
public String visitURI(Resource r, String uri) {
return "uri";
}
public String visitLiteral(Literal lit) {
return "literal";
}
public String visitBlank(Resource r, AnonId id) {
return "blank";
}
};
private static final int MAXLEN = 15;
private static final RDFVisitor VALUE_VISITOR = new RDFVisitor() {
public String visitURI(Resource r, String uri) {
String s = r.getModel().shortForm(uri);
return s.length() > MAXLEN ? "..."+s.substring(3) : s;
}
public String visitLiteral(Literal lit) {
String s = lit.getLexicalForm();
return s.length() > MAXLEN ? s.substring(0,MAXLEN-3)+"..." : s;
}
public String visitBlank(Resource r, AnonId id) {
return "[]";
}
};
private static final RDFVisitor LVALUE_VISITOR = new RDFVisitor() {
public String visitURI(Resource r, String uri) {
return uri;
}
public String visitLiteral(Literal lit) {
return lit.asNode().toString(false);
}
public String visitBlank(Resource r, AnonId id) {
return "[]";
}
};
private static Set<RDFNode> allNodes(Model model) {
Set<RDFNode> nodes = new HashSet<RDFNode>();
for (StmtIterator it = model.listStatements(); it.hasNext();) {
Statement s = it.next();
nodes.add(s.getSubject());
nodes.add(s.getObject());
}
return nodes;
}
private static String graphId(Map<RDFNode, Integer> ids, RDFNode node) {
Integer id = ids.get(node);
if (id == null) {
id = Integer.valueOf(ids.size());
ids.put(node, id);
}
return "n" + id;
}
}