/* Copyright 2012-2013 Fabian Steeg. Licensed under the Eclipse Public License 1.0 */
package org.lobid.lodmill;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import org.json.simple.JSONObject;
import org.json.simple.JSONValue;
import org.lobid.lodmill.hadoop.NTriplesToJsonLd;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.jsonldjava.core.JsonLdError;
import com.github.jsonldjava.core.JsonLdOptions;
import com.github.jsonldjava.core.JsonLdProcessor;
import com.github.jsonldjava.jena.JenaRDFParser;
import com.github.jsonldjava.jena.JenaTripleCallback;
import com.github.jsonldjava.utils.JSONUtils;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
/**
* A simple API for JSON-LD conversion (JSON-LD to RDF and RDF to JSON-LD),
* wrapping calls to the Jena and jsonld-java libraries.
*
* @author Fabian Steeg (fsteeg)
*/
public class JsonLdConverter {
private static final Logger LOG = LoggerFactory
.getLogger(JsonLdConverter.class);
private final Format format;
/**
* RDF serialization formats.
*/
@SuppressWarnings("javadoc")
public static enum Format {
RDF_XML("RDF/XML"), RDF_XML_ABBREV("RDF/XML-ABBREV"), N_TRIPLE("N-TRIPLE"), N3(
"N3"), TURTLE("TURTLE");
private final String name;
Format(final String name) {
this.name = name;
}
public String getName() {
return name;
}
}
/**
* @param format The RDF serialization format to use for conversions.
*/
public JsonLdConverter(final Format format) {
this.format = format;
}
/**
* @param jsonLd The JSON-LD string to convert
* @return The input, converted to this converters RDF serialization, or null
*/
public String toRdf(final String jsonLd) {
try {
final Object jsonObject = JSONUtils.fromString(jsonLd);
final JenaTripleCallback callback = new JenaTripleCallback();
final Model model = (Model) JsonLdProcessor.toRDF(jsonObject, callback);
final StringWriter writer = new StringWriter();
model.write(writer, format.getName());
return writer.toString();
} catch (IOException | JsonLdError e) {
LOG.error(e.getMessage(), e);
}
return null;
}
/**
* @param rdf The RDF string in this converter's format
* @return The input, converted to JSON-LD, or null
*/
public String toJsonLd(final String rdf) {
return toJsonLd(rdf, null, null);
}
/**
* @param rdf The RDF string in this converter's format
* @param parentProperty The property pointing to the parent
* @param id The internal ID to use in ES
* @return The input, converted to JSON-LD, or null
*/
public String toJsonLd(final String rdf, String parentProperty, String id) {
final Model model = ModelFactory.createDefaultModel();
model.read(new StringReader(rdf), null, format.getName());
return jenaModelToJsonLd(model, parentProperty, id);
}
/**
* @param model The Jena model to serialize as a JSON-LD string
* @param parentProperty The property pointing to the parent
* @param id The internal ID to use in ES
* @return The JSON-LD serialization of the Jena model, or null
*/
public static String jenaModelToJsonLd(final Model model,
String parentProperty, String id) {
final JenaRDFParser parser = new JenaRDFParser();
try {
Object json = JsonLdProcessor.fromRDF(model, new JsonLdOptions(), parser);
/* We use the 'expanded' JSON-LD serialization for consistent field types: */
json = JsonLdProcessor.expand(json);
/* But we wrap it into a "@graph" for elasticsearch (still valid JSON-LD): */
String jsonString = JSONUtils.toString(json);
Map<String, Object> map = new HashMap<>();
map.put("@graph", JSONValue.parse(jsonString));
addInternalProperties(parentProperty, id, jsonString, map);
return JSONObject.toJSONString(map);
} catch (JsonLdError e) {
e.printStackTrace();
}
return null;
}
private static void addInternalProperties(String parentProperty, String id,
String jsonString, Map<String, Object> map) {
if (parentProperty != null) {
try {
JsonNode node =
new ObjectMapper().readValue(jsonString, JsonNode.class);
final JsonNode parent = node.findValue(parentProperty);
String p = parent != null ? parent.findValue("@id").asText() : "none";
map.put(NTriplesToJsonLd.INTERNAL_PARENT, p);
} catch (IOException e) {
e.printStackTrace();
}
}
if (id != null) {
map.put(NTriplesToJsonLd.INTERNAL_ID, id);
}
}
}