You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ss...@apache.org on 2013/03/08 11:11:45 UTC
[5/5] git commit: added the DFKI JSON-LD source to source code
(temporary fix for MARMOTTA-122)
Updated Branches:
refs/heads/master 7f9196fce -> 1587eba09
added the DFKI JSON-LD source to source code (temporary fix for MARMOTTA-122)
Project: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/commit/1587eba0
Tree: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/tree/1587eba0
Diff: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/diff/1587eba0
Branch: refs/heads/master
Commit: 1587eba09c48f89a71a4659bbabb73cd792be671
Parents: 700516b
Author: Sebastian Schaffert <ss...@apache.org>
Authored: Fri Mar 8 11:11:33 2013 +0100
Committer: Sebastian Schaffert <ss...@apache.org>
Committed: Fri Mar 8 11:11:33 2013 +0100
----------------------------------------------------------------------
commons/sesame-tools-rio-jsonld/pom.xml | 50 +-
.../src/ext/java/de/dfki/km/json/JSONUtils.java | 208 +++
.../java/de/dfki/km/json/jsonld/JSONLDConsts.java | 17 +
.../de/dfki/km/json/jsonld/JSONLDProcessor.java | 1386 +++++++++++++++
.../de/dfki/km/json/jsonld/JSONLDSerializer.java | 241 +++
.../dfki/km/json/jsonld/JSONLDTripleCallback.java | 34 +
.../java/de/dfki/km/json/jsonld/JSONLDUtils.java | 855 +++++++++
.../json/jsonld/impl/SesameJSONLDSerializer.java | 49 +
.../km/json/jsonld/impl/SesameTripleCallback.java | 83 +
9 files changed, 2919 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/1587eba0/commons/sesame-tools-rio-jsonld/pom.xml
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-rio-jsonld/pom.xml b/commons/sesame-tools-rio-jsonld/pom.xml
index 2a73978..66a9430 100644
--- a/commons/sesame-tools-rio-jsonld/pom.xml
+++ b/commons/sesame-tools-rio-jsonld/pom.xml
@@ -29,6 +29,52 @@
<artifactId>sesame-tools-rio-jsonld</artifactId>
<packaging>jar</packaging>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.7</version>
+ <executions>
+ <execution>
+ <id>add-ext</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>src/ext/java</source>
+ </sources>
+ </configuration>
+ </execution>
+ <execution>
+ <id>add-ext-test</id>
+ <phase>generate-test-sources</phase>
+ <goals>
+ <goal>add-test-source</goal>
+ </goals>
+ <inherited>false</inherited>
+ <configuration>
+ <sources>
+ <source>src/ext-test/java</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ <resources>
+ <resource>
+ <directory>src/main/resources</directory>
+ </resource>
+ <resource>
+ <directory>src/ext/resources</directory>
+ </resource>
+ </resources>
+ </build>
+
+
<dependencies>
<dependency>
<groupId>org.apache.marmotta</groupId>
@@ -41,10 +87,6 @@
</dependency>
<dependency>
- <groupId>dfki.km.json</groupId>
- <artifactId>jsonld-java</artifactId>
- </dependency>
- <dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
</dependency>
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/1587eba0/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/JSONUtils.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/JSONUtils.java b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/JSONUtils.java
new file mode 100644
index 0000000..4be1f99
--- /dev/null
+++ b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/JSONUtils.java
@@ -0,0 +1,208 @@
+package de.dfki.km.json;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.JsonGenerationException;
+import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.JsonLocation;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+
+/**
+ * A bunch of functions to make loading JSON easy
+ *
+ * @author tristan
+ *
+ */
+public class JSONUtils {
+ public static Object fromString(String jsonString) throws JsonParseException, JsonMappingException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ Object rval = null;
+ if (jsonString.trim().startsWith("[")) {
+ try {
+ rval = objectMapper.readValue(jsonString, List.class);
+ } catch (IOException e) {
+ // TODO: what?
+ if (e instanceof JsonParseException) {
+ throw (JsonParseException) e;
+ } else if (e instanceof JsonMappingException) {
+ throw (JsonMappingException) e;
+ } else {
+ // TODO: Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ } else if (jsonString.trim().startsWith("{")) {
+ try {
+ rval = objectMapper.readValue(jsonString, Map.class);
+ } catch (IOException e) {
+ if (e instanceof JsonParseException) {
+ throw (JsonParseException) e;
+ } else if (e instanceof JsonMappingException) {
+ throw (JsonMappingException) e;
+ } else {
+ // TODO: Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ } else if (jsonString.trim().startsWith("\"")) {
+ try {
+ rval = objectMapper.readValue(jsonString, String.class);
+ } catch (IOException e) {
+ if (e instanceof JsonParseException) {
+ throw (JsonParseException) e;
+ } else if (e instanceof JsonMappingException) {
+ throw (JsonMappingException) e;
+ } else {
+ // TODO: Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ } else if (jsonString.trim().equals("true") || (jsonString.trim().equals("false"))) {
+ try {
+ rval = objectMapper.readValue(jsonString, Boolean.class);
+ } catch (IOException e) {
+ if (e instanceof JsonParseException) {
+ throw (JsonParseException) e;
+ } else if (e instanceof JsonMappingException) {
+ throw (JsonMappingException) e;
+ } else {
+ // TODO: Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ } else if (jsonString.trim().matches("[0-9.e+-]+")) {
+ try {
+ rval = objectMapper.readValue(jsonString, Number.class);
+ } catch (IOException e) {
+ if (e instanceof JsonParseException) {
+ throw (JsonParseException) e;
+ } else if (e instanceof JsonMappingException) {
+ throw (JsonMappingException) e;
+ } else {
+ // TODO: Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ } else if (jsonString.trim().equals("null")) {
+ rval = null;
+ } else {
+ throw new JsonParseException("document doesn't start with a valid json element", new JsonLocation("\""
+ + jsonString.substring(0, Math.min(jsonString.length(), 100)) + "...\"", 0, 1, 0));
+ }
+ return rval;
+ }
+
+ public static Object fromReader(Reader r) throws IOException {
+ StringBuffer sb = new StringBuffer();
+ int b;
+ while ((b = r.read()) != -1) {
+ sb.append((char) b);
+ }
+ return fromString(sb.toString());
+ }
+
+ public static void write(Writer w, Object jsonObject) throws JsonGenerationException, JsonMappingException, IOException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.getJsonFactory().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+ objectMapper.writeValue(w, jsonObject);
+ }
+
+ public static void writePrettyPrint(Writer w, Object jsonObject) throws JsonGenerationException, JsonMappingException, IOException {
+ ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.getJsonFactory().disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);
+ ObjectWriter objectWriter = objectMapper.writerWithDefaultPrettyPrinter();
+
+ objectWriter.writeValue(w, jsonObject);
+ }
+
+ public static Object fromInputStream(InputStream content) throws IOException {
+ return fromInputStream(content, "UTF-8"); // no readers from
+ // inputstreams w.o.
+ // encoding!!
+ }
+
+ public static Object fromInputStream(InputStream content, String enc) throws IOException {
+ return fromReader(new BufferedReader(new InputStreamReader(content, enc)));
+ }
+
+ public static String toPrettyString(Object obj) {
+ StringWriter sw = new StringWriter();
+ try {
+ writePrettyPrint(sw, obj);
+ } catch (Exception e) {
+ // TODO Is this really possible with stringwriter?
+ // I think it's only there because of the interface
+ // however, if so... well, we have to do something!
+ // it seems weird for toString to throw an IOException
+ }
+ return sw.toString();
+ }
+
+ public static String toString(Object obj) { // throws
+ // JsonGenerationException,
+ // JsonMappingException {
+ StringWriter sw = new StringWriter();
+ try {
+ write(sw, obj);
+ } catch (Exception e) {
+ // TODO Is this really possible with stringwriter?
+ // I think it's only there because of the interface
+ // however, if so... well, we have to do something!
+ // it seems weird for toString to throw an IOException
+ }
+ return sw.toString();
+ }
+
+ public static boolean equals(Object v1, Object v2) {
+ boolean rval = true;
+ // TODO Auto-generated method stub
+ if (v1 instanceof List && v2 instanceof List) {
+ if (((List) v1).size() != ((List) v2).size()) {
+ rval = false;
+ } else {
+ // TODO: should the order of things in the list matter?
+ for (int i = 0; i < ((List<Object>) v1).size() && rval == true; i++) {
+ rval = equals(((List<Object>) v1).get(i), ((List<Object>) v2).get(i));
+ }
+ }
+ } else if (v1 instanceof Number && v2 instanceof Number) {
+ // TODO: this is VERY sketchy
+ double n1 = ((Number) v1).doubleValue();
+ double n2 = ((Number) v2).doubleValue();
+
+ rval = n1 == n2;
+ } else if (v1 instanceof String && v2 instanceof String) {
+ rval = ((String) v1).equals((String) v2);
+ } else if (v1 instanceof Map && v2 instanceof Map) {
+ if (((Map) v1).size() != ((Map) v2).size()) {
+ rval = false;
+ } else {
+ for (Object k1 : ((Map) v1).keySet()) {
+ rval = ((Map) v2).containsKey(k1) ? equals(((Map) v1).get(k1), ((Map) v2).get(k1)) : false;
+ if (rval != true) {
+ break;
+ }
+ }
+ }
+ } else if (v1 instanceof Boolean && v2 instanceof Boolean) {
+ rval = v1 == v2;
+ } else if (v1 != null && v2 != null) {
+ rval = v1.equals(v2);
+ } else {
+ rval = v1 == v2;
+ }
+
+ return rval;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/1587eba0/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDConsts.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDConsts.java b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDConsts.java
new file mode 100644
index 0000000..a280194
--- /dev/null
+++ b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDConsts.java
@@ -0,0 +1,17 @@
+package de.dfki.km.json.jsonld;
+
+public class JSONLDConsts {
+
+ public static final String RDF_SYNTAX_NS = "http://www.w3.org/1999/02/22-rdf-syntax-ns#";
+ public static final String RDF_SCHEMA_NS = "http://www.w3.org/2000/01/rdf-schema#";
+ public static final String XSD_NS = "http://www.w3.org/2001/XMLSchema#";
+
+ public static final String XSD_ANYTYPE = XSD_NS + "anyType";
+ public static final String XSD_BOOLEAN = XSD_NS + "boolean";
+ public static final String XSD_DOUBLE = XSD_NS + "double";
+ public static final String XSD_INTEGER = XSD_NS + "integer";
+ public static final String XSD_ANYURI = XSD_NS + "anyURI";
+ public static final String XSD_STRING = XSD_NS + "string";
+
+ public static final String RDF_TYPE = RDF_SYNTAX_NS + "type";
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/1587eba0/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDProcessor.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDProcessor.java b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDProcessor.java
new file mode 100644
index 0000000..3d0074e
--- /dev/null
+++ b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDProcessor.java
@@ -0,0 +1,1386 @@
+package de.dfki.km.json.jsonld;
+
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import de.dfki.km.json.jsonld.JSONLDUtils.NameGenerator;
+
+public class JSONLDProcessor {
+
+ private static final Logger LOG = LoggerFactory.getLogger(JSONLDProcessor.class);
+ private NameGenerator ngtmp;
+
+ private Set<String> ignoredKeywords = new HashSet<String>();
+
+ /**
+ * Tells the processor to skip over the key specified by keyword any time it encounters it. Objects under this key will not be manipulated by any of the
+ * processor functions and no triples will be created using it.
+ *
+ * @param keyword
+ * The name of the key this processor should ignore.
+ */
+ public void ignoreKeyword(String keyword) {
+ ignoredKeywords.add(keyword);
+ }
+
+ private Map<String, Object> edges;
+ private Map<String, Object> subjects;
+ private Map<String, Object> renamed;
+ private Map<String, Object> serializations;
+ private NameGenerator ngc14n;
+
+ public Object expand(Object input) {
+ return expand(new HashMap<String, Object>(), null, input);
+ }
+
+ private Object expand(Map<String, Object> ctx, Object property, Object value) {
+ Object rval = null;
+ if (value == null) {
+ return null;
+ } else if (property == null && value instanceof String) {
+ rval = JSONLDUtils.expandTerm(ctx, (String) value);// , null));
+ } else if (value instanceof List) {
+ rval = new ArrayList<Object>();
+ for (Object i : (List) value) {
+ ((List) rval).add(expand(ctx, property, i));
+ }
+ } else if (value instanceof Map) {
+ rval = new HashMap<String, Object>();
+ if (((Map<String, Object>) value).containsKey("@context")) {
+ try {
+ ctx = JSONLDUtils.mergeContexts((Map<String, Object>) ctx, (Map<String, Object>) ((Map<String, Object>) value).get("@context"));
+ } catch (Exception e) {
+ // unable to merge contexts
+ // TODO: this should probably just throw back to the calling
+ // function
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ rval = new HashMap<String, Object>();
+ for (String key : ((Map<String, Object>) value).keySet()) {
+ if ("@embed".equals(key) || "@explicit".equals(key) || "@default".equals(key) || "@omitDefault".equals(key) || ignoredKeywords.contains(key)) {
+ JSONLDUtils.setProperty((Map<String, Object>) rval, key, JSONLDUtils.clone(((Map<String, Object>) value).get(key)));
+ } else if (!"@context".equals(key)) {
+ JSONLDUtils.setProperty((Map<String, Object>) rval, JSONLDUtils.expandTerm(ctx, key),
+ expand(ctx, key, ((Map<String, Object>) value).get(key)));
+ }
+ }
+ } else {
+ // do type coercion
+ String coerce = JSONLDUtils.getCoercionType(ctx, (String) property);// ,
+ // null);
+ Map<String, String> keywords = JSONLDUtils.getKeywords(ctx);
+
+ // automatic coercion for basic JSON types
+ if (coerce == null) {
+ if (value instanceof Boolean) {
+ coerce = JSONLDConsts.XSD_BOOLEAN;
+ } else if (value instanceof Integer) {
+ coerce = JSONLDConsts.XSD_INTEGER;
+ } else if (value instanceof Double) {
+ coerce = JSONLDConsts.XSD_DOUBLE;
+ }
+ }
+
+ // special-case expand @id and @type (skips '@id' expansion)
+ if (property.equals("@id") || property.equals(keywords.get("@id")) || property.equals("@type") || property.equals(keywords.get("@type"))) {
+ rval = JSONLDUtils.expandTerm(ctx, (String) value);
+ }
+ // coerce to appropriate type
+ else if (coerce != null) {
+ rval = new HashMap<String, Object>();
+
+ if (coerce.equals("@id")) {
+ // expand IRI
+ ((Map<String, Object>) rval).put("@id", JSONLDUtils.expandTerm(ctx, (String) value)); // ,
+ // null));
+ } else {
+ ((Map<String, Object>) rval).put("@type", coerce);
+ if (coerce.equals(JSONLDConsts.XSD_DOUBLE)) {
+ DecimalFormat decimalFormat = new DecimalFormat("0.000000E0", new DecimalFormatSymbols(Locale.US));
+ Double v = null;
+ if (value instanceof String) {
+ v = Double.parseDouble((String) value);
+ } else if (value instanceof Integer) {
+ // TODO: what is this? really?
+ v = new Double(1.0 * (Integer) value);
+ } else {
+ v = (Double) value;
+ }
+ String dec = decimalFormat.format(v);
+ Pattern p = Pattern.compile("(-?[0-9\\.]+)E((?:-*))([0-9]+)");
+ Matcher matcher = p.matcher(dec);
+ matcher.find();
+ String sign = matcher.group(2);
+ if ("".equals(sign)) {
+ sign = "+";
+ }
+ value = matcher.group(1) + "e" + sign + (matcher.group(3).length() > 1 ? matcher.group(3) : "0" + matcher.group(3));
+ } else {
+ value = value.toString();
+ }
+ ((Map<String, Object>) rval).put("@value", value);
+ }
+ } else {
+ // nothing to coerce
+ rval = value.toString();
+ }
+ }
+
+ return rval;
+ }
+
+ // TODO: note that in the spec, input is the first input, but in the ref
+ // impl, context is.
+ // using context here first because it matches everything else
+ public Object compact(Object context, Object input) {
+
+ Object rval = null;
+
+ Map<String, Object> ctx;
+ if (context == null) {
+ ctx = new HashMap<String, Object>();
+ } else if (context instanceof Map) {
+ ctx = (Map<String, Object>) JSONLDUtils.clone(context);
+ } else if (context instanceof List) {
+ ctx = (Map<String, Object>) JSONLDUtils.mergeContexts(new HashMap<String, Object>(), context);
+ } else {
+ // TODO: are there any reasons that ctx shouldn't be a map?
+ throw new RuntimeException("non-map or list contexts not yes supported");
+ }
+
+ input = expand(input);
+
+ Map<String, Object> ctxOut = new HashMap<String, Object>();
+ Object out = compact(ctx, null, input, ctxOut);
+ rval = out;
+
+ if (ctxOut.size() > 0) {
+ rval = new HashMap<String, Object>();
+ ((Map<String, Object>) rval).put("@context", ctxOut);
+ if (out instanceof List) {
+ ((Map<String, Object>) rval).put(JSONLDUtils.getKeywords(ctxOut).get("@id"), out);
+ } else {
+ for (String key : ((Map<String, Object>) out).keySet()) {
+ ((Map<String, Object>) rval).put(key, ((Map<String, Object>) out).get(key));
+ }
+ }
+ }
+
+ return rval;
+ }
+
+ /*
+ * TODO: this throws runtime exception. need to look at doing something more sane.
+ */
+ public Object compact(Map<String, Object> ctx, Object property, Object value, Map<String, Object> usedCtx) {
+
+ Object rval = null;
+ Map<String, String> keywords = JSONLDUtils.getKeywords(ctx);
+
+ if (value == null) {
+ rval = null;
+ // TODO: used ctx stuff may actually be handy here
+ JSONLDUtils.getCoercionType(ctx, (String) property, usedCtx);
+ } else if (value instanceof List) {
+ // recursively add compacted values to array
+ rval = new ArrayList<Object>();
+ for (Object o : (List<Object>) value) {
+ ((List) rval).add(compact(ctx, property, o, usedCtx));
+ }
+ } else if (value instanceof Map && ((Map) value).containsKey("@id") && ((Map) value).get("@id") instanceof List) {
+ // graph literal/disjoint graph
+ rval = new HashMap<String, Object>();
+ ((Map<String, Object>) rval).put(keywords.get("@id"), compact(ctx, property, ((Map) value).get("@id"), usedCtx));
+ } else if (JSONLDUtils.isSubject(value)) { // recurse if value is a
+ // subject
+ // recursively handle sub-properties that aren't a sub-context
+ rval = new HashMap<String, Object>();
+ for (String key : ((Map<String, Object>) value).keySet()) {
+ if (!"@context".equals(((Map<String, Object>) value).get(key))) {
+ // set object to compacted property, only overwrite existing
+ // properties if the property actually compacted
+ String p = JSONLDUtils.compactIRI(ctx, key, usedCtx);
+ if (!(key.equals(p)) || !((Map<String, Object>) rval).containsKey(p)) {
+ ((Map<String, Object>) rval).put(p, compact(ctx, key, ((Map<String, Object>) value).get(key), usedCtx));
+ }
+ }
+ }
+ } else {
+ // get coerce type
+ String coerce = JSONLDUtils.getCoercionType(ctx, (String) property, usedCtx);
+
+ // get type from value, to ensure coercion is valid
+ String type = null;
+ if (value instanceof Map) {
+ // type coercion can only occur if language is not specified
+ if (!((Map) value).containsKey("@language")) {
+ // type must match coerce type if specified
+ if (((Map) value).containsKey("@type")) {
+ type = (String) ((Map<String, Object>) value).get("@type");
+ } else if (((Map) value).containsKey("@id")) { // type is ID
+ // (IRI)
+ type = "@id";
+ } else { // can be coerced to any type
+ type = coerce;
+ }
+ }
+ } else if (value instanceof String) {
+ // type can be coerced to anything
+ type = coerce;
+ }
+
+ // types that can be auto-coerced from a JSON-builtin
+ if (coerce == null && (JSONLDConsts.XSD_BOOLEAN.equals(type) || JSONLDConsts.XSD_INTEGER.equals(type) || JSONLDConsts.XSD_DOUBLE.equals(type))) {
+ coerce = type;
+ }
+
+ // do reverse type-coercion
+ if (coerce != null) {
+ // type is only None if a language was specified, which is an
+ // error if type coercion is specified
+ if (type == null) {
+ throw new RuntimeException("Cannot coerce type when a language is " + "specified. The language information would be lost.");
+ } else if (!type.equals(coerce)) {
+ // if the value type does not match the coerce type, it is
+ // an error
+ throw new RuntimeException("Cannot coerce type because the type does not match.");
+ } else {
+ // do reverse type-coercion
+ if (value instanceof Map) {
+ if (((Map) value).containsKey("@id")) {
+ rval = ((Map) value).get("@id");
+ } else if (((Map) value).containsKey("@value")) {
+ rval = ((Map) value).get("@value");
+ }
+ } else {
+ rval = value;
+ }
+
+ // do basic JSON types conversion
+ if (JSONLDConsts.XSD_BOOLEAN.equals(coerce)) {
+ // TODO: this is a bit mad (and probably not exhaustive)
+ if (rval instanceof String) {
+ rval = "true".equals(rval);
+ } else if (rval instanceof Integer) {
+ rval = ((Integer) rval) != 0;
+ } else if (rval instanceof Double) {
+ rval = ((Double) rval) != 0.0;
+ } else if (rval instanceof Long) {
+ rval = ((Long) rval) != 0L;
+ } else if (rval instanceof Float) {
+ rval = ((Float) rval) != 0.0f;
+ } else if (rval instanceof Short) {
+ rval = ((Short) rval) != 0;
+ } else if (!(rval instanceof Boolean)) {
+ rval = false;
+ }
+ } else if (JSONLDConsts.XSD_DOUBLE.equals(coerce)) {
+ if (rval instanceof String) {
+ rval = Double.parseDouble((String) rval);
+ } else if (rval instanceof Number) {
+ rval = ((Number) rval).doubleValue();
+ }
+ } else if (JSONLDConsts.XSD_INTEGER.equals(coerce)) {
+ if (rval instanceof String) {
+ rval = Integer.parseInt((String) rval);
+ } else if (rval instanceof Number) {
+ rval = ((Number) rval).intValue();
+ }
+ }
+ }
+ } else if (value instanceof Map) {
+ // no type-coercion, just change keywords/copy value
+ rval = new HashMap<String, Object>();
+ for (String key : ((Map<String, Object>) value).keySet()) {
+ ((Map<String, Object>) rval).put(keywords.get(key), ((Map) value).get(key));
+ }
+ } else {
+ rval = JSONLDUtils.clone(value);
+ }
+
+ if ("@id".equals(type)) {
+ // compact IRI
+ if (rval instanceof Map) {
+ ((Map) rval).put(keywords.get("@id"), JSONLDUtils.compactIRI(ctx, (String) ((Map<String, Object>) rval).get(keywords.get("@id")), usedCtx));
+ } else {
+ rval = JSONLDUtils.compactIRI(ctx, (String) rval, usedCtx);
+ }
+ }
+ }
+ return rval;
+ }
+
+ public Object frame(Object input, Object frame) {
+ return frame(input, frame, null);
+ }
+
+ public Object frame(Object input, Object frame, Map options) {
+ Object rval = null;
+
+ input = normalize(input);
+
+ Object ctx = null;
+
+ if (frame instanceof Map && ((Map) frame).containsKey("@context")) {
+ ctx = JSONLDUtils.clone(((Map) frame).get("@context"));
+ frame = expand(frame);
+ } else if (frame instanceof List) {
+ if (((List) frame).size() > 0) {
+ Object f0 = ((List) frame).get(0);
+ if (f0 instanceof Map && ((Map) f0).containsKey("@context")) {
+ ctx = JSONLDUtils.clone(((Map) f0).get("@context"));
+ }
+
+ List tmp = new ArrayList();
+ for (Object f : (List) frame) {
+ tmp.add(expand(f));
+ }
+ frame = tmp;
+ }
+ }
+
+ Map defaultOptions = new HashMap();
+ Map tmpopts = new HashMap();
+ tmpopts.put("embedOn", true);
+ tmpopts.put("explicitOn", false);
+ tmpopts.put("omitDefaultOn", false);
+ defaultOptions.put("defaults", tmpopts);
+
+ // TODO: merge in options from input
+ options = defaultOptions;
+
+ Map subjects = new HashMap();
+ for (Object i : (List) input) {
+ subjects.put(((Map) i).get("@id"), i);
+ }
+
+ rval = JSONLDUtils.frame(subjects, (List) input, frame, new HashMap(), false, null, null, options);
+
+ if (ctx != null && rval != null) {
+ if (rval instanceof List) {
+ List tmp = (List) rval;
+ rval = new ArrayList();
+ for (Object i : tmp) {
+ ((List) rval).add(compact(ctx, i));
+ }
+ } else {
+ rval = compact(ctx, rval);
+ }
+ }
+
+ return rval;
+ }
+
+ public List<? extends Map<String, Object>> normalize(Object input) {
+ // because the expanded output of items from the onlinebox are the same
+ // as the normalized version
+ // (just inside a list) i'm going to skip implementing the normalize
+ // function for now.
+ // TODO: implement this properly as if data is really to be imported
+ // into the OB with this method
+ // this will be needed (mainly for identifying embedded items)
+ List<Map<String, Object>> rval = new ArrayList<Map<String, Object>>();
+
+ if (input != null) {
+
+ Object expanded = expand(new HashMap<String, Object>(), null, input);
+
+ nameBlankNodes(expanded);
+
+ Map<String, Object> subjects = new HashMap<String, Object>();
+ try {
+ flatten(null, null, expanded, subjects);
+ } catch (Exception e) {
+ // TODO: This should probably be thrown back to the caller
+ e.printStackTrace();
+ LOG.error("flatten failed!");
+ return null;
+ }
+
+ for (String key : subjects.keySet()) {
+ Map<String, Object> s = (Map<String, Object>) subjects.get(key);
+ // TODO: in javascript the keys are sorted and added back into
+ // the array
+ // in alphabetical order. however in HashMaps, this order isn't
+ // kept
+ rval.add(s);
+ }
+
+ canonicalizeBlankNodes(rval);
+
+ // sort the output
+ Collections.sort(rval, new Comparator<Map<String, Object>>() {
+ public int compare(Map<String, Object> a, Map<String, Object> b) {
+ return JSONLDUtils.compare(a.get("@id"), b.get("@id"));
+ }
+ });
+ }
+
+ return rval;
+ }
+
+ /**
+ *
+ *
+ * @return a list of objects returned by tripleCallback
+ */
+ public void triples(Object input, JSONLDTripleCallback tripleCallback) {
+ Object normalized = normalize(input);
+
+ if (tripleCallback == null) {
+ // TODO: make default triple callback
+ }
+
+ List<Object> rval = new ArrayList<Object>();
+ for (Map<String, Object> e : (List<Map<String, Object>>) normalized) {
+ String s = (String) e.get("@id");
+
+ for (String p : e.keySet()) {
+ Object obj = e.get(p);
+
+ // don't generate a triple for the @id or any keys that should
+ // be ignored
+ if (p.equals("@id") || ignoredKeywords.contains(p)) {
+ continue;
+ } else if (p.equals("@type")) {
+ p = JSONLDConsts.RDF_SYNTAX_NS + "type";
+ }
+
+ if (!(obj instanceof List)) {
+ List<Object> tmp = new ArrayList<Object>();
+ tmp.add(obj);
+ obj = tmp;
+ }
+ for (Object o : (List<Object>) obj) {
+ if (o instanceof String) {
+ // type is a special case where the uri isn't expanded
+ // out into an object
+ if (p.toString().equals(JSONLDConsts.RDF_SYNTAX_NS + "type")) {
+ tripleCallback.triple(s, p, o.toString());
+ } else {
+ tripleCallback.triple(s, p, (String) o, JSONLDConsts.XSD_STRING, null);
+ }
+ } else if (o instanceof Map) {
+ if (((Map) o).containsKey("@value")) {
+ if (((Map) o).containsKey("@type")) {
+ String datatypeURI = (String) ((Map) o).get("@type");
+ String value = (String) ((Map) o).get("@value");
+ tripleCallback.triple(s, p, value, datatypeURI, null);
+ } else if (((Map) o).containsKey("@language")) {
+ tripleCallback.triple(s, p, (String) ((Map) o).get("@value"), JSONLDConsts.XSD_STRING, (String) ((Map) o).get("@language"));
+ } else {
+ tripleCallback.triple(s, p, (String) ((Map) o).get("@value"), JSONLDConsts.XSD_STRING, null);
+ }
+ } else if (((Map) o).containsKey("@id")) {
+ tripleCallback.triple(s, p, (String) ((Map) o).get("@id"));
+ } else {
+ // TODO: have i missed anything?
+ return;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * public Object simplify(Map input) { return simplify(input, new HashMap()); }
+ */
+
+ public static void generateSimplifyContext(Object input, Map<String, Object> ctx) {
+ if (input instanceof List) {
+ for (Object o : (List) input) {
+ generateSimplifyContext(o, ctx);
+ }
+ } else if (input instanceof Map) {
+ Map<String, Object> o = (Map<String, Object>) input;
+ for (String key : o.keySet()) {
+ Object val = o.get(key);
+ if (key.matches("^https?://.+$")) {
+ int idx = key.lastIndexOf('#');
+ if (idx < 0) {
+ idx = key.lastIndexOf('/');
+ }
+ String skey = key.substring(idx + 1);
+ Object keyval = key;
+ if (val instanceof Map) {
+ if (((Map) val).containsKey("@id")) {
+ Map tmp = new HashMap();
+ tmp.put("@type", "@id");
+ tmp.put("@id", key);
+ keyval = tmp;
+ }
+ }
+ while (true) {
+ // check if the key is already in the frame ctx
+ if (ctx.containsKey(skey)) {
+ // if so, check if the values are the same
+ if (ctx.get(skey).equals(keyval)) {
+ // if they are, skip adding this
+ break;
+ }
+ // if not, add a _ to the simple key and try again
+ skey += "_";
+ } else {
+ ctx.put(skey, keyval);
+ break;
+ }
+ }
+ }
+ if (val instanceof Map || val instanceof List) {
+ generateSimplifyContext(val, ctx);
+ }
+ }
+ }
+ }
+
+ /**
+ * automatically builds a frame which attempts to simplify the keys and values as much as possible
+ *
+ * NOTE: this is experimental and only built for specific conditions
+ *
+ * @param input
+ * @return
+ */
+ public Object simplify(Map input) {
+
+ Map<String, Object> origCtx = (Map<String, Object>) input.get("@context");
+ Object expanded = expand(input);
+ Map<String, Object> framectx = new HashMap<String, Object>();
+
+ generateSimplifyContext(expanded, framectx);
+
+ if (origCtx != null) {
+ framectx = JSONLDUtils.mergeContexts(origCtx, framectx);
+ }
+
+ return compact(framectx, expanded);
+ }
+
+ private Map<String, Object> nestCore(Map<String, Object> rootObj, Map<String, Map<String, Object>> otherObjs) {
+ Map<String, Object> rval = new HashMap<String, Object>();
+ for (String key : rootObj.keySet()) {
+ Object val = rootObj.get(key);
+ if (ignoredKeywords.contains(key)) {
+ rval.put(key, val);
+ } else if (val instanceof List) {
+ List<Object> lv = new ArrayList<Object>();
+ for (Map<String, Object> o : (List<Map<String, Object>>) val) {
+ lv.add(nestCore(o, otherObjs));
+ }
+ rval.put(key, lv);
+ } else if (val instanceof Map) {
+ // TODO: should this be true as well? ((Map) val).size() == 1
+ if (((Map) val).containsKey("@id") && otherObjs.containsKey(((Map) val).get("@id"))) {
+ rval.put(key, otherObjs.get(((Map) val).get("@id")));
+ } else {
+ rval.put(key, nestCore((Map<String, Object>) val, otherObjs));
+ }
+ } else {
+ rval.put(key, val);
+ }
+ }
+ return rval;
+ }
+
+ /**
+ * expands all the objects in the input list, and nests all the non-root object lists
+ * into the root object, resulting in a single object
+ *
+ * TODO: i'm not sure if the way i'm keeping the original context is what i really want
+ *
+ * @param input
+ * @param rootObjId
+ * @return
+ */
+ public Object nest(List<Map<String, Object>> input, String rootObjId) {
+ Map<String, Object> rootObj = null;
+ Map<String, Object> rootObjCtx = null;
+ Map<String, Map<String, Object>> otherObjs = new HashMap<String, Map<String, Object>>();
+ // find the root object and build a map of the non-root objects mapped by id
+ for (Map<String, Object> item : input) {
+ if (item.containsKey("@id")) {
+ if (rootObjId.equals(item.get("@id"))) {
+ rootObjCtx = (Map<String, Object>) item.get("@context");
+ rootObj = (Map<String, Object>) expand(item);
+ } else {
+ //Map<String, Object> clone = (Map<String, Object>) JSONLDUtils.clone(item);
+ //clone.remove("@id");
+ otherObjs.put((String) item.get("@id"), (Map<String, Object>) expand(item));
+ }
+ }
+ }
+
+ if (rootObj == null) {
+ // no object matching the root object found, should probably return an error actually
+ // TODO: throw runtimeexception when the rest of the library is updated
+ return input;
+ }
+
+ // this nests all the elements in the input once (not including the root object)
+ Map<String, Map<String, Object>> nestedOthers = new HashMap<String, Map<String, Object>>();
+ for (String key : otherObjs.keySet()) {
+ Map<String, Object> val = otherObjs.get(key);
+ nestedOthers.put(key, nestCore(val, otherObjs));
+ }
+ // nests the root object with the nested other objects
+ Map<String, Object> rval = nestCore(rootObj, nestedOthers);
+
+ // compact the results with the original root object's context
+ return compact(rootObjCtx != null ? rootObjCtx : new HashMap<String, Object>(), rval);
+ }
+
+ public void nameBlankNodes(Object input) {
+ JSONLDUtils.NameGenerator ng = new JSONLDUtils.NameGenerator("tmp");
+ this.ngtmp = ng;
+
+ // Map<String,Object> subjects = new HashMap<String, Object>();
+ subjects = new HashMap<String, Object>();
+ List<Map<String, Object>> bnodes = new ArrayList<Map<String, Object>>();
+
+ collectSubjects(input, subjects, bnodes);
+
+ for (Map<String, Object> bnode : bnodes) {
+ if (!bnode.containsKey("@id")) {
+ while (subjects.containsKey(ng.next()))
+ ;
+ ((Map<String, Object>) bnode).put("@id", ng.current());
+ subjects.put(ng.current(), bnode);
+ }
+ }
+ }
+
+ private void flatten(Object parent, String parentProperty, Object value, Map<String, Object> subjects) throws Exception {
+
+ Object flattened = null;
+
+ if (value == null) {
+ // drop null values
+ } else if (value instanceof List) {
+ for (Object v : (List<Object>) value) {
+ flatten(parent, parentProperty, v, subjects);
+ }
+ } else if (value instanceof Map) {
+ Map<String, Object> mapVal = (Map<String, Object>) value;
+ if (mapVal.containsKey("@value") || "@type".equals(parentProperty)) {
+ // already-expanded value
+ flattened = JSONLDUtils.clone(value);
+ } else if (mapVal.get("@id") instanceof List) {
+ // graph literal/disjoint graph
+ if (parent != null) {
+ // cannot flatten embedded graph literals
+ throw new Exception("Embedded graph literals cannot be flattened");
+ }
+
+ // top-level graph literal
+ for (Object key : (List<Object>) mapVal.get("@id")) {
+ if (!ignoredKeywords.contains(key)) {
+ flatten(parent, parentProperty, key, subjects);
+ }
+ }
+ } else { // regular subject
+ // create of fetch existing subject
+ Object subject;
+ if (subjects.containsKey(mapVal.get("@id"))) {
+ subject = subjects.get(mapVal.get("@id"));
+ } else {
+ subject = new HashMap<String, Object>();
+ ((Map<String, Object>) subject).put("@id", mapVal.get("@id"));
+ subjects.put((String) mapVal.get("@id"), subject);
+ }
+ flattened = new HashMap<String, Object>();
+ ((Map<String, Object>) flattened).put("@id", ((Map<String, Object>) subject).get("@id"));
+
+ for (String key : mapVal.keySet()) {
+ Object v = mapVal.get(key);
+
+ if (ignoredKeywords.contains(key)) {
+ ((Map<String, Object>) subject).put(key, v);
+ } else if (v != null && !"@id".equals(key)) {
+ if (((Map<String, Object>) subject).containsKey(key)) {
+ if (!(((Map<String, Object>) subject).get(key) instanceof List)) {
+ Object tmp = ((Map<String, Object>) subject).get(key);
+ List<Object> lst = new ArrayList<Object>();
+ lst.add(tmp);
+ ((Map<String, Object>) subject).put(key, lst);
+ }
+ } else {
+ List<Object> lst = new ArrayList<Object>();
+ ((Map<String, Object>) subject).put(key, lst);
+ }
+
+ flatten(((Map<String, Object>) subject).get(key), key, v, subjects);
+ if (((List<Object>) ((Map<String, Object>) subject).get(key)).size() == 1) {
+ // convert subject[key] to a single object if there
+ // is only one object in the list
+ ((Map<String, Object>) subject).put(key, ((List<Object>) ((Map<String, Object>) subject).get(key)).get(0));
+ }
+ }
+ }
+ }
+ } else {
+ // string value
+ flattened = value;
+ }
+
+ if (flattened != null && parent != null) {
+ if (parent instanceof List) {
+ boolean duplicate = false;
+ for (Object e : (List<Object>) parent) {
+ if (JSONLDUtils.compareObjects(e, flattened) == 0) {
+ duplicate = true;
+ break;
+ }
+ }
+ if (!duplicate) {
+ ((List<Object>) parent).add(flattened);
+ }
+ } else {
+ ((Map<String, Object>) parent).put(parentProperty, flattened);
+ }
+ }
+ }
+
+ private void collectEdges() {
+ Map<String, Object> refs = (Map<String, Object>) this.edges.get("refs");
+ Map<String, Object> props = (Map<String, Object>) this.edges.get("props");
+
+ for (String iri : this.subjects.keySet()) {
+ Map<String, Object> subject = (Map<String, Object>) this.subjects.get(iri);
+ for (String key : subject.keySet()) {
+ if (!key.equals("@id") && !ignoredKeywords.contains(key)) {
+ Object object = subject.get(key);
+ List<Object> tmp = null;
+ if (object instanceof List) {
+ tmp = (List<Object>) object;
+ } else {
+ tmp = new ArrayList<Object>();
+ tmp.add(object);
+ }
+ for (Object o : tmp) {
+ if (o instanceof Map && ((Map) o).containsKey("@id") && this.subjects.containsKey(((Map) o).get("@id"))) {
+ Object objIri = ((Map<String, Object>) o).get("@id");
+ Map<String, Object> tmp1 = new HashMap<String, Object>();
+ tmp1.put("s", iri);
+ tmp1.put("p", key);
+ ((Map<String, List>) refs.get(objIri)).get("all").add(tmp1);
+ tmp1 = new HashMap<String, Object>();
+ tmp1.put("s", objIri);
+ tmp1.put("p", key);
+ ((Map<String, List>) props.get(iri)).get("all").add(tmp1);
+ }
+ }
+ }
+ }
+ }
+
+ Comparator<Object> edgesCmp = new Comparator<Object>() {
+ public int compare(Object a, Object b) {
+ return compareEdges(a, b);
+ }
+ };
+
+ for (String iri : refs.keySet()) {
+ List<Object> all = (List<Object>) ((Map<String, Object>) refs.get(iri)).get("all");
+ Collections.sort(all, edgesCmp);
+ List<Object> bnodes = new ArrayList<Object>();
+ for (Object edge : all) {
+ if (JSONLDUtils.isBlankNodeIri(((Map<String, Object>) edge).get("s"))) {
+ bnodes.add(edge);
+ }
+ }
+ ((Map<String, Object>) refs.get(iri)).put("bnodes", bnodes);
+ }
+ for (String iri : props.keySet()) {
+ List<Object> all = (List<Object>) ((Map<String, Object>) props.get(iri)).get("all");
+ Collections.sort(all, edgesCmp);
+ List<Object> bnodes = new ArrayList<Object>();
+ for (Object edge : all) {
+ if (JSONLDUtils.isBlankNodeIri(((Map<String, Object>) edge).get("s"))) {
+ bnodes.add(edge);
+ }
+ }
+ ((Map<String, Object>) props.get(iri)).put("bnodes", bnodes);
+ }
+
+ }
+
+ public void canonicalizeBlankNodes(List<Map<String, Object>> input) {
+
+ this.renamed = new HashMap<String, Object>();
+ this.serializations = new HashMap<String, Object>();
+ this.edges = new HashMap<String, Object>();
+ edges.put("refs", new HashMap<String, Object>());
+ edges.put("props", new HashMap<String, Object>());
+
+ this.subjects = new HashMap<String, Object>();
+ List<Map<String, Object>> bnodes = new ArrayList<Map<String, Object>>();
+
+ for (Map<String, Object> s : input) {
+ String iri = (String) s.get("@id");
+ subjects.put(iri, s);
+ Map<String, Object> refs = (Map<String, Object>) edges.get("refs");
+ Map<String, List> tmp = new HashMap<String, List>();
+ tmp.put("all", new ArrayList<Object>());
+ tmp.put("bnodes", new ArrayList<Object>());
+ refs.put(iri, tmp);
+ Map<String, Object> props = (Map<String, Object>) edges.get("props");
+ tmp = new HashMap<String, List>();
+ tmp.put("all", new ArrayList<Object>());
+ tmp.put("bnodes", new ArrayList<Object>());
+ props.put(iri, tmp);
+
+ if (JSONLDUtils.isBlankNodeIri(iri)) {
+ bnodes.add(s);
+ }
+ }
+
+ collectEdges();
+
+ this.ngc14n = new NameGenerator("c14n");
+ NameGenerator c14n = this.ngc14n;
+ NameGenerator ngTmp = this.ngtmp;
+
+ for (Map<String, Object> bnode : bnodes) {
+ String iri = (String) bnode.get("@id");
+ if (c14n.inNamespace(iri)) {
+ while (subjects.containsKey(ngTmp.next()))
+ ;
+ renameBlankNode(bnode, ngTmp.current());
+ iri = (String) bnode.get("@id");
+ }
+ Map<String, Object> tmp = new HashMap<String, Object>();
+ tmp.put("props", null);
+ tmp.put("refs", null);
+ serializations.put(iri, tmp);
+ }
+
+ Comparator<Map<String, Object>> bnodeSort = new Comparator<Map<String, Object>>() {
+ private JSONLDProcessor processor;
+
+ public Comparator<Map<String, Object>> setProcessor(JSONLDProcessor p) {
+ processor = p;
+ return this;
+ }
+
+ public int compare(Map<String, Object> a, Map<String, Object> b) {
+ int rval = processor.deepCompareBlankNodes(a, b);
+ return rval;
+ }
+ }.setProcessor(this);
+
+ // keep sorting and naming blank nodes until they are all named
+ boolean resort = true;
+ while (bnodes.size() > 0) {
+
+ if (resort) {
+ resort = false;
+ Collections.sort(bnodes, bnodeSort);
+ }
+
+ Map<String, Object> bnode = bnodes.get(0);
+ bnodes.remove(0);
+ String iri = (String) bnode.get("@id");
+ resort = serializations.containsKey(iri) && ((Map<String, Object>) serializations.get(iri)).get("props") != null;
+ Map<String, Object> mapping = null;
+ for (String dir : new String[] { "props", "refs" }) {
+ // if no serialization has been computed, name only the first
+ // node
+ if (serializations.containsKey(iri) && ((Map<String, Object>) serializations.get(iri)).containsKey(dir)
+ && ((Map<String, Object>) serializations.get(iri)).get(dir) != null) {
+ mapping = (Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) serializations.get(iri)).get(dir)).get("m");
+ } else {
+ mapping = new HashMap<String, Object>();
+ mapping.put(iri, "s1");
+ }
+
+ // TODO: sort keys by value to name them in order
+ List<String> keys = new ArrayList<String>(mapping.keySet());
+ Collections.sort(keys, new Comparator<String>() {
+ private Map<String, Object> mapping;
+
+ public Comparator<String> setMapping(Map<String, Object> m) {
+ this.mapping = m;
+ return this;
+ }
+
+ public int compare(String a, String b) {
+ return JSONLDUtils.compare(this.mapping.get(a), this.mapping.get(b));
+ }
+ }.setMapping(mapping));
+
+ // name bnodes in mapping
+ List<String> renamed = new ArrayList<String>();
+ for (String iriK : keys) {
+ if (!c14n.inNamespace(iri) && subjects.containsKey(iriK)) {
+ renameBlankNode((Map<String, Object>) subjects.get(iriK), c14n.next());
+ renamed.add(iriK);
+ }
+ }
+
+ // only keep non-canonically named bnodes
+ List<Map<String, Object>> tmp = bnodes;
+ bnodes = new ArrayList<Map<String, Object>>();
+ for (Map<String, Object> b : tmp) {
+ String iriB = (String) b.get("@id");
+ if (!c14n.inNamespace(iriB)) {
+ for (Object i2 : renamed) {
+ if (markSerializationDirty(iriB, i2, dir)) {
+ resort = true;
+ }
+ }
+ bnodes.add(b);
+ }
+ }
+ }
+ }
+
+ for (String key : ((Map<String, Object>) edges.get("props")).keySet()) {
+ if (((List<Object>) ((Map<String, Object>) ((Map<String, Object>) edges.get("props")).get(key)).get("bnodes")).size() > 0) {
+ Map<String, Object> bnode = (Map<String, Object>) subjects.get(key);
+ for (String p : bnode.keySet()) {
+ if (!p.startsWith("@") && bnode.get(p) instanceof List) {
+ Collections.sort((List<Object>) bnode.get(p), new Comparator<Object>() {
+ public int compare(Object o1, Object o2) {
+ return JSONLDUtils.compareObjects(o1, o2);
+ }
+
+ });
+ }
+ }
+
+ }
+ }
+
+ }
+
+ private boolean markSerializationDirty(String iri, Object changed, String dir) {
+ boolean rval = false;
+ Object s = serializations.get(iri);
+ if (((Map<String, Object>) s).containsKey(dir) && ((Map<String, Object>) s).get(dir) != null
+ && ((Map<String, Object>) ((Map<String, Object>) ((Map<String, Object>) s).get(dir)).get("m")).containsKey(changed)) {
+ ((Map<String, Object>) s).put(dir, null);
+ rval = true;
+ }
+ return rval;
+ }
+
+ private void renameBlankNode(Map<String, Object> b, String id) {
+
+ String old = (String) b.get("@id");
+ b.put("@id", id);
+
+ subjects.put(id, subjects.get(old));
+ subjects.remove(old);
+
+ // update reference and property lists
+ ((Map<String, Object>) edges.get("refs")).put(id, ((Map<String, Object>) edges.get("refs")).get(old));
+ ((Map<String, Object>) edges.get("props")).put(id, ((Map<String, Object>) edges.get("props")).get(old));
+ ((Map<String, Object>) edges.get("refs")).remove(old);
+ ((Map<String, Object>) edges.get("props")).remove(old);
+
+ // update references to this bnode
+ List<Map<String, Object>> refs = (List<Map<String, Object>>) ((Map<String, Object>) ((Map<String, Object>) edges.get("refs")).get(id)).get("all");
+ for (Map<String, Object> i : refs) {
+ String iri = (String) i.get("s");
+ if (iri.equals(old)) {
+ iri = id;
+ }
+ Map<String, Object> ref = (Map<String, Object>) subjects.get(iri);
+ List<Map<String, Object>> props = (List<Map<String, Object>>) ((Map<String, Object>) ((Map<String, Object>) edges.get("props")).get(iri))
+ .get("all");
+ for (Map<String, Object> i2 : props) {
+ if (old.equals(i2.get("s"))) {
+ i2.put("s", id);
+ String p = (String) i2.get("p");
+ List<Object> tmp = null;
+ if (ref.get(p) instanceof Map) {
+ tmp = new ArrayList<Object>();
+ tmp.add(ref.get(p));
+ } else if (ref.get(p) instanceof List) {
+ tmp = (List<Object>) ref.get(p);
+ } else {
+ tmp = new ArrayList<Object>();
+ }
+
+ for (Object n : tmp) {
+ if (n instanceof Map && ((Map) n).containsKey("@id") && old.equals(((Map<String, Object>) n).get("@id"))) {
+ ((Map<String, Object>) n).put("@id", id);
+ }
+ }
+ }
+ }
+ }
+
+ // update references from this bnode
+ List<Map<String, Object>> props = (List<Map<String, Object>>) ((Map<String, Object>) ((Map<String, Object>) edges.get("props")).get(id)).get("all");
+ for (Map<String, Object> i : props) {
+ String iri = (String) i.get("s");
+ refs = (List<Map<String, Object>>) ((Map<String, Object>) ((Map<String, Object>) edges.get("refs")).get(iri)).get("all");
+ for (Map<String, Object> r : refs) {
+ if (old.equals(r.get("s"))) {
+ r.put("s", id);
+ }
+ }
+ }
+ }
+
+ private int deepCompareBlankNodes(Map<String, Object> a, Map<String, Object> b) {
+ int rval = 0;
+
+ String iriA = (String) a.get("@id");
+ String iriB = (String) b.get("@id");
+
+ if (iriA.equals(iriB)) {
+ rval = 0;
+ } else {
+ // try a shallow compare first
+ rval = shallowCompareBlankNodes(a, b);
+
+ if (rval == 0) {
+ // deep compare is needed
+ String[] dirs = new String[] { "props", "refs" };
+ for (int i = 0; rval == 0 && i < dirs.length; i++) {
+ String dir = dirs[i];
+ Map<String, Object> sA = (Map<String, Object>) serializations.get(iriA);
+ Map<String, Object> sB = (Map<String, Object>) serializations.get(iriB);
+ if (sA.get(dir) == null) {
+ MappingBuilder mb = new MappingBuilder();
+ if (dir.equals("refs")) {
+ mb.mapping = (Map<String, String>) JSONLDUtils.clone(((Map<String, Object>) sA.get("props")).get("m"));
+ mb.count = mb.mapping.size() + 1;
+ }
+ serializeBlankNode(sA, iriA, mb, dir);
+ }
+ if (sB.get(dir) == null) {
+ MappingBuilder mb = new MappingBuilder();
+ if (dir.equals("refs")) {
+ mb.mapping = (Map<String, String>) JSONLDUtils.clone(((Map<String, Object>) sB.get("props")).get("m"));
+ mb.count = mb.mapping.size() + 1;
+ }
+ serializeBlankNode(sB, iriB, mb, dir);
+ }
+
+ rval = JSONLDUtils.compare(((Map<String, Object>) sA.get(dir)).get("s"), ((Map<String, Object>) sB.get(dir)).get("s"));
+ }
+ }
+ }
+
+ return rval;
+ }
+
+ private void serializeBlankNode(Map<String, Object> s, String iri, MappingBuilder mb, String dir) {
+ if (!(mb.processed.containsKey(iri))) {
+ mb.processed.put(iri, true);
+ String siri = mb.mapNode(iri);
+
+ MappingBuilder original = mb.copy();
+
+ List<Object> adj = (List<Object>) ((Map<String, Object>) ((Map<String, Object>) edges.get(dir)).get(iri)).get("bnodes");
+ Map<String, Object> mapped = new HashMap<String, Object>();
+ List<Object> notMapped = new ArrayList<Object>();
+
+ for (Object i : adj) {
+ if (mb.mapping.containsKey(((Map<String, Object>) i).get("s"))) {
+ mapped.put(mb.mapping.get(((Map<String, Object>) i).get("s")), ((Map<String, Object>) i).get("s"));
+ } else {
+ notMapped.add(i);
+ }
+ }
+
+ int combos = Math.max(1, notMapped.size());
+ for (int i = 0; i < combos; ++i) {
+ MappingBuilder m = (i == 0) ? mb : original.copy();
+ serializeCombos(s, iri, siri, mb, dir, mapped, notMapped);
+ }
+ }
+ }
+
+ private void serializeCombos(Map<String, Object> s, String iri, String siri, MappingBuilder mb, String dir, Map<String, Object> mapped,
+ List<Object> notMapped) {
+ if (notMapped.size() > 0) {
+ mapped = (Map<String, Object>) JSONLDUtils.clone(mapped);
+ mapped.put(mb.mapNode((String) ((Map<String, Object>) notMapped.get(0)).get("s")), ((Map<String, Object>) notMapped.get(0)).get("s"));
+
+ MappingBuilder original = mb.copy();
+ notMapped.remove(0);
+
+ int rotations = Math.max(1, notMapped.size());
+ for (int r = 0; r < rotations; ++r) {
+ MappingBuilder m = (r == 0) ? mb : original.copy();
+ serializeCombos(s, iri, siri, m, dir, mapped, notMapped);
+ JSONLDUtils.rotate(notMapped);
+ }
+ } else {
+ List<String> keys = new ArrayList<String>(mapped.keySet());
+ Collections.sort(keys);
+ Map<String, Object> tmp = new HashMap<String, Object>();
+ tmp.put("i", iri);
+ tmp.put("k", keys);
+ tmp.put("m", mapped);
+ mb.adj.put(siri, tmp);
+ mb.serialize(this.subjects, this.edges);
+
+ if (s.get(dir) == null || JSONLDUtils.compareSerializations(mb.s, (String) ((Map<String, Object>) s.get(dir)).get("s")) <= 0) {
+ for (String k : keys) {
+ serializeBlankNode(s, (String) mapped.get(k), mb, dir);
+ }
+
+ mb.serialize(this.subjects, this.edges);
+ if (s.get(dir) == null || JSONLDUtils.compareSerializations(mb.s, (String) ((Map<String, Object>) s.get(dir)).get("s")) <= 0
+ && mb.s.length() >= ((String) ((Map<String, Object>) s.get(dir)).get("s")).length()) {
+ tmp = new HashMap<String, Object>();
+ tmp.put("s", mb.s);
+ tmp.put("m", mb.mapping);
+ s.put(dir, tmp);
+ }
+ }
+ }
+ }
+
+ private int shallowCompareBlankNodes(Map<String, Object> a, Map<String, Object> b) {
+ int rval = 0;
+
+ List<String> pA = new ArrayList<String>();
+ pA.addAll(a.keySet());
+ List<String> pB = new ArrayList<String>();
+ pB.addAll(b.keySet());
+
+ rval = JSONLDUtils.compare(pA.size(), pB.size());
+
+ if (rval == 0) {
+ Collections.sort(pA);
+ Collections.sort(pB);
+ rval = JSONLDUtils.compare(pA, pB);
+ }
+
+ if (rval == 0) {
+ rval = JSONLDUtils.compareBlankNodeObjects(a, b);
+ }
+
+ if (rval == 0) {
+ List<Object> edgesA = (List<Object>) ((Map<String, Object>) ((Map<String, Object>) edges.get("refs")).get(a.get("@id"))).get("all");
+ List<Object> edgesB = (List<Object>) ((Map<String, Object>) ((Map<String, Object>) edges.get("refs")).get(b.get("@id"))).get("all");
+ rval = JSONLDUtils.compare(edgesA.size(), edgesB.size());
+
+ if (rval == 0) {
+ for (int i = 0; i < edgesA.size() && rval == 0; ++i) {
+ rval = compareEdges(edgesA.get(i), edgesB.get(i));
+ }
+ }
+ }
+
+ return rval;
+ }
+
+ private int compareEdges(Object a, Object b) {
+ int rval = 0;
+
+ boolean bnodeA = JSONLDUtils.isBlankNodeIri(((Map<String, Object>) a).get("s"));
+ boolean bnodeB = JSONLDUtils.isBlankNodeIri(((Map<String, Object>) b).get("s"));
+ JSONLDUtils.NameGenerator c14n = ngc14n;
+
+ if (bnodeA != bnodeB) {
+ rval = bnodeA ? 1 : -1;
+ } else {
+
+ if (!bnodeA) {
+ rval = JSONLDUtils.compare(((Map<String, Object>) a).get("s"), ((Map<String, Object>) b).get("s"));
+ }
+ if (rval == 0) {
+ rval = JSONLDUtils.compare(((Map<String, Object>) a).get("p"), ((Map<String, Object>) b).get("p"));
+ }
+
+ if (rval == 0 && c14n != null) {
+ boolean c14nA = c14n.inNamespace((String) ((Map<String, Object>) a).get("s"));
+ boolean c14nB = c14n.inNamespace((String) ((Map<String, Object>) b).get("s"));
+
+ if (c14nA != c14nB) {
+ rval = c14nA ? 1 : -1;
+ } else if (c14nA) {
+ rval = JSONLDUtils.compare(((Map<String, Object>) a).get("s"), ((Map<String, Object>) b).get("s"));
+ }
+
+ }
+
+ }
+
+ return rval;
+ }
+
+ private void collectSubjects(Object input, Map<String, Object> subjects, List<Map<String, Object>> bnodes) {
+ if (input == null) {
+ return;
+ } else if (input instanceof List) {
+ for (Object o : (List<Object>) input) {
+ collectSubjects(o, subjects, bnodes);
+ }
+ } else if (input instanceof Map) {
+ if (((Map<String, Object>) input).containsKey("@id")) {
+ Object id = ((Map<String, Object>) input).get("@id");
+ if (id instanceof List) {
+ // graph literal
+ collectSubjects(id, subjects, bnodes);
+ } else if (JSONLDUtils.isSubject(input)) {
+ // named subject
+ subjects.put((String) id, input);
+ }
+
+ } else if (JSONLDUtils.isBlankNode(input)) {
+ bnodes.add((Map<String, Object>) input);
+ }
+
+ for (String key : ((Map<String, Object>) input).keySet()) {
+ if (!ignoredKeywords.contains(key)) {
+ collectSubjects(((Map<String, Object>) input).get(key), subjects, bnodes);
+ }
+ }
+ }
+ }
+
+ /**
+ * TODO: this whole thing should probably be optimized
+ *
+ * why doesn't Java make using maps and lists easy?!?!?!??!?
+ *
+ * @author tristan
+ *
+ */
+ private class MappingBuilder {
+
+ public MappingBuilder() {
+ this.count = 1;
+ this.processed = new HashMap<String, Boolean>();
+ this.mapping = new HashMap<String, String>();
+ this.adj = new HashMap<String, Object>();
+
+ // this.keyStack = [{ keys: ['s1'], idx: 0 }];
+ this.keyStack = new ArrayList<Object>();
+ Map<String, Object> t1 = new HashMap<String, Object>();
+ List<String> t2 = new ArrayList<String>();
+ t2.add("s1");
+ t1.put("keys", t2);
+ t1.put("idx", 0);
+ keyStack.add(t1);
+ this.done = new HashMap<String, Boolean>();
+ this.s = "";
+ }
+
+ public HashMap<String, Boolean> done;
+ public ArrayList<Object> keyStack;
+ public String s;
+ public Map<String, Object> adj;
+ public Map<String, Boolean> processed;
+ public int count;
+ public Map<String, String> mapping;
+
+ /**
+ * Maps the next name to the given bnode IRI if the bnode IRI isn't already in the mapping. If the given bnode IRI is canonical, then it will be given a
+ * shortened form of the same name.
+ *
+ * @param iri
+ * the blank node IRI to map the next name to.
+ *
+ * @return the mapped name.
+ */
+ public String mapNode(String iri) {
+ if (!this.mapping.containsKey(iri)) {
+ if (iri.startsWith("_:c14n")) {
+ this.mapping.put(iri, "c" + iri.substring(6));
+ } else {
+ this.mapping.put(iri, "s" + this.count);
+ this.count += 1;
+ }
+ }
+ return this.mapping.get(iri);
+ }
+
+ public void serialize(Map<String, Object> subjects, Map<String, Object> edges) {
+ if (this.keyStack.size() > 0) {
+ Map<String, Object> next = (Map<String, Object>) this.keyStack.remove(this.keyStack.size() - 1);
+ // for (; (Integer)next.get("idx") < ((List<String>)
+ // next.get("keys")).size(); next.put("idx",
+ // (Integer)next.get("idx")+1)) {
+ while ((Integer) next.get("idx") < ((List<String>) next.get("keys")).size()) {
+ String k = ((List<String>) next.get("keys")).get((Integer) next.get("idx"));
+ if (!this.adj.containsKey(k)) {
+ this.keyStack.add(next);
+ break;
+ }
+ next.put("idx", (Integer) next.get("idx") + 1);
+
+ if (this.done.containsKey(k)) {
+ this.s += "_" + k;
+ } else {
+ this.done.put(k, true);
+
+ String s = k;
+ Map<String, Object> adj = (Map<String, Object>) this.adj.get(k);
+ String iri = (String) adj.get("i");
+ if (subjects.containsKey(iri)) {
+ Map<String, Object> b = (Map<String, Object>) subjects.get(iri);
+ s += "[" + JSONLDUtils.serializeProperties(b) + "]";
+
+ Boolean first = true;
+ s += "[";
+ List<Map<String, Object>> refs = (List<Map<String, Object>>) ((Map<String, Object>) ((Map<String, Object>) edges.get("refs"))
+ .get(iri)).get("all");
+ for (Map<String, Object> r : refs) {
+ if (first) {
+ first = false;
+ } else {
+ s += "|";
+ }
+ s += "<" + r.get("p") + ">";
+ s += JSONLDUtils.isBlankNodeIri(r.get("s")) ? "_:" : ("<" + r.get("s") + ">");
+ }
+ s += "]";
+ }
+
+ for (String o : (List<String>) adj.get("k")) {
+ s += o;
+ }
+ this.s += s;
+ Map<String, Object> tmp = new HashMap<String, Object>();
+ tmp.put("keys", adj.get("k"));
+ tmp.put("idx", 0);
+ this.keyStack.add(tmp);
+ this.serialize(subjects, edges);
+ }
+ }
+ }
+ }
+
+ public MappingBuilder copy() {
+ MappingBuilder rval = new MappingBuilder();
+ rval.count = this.count;
+ rval.processed = (Map<String, Boolean>) JSONLDUtils.clone(this.processed);
+ rval.mapping = (Map<String, String>) JSONLDUtils.clone(this.mapping);
+ rval.adj = (Map<String, Object>) JSONLDUtils.clone(this.adj);
+ rval.keyStack = (ArrayList<Object>) JSONLDUtils.clone(this.keyStack);
+ rval.done = (HashMap<String, Boolean>) JSONLDUtils.clone(this.done);
+
+ rval.s = this.s;
+ return rval;
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/1587eba0/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDSerializer.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDSerializer.java b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDSerializer.java
new file mode 100644
index 0000000..5935071
--- /dev/null
+++ b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDSerializer.java
@@ -0,0 +1,241 @@
+package de.dfki.km.json.jsonld;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.io.Writer;
+
+import de.dfki.km.json.JSONUtils;
+
+/**
+ * TODO:
+ *
+ * @author tristan
+ *
+ */
+public class JSONLDSerializer {
+
+ private Map<String, Map<String, Object>> _subjects;
+ private Map<String, Object> _context;
+
+ JSONLDUtils.NameGenerator _ng;
+ Map<String, String> _bns;
+
+ public JSONLDSerializer() {
+ reset();
+ }
+
+ /**
+ * Resets the Serializer. Call this if you want to reuse the serializer for a different document
+ */
+ public void reset() {
+ _subjects = new HashMap<String, Map<String, Object>>();
+ _context = new HashMap<String, Object>();
+ _context.put("rdf", JSONLDConsts.RDF_SYNTAX_NS);
+ _context.put("rdfs", JSONLDConsts.RDF_SCHEMA_NS);
+ _context.put("xsd", JSONLDConsts.XSD_NS);
+
+ _ng = new JSONLDUtils.NameGenerator("bn");
+ _bns = new HashMap<String, String>();
+ }
+
+ // some helper functions for extended classes
+ protected Map<String, Object> getSubject(String subjURI) {
+ return _subjects.get(subjURI);
+ }
+
+ protected void setSubject(String subjURI, Map<String, Object> subj) {
+ _subjects.put(subjURI, subj);
+ }
+
+ protected String getNameForBlankNode(String node) {
+ if (!_bns.containsKey(node)) {
+ _bns.put(node, _ng.next());
+ }
+ return _bns.get(node);
+ }
+
+ /**
+ * internal function to avoid repetition of code
+ *
+ * @param s
+ * @param p
+ * @param value
+ */
+ private void triple(String s, String p, Object value) {
+ // get the cached object for this subject
+ Map<String, Object> subj = _subjects.get(s);
+ if (subj == null) {
+ // if no cached object exists, create one.
+ subj = new HashMap<String, Object>();
+ _subjects.put(s, subj);
+
+ // since this is the first time we're encountering this subject, add
+ // it's @id key
+ subj.put("@id", s);
+ }
+
+ // check for @type predicate
+ if (JSONLDConsts.RDF_TYPE.equals(p)) {
+ p = "@type";
+ // type doesn't need to be (TODO: should it not be?) in an object
+ if (value instanceof Map) {
+ if (((Map) value).containsKey("@id")) {
+ value = ((Map) value).get("@id");
+ } else if (((Map) value).containsKey("@value")) {
+ // this is a weird case, which probably shouldn't happen
+ // but i'll account for it anyway.
+ value = ((Map) value).get("@value");
+ } // otherwise it's a string, leave it as such (TODO: it should
+ // never be a list, but perhaps we should make sure)
+ }
+ }
+
+ Object oldval = subj.get(p);
+ // check if an existing value is present for this predicate
+ if (oldval != null) {
+ // if so, make the value a list (if it isn't already) and add the
+ // new value to the end of the list
+ // TODO: what if the value itself is a list, is this even possible?
+ if (oldval instanceof List) {
+ ((List) oldval).add(value);
+ value = oldval;
+ } else {
+ List<Object> tmp = new ArrayList<Object>();
+ tmp.add(oldval);
+ tmp.add(value);
+ value = tmp;
+ }
+ }
+ // add the new value to the cache object
+ subj.put(p, value);
+ }
+
+ /**
+ * Call this to add a literal to the JSON-LD document
+ *
+ * @param s
+ * the subjuct URI
+ * @param p
+ * the predicate URI
+ * @param value
+ * the literal value as a string
+ * @param datatype
+ * the datatype URI (if null, a plain literal is assumed)
+ * @param language
+ * the language (may be null, or an empty string)
+ */
+ public void triple(String s, String p, String value, String datatype, String language) {
+
+ Object val;
+ if (datatype == null || JSONLDConsts.XSD_STRING.equals(datatype)) {
+ if (language == null || "".equals(language)) {
+ val = value;
+ } else {
+ val = new HashMap<String, Object>();
+ ((Map<String, Object>) val).put("@value", value);
+ ((Map<String, Object>) val).put("@language", language);
+ }
+ } else {
+ // compact the datatype (will return the same thing if no prefix has
+ // been set for the uri)
+ // datatype = JSONLDUtils.compactIRI(_context, datatype); NOTE:
+ // going to leave this up to the user
+ val = new HashMap<String, Object>();
+ ((Map<String, Object>) val).put("@value", value);
+ ((Map<String, Object>) val).put("@type", datatype);
+ }
+
+ triple(s, p, val);
+ }
+
+ /**
+ * Call this to add a new object,predicate,object relation to the JSON-LD document
+ *
+ * @param s
+ * the subject URI
+ * @param p
+ * the predicate URI
+ * @param o
+ * the object URI
+ */
+ public void triple(String s, String p, String o) {
+ Map<String, Object> val = new HashMap<String, Object>();
+ val.put("@id", o);
+
+ // TODO: should we check if this object exists in the _subjects list and
+ // add it if it doesn't?
+ // this seems to be what the python rdflib serializer does, but it seems
+ // redundant.
+ triple(s, p, (Object) val);
+ }
+
+ public void setPrefix(String fullUri, String prefix) {
+ _context.put(prefix, fullUri);
+ }
+
+ /**
+ * Builds the JSON-LD document based on the currently stored triples, compacting the URIs based on the stored context.
+ *
+ * @return A Map representing the JSON-LD document.
+ */
+ public Object asObject() {
+ JSONLDProcessor p = new JSONLDProcessor();
+
+ // go through the list of subjects that were built, compact them based
+ // of the current context
+ // then add them to a subjects list
+ List<Object> subjects = new ArrayList<Object>();
+ for (Map<String, Object> subj : _subjects.values()) {
+ subj = (Map<String, Object>) p.compact(_context, subj);
+ subjects.add(subj);
+ }
+
+ if (subjects.size() == 1) {
+ // if there is only one subject, make the base object this object
+ Map<String, Object> rval = new HashMap<String, Object>();
+ rval = (Map<String, Object>) subjects.get(0);
+ rval.put("@context", _context);
+ return rval;
+ } else {
+ return subjects;
+ }
+ }
+
+ public void toWriter(Writer writer) {
+ try {
+ JSONUtils.writePrettyPrint(writer, asObject());
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ *
+ * @return A String representing the JSON-LD document.
+ */
+ public String asString() {
+ return asString(false);
+ }
+
+ /**
+ * Returns a formated String representing the JSON-LD document using PrettyPrint writer.
+ * @return A String representing the JSON-LD document.
+ */
+ public String asString(boolean prettyPrint) {
+ // TODO: catching the exceptions here and returning JSON with the error
+ // messages may not
+ // be the best idea
+ try {
+ if (!prettyPrint)
+ return JSONUtils.toString(asObject());
+ else
+ return JSONUtils.toPrettyString(asObject());
+ } catch (Exception e) {
+ return "{\"error\":\"" + e.getLocalizedMessage() + "\"}";
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/1587eba0/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDTripleCallback.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDTripleCallback.java b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDTripleCallback.java
new file mode 100644
index 0000000..e332492
--- /dev/null
+++ b/commons/sesame-tools-rio-jsonld/src/ext/java/de/dfki/km/json/jsonld/JSONLDTripleCallback.java
@@ -0,0 +1,34 @@
+package de.dfki.km.json.jsonld;
+
+public interface JSONLDTripleCallback {
+ /**
+ * Construct a triple with three URIs.
+ *
+ * @param s
+ * The Subject URI
+ * @param p
+ * The Predicate URI
+ * @param o
+ * The Object URI
+ * @return The generated triple, or null to force triple generation to stop
+ */
+ void triple(String s, String p, String o);
+
+ /**
+ * Constructs a triple with a Literal object, which may or may not contain a
+ * language and/or a datatype.
+ *
+ * @param s
+ * The Subject URI
+ * @param p
+ * The Predicate URI
+ * @param value
+ * The literal value
+ * @param datatype
+ * The literal datatype
+ * @param language
+ * The literal language (NOTE: may be null if not specified!)
+ * @return The generated triple, or null to force triple generation to stop
+ */
+ void triple(String s, String p, String value, String datatype, String language);
+}