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);
+}