) termDefinitions.get(candidate)).get(JsonLdConsts.ID))
+ && value == null));
+
+ if (condition1 && condition2) {
+ compactIRI = candidate;
+ }
+ return compactIRI;
+ }
+
+ /**
+ * Return a map of potential RDF prefixes based on the JSON-LD Term
+ * Definitions in this context.
+ *
+ * No guarantees of the prefixes are given, beyond that it will not contain
+ * ":".
+ *
+ * @param onlyCommonPrefixes
+ * If true
, the result will not include "not so
+ * useful" prefixes, such as "term1": "http://example.com/term1",
+ * e.g. all IRIs will end with "/" or "#". If false
,
+ * all potential prefixes are returned.
+ *
+ * @return A map from prefix string to IRI string
+ */
+ public Map getPrefixes(boolean onlyCommonPrefixes) {
+ final Map prefixes = new LinkedHashMap();
+ for (final String term : termDefinitions.keySet()) {
+ if (term.contains(":")) {
+ continue;
+ }
+ final Map termDefinition = (Map) termDefinitions
+ .get(term);
+ if (termDefinition == null) {
+ continue;
+ }
+ final String id = (String) termDefinition.get(JsonLdConsts.ID);
+ if (id == null) {
+ continue;
+ }
+ if (term.startsWith("@") || id.startsWith("@")) {
+ continue;
+ }
+ if (!onlyCommonPrefixes || id.endsWith("/") || id.endsWith("#")) {
+ prefixes.put(term, id);
+ }
+ }
+ return prefixes;
+ }
+
+ String compactIri(String iri, boolean relativeToVocab) {
+ return compactIri(iri, null, relativeToVocab, false);
+ }
+
+ String compactIri(String iri) {
+ return compactIri(iri, null, false, false);
+ }
+
+ @Override
+ public Context clone() {
+ final Context rval = (Context) super.clone();
+ // TODO: is this shallow copy enough? probably not, but it passes all
+ // the tests!
+ rval.termDefinitions = new LinkedHashMap(this.termDefinitions);
+ return rval;
+ }
+
+ /**
+ * Inverse Context Creation
+ *
+ * http://json-ld.org/spec/latest/json-ld-api/#inverse-context-creation
+ *
+ * Generates an inverse context for use in the compaction algorithm, if not
+ * already generated for the given active context.
+ *
+ * @return the inverse context.
+ */
+ public Map getInverse() {
+
+ // lazily create inverse
+ if (inverse != null) {
+ return inverse;
+ }
+
+ // 1)
+ inverse = newMap();
+
+ // 2)
+ String defaultLanguage = (String) this.get(JsonLdConsts.LANGUAGE);
+ if (defaultLanguage == null) {
+ defaultLanguage = JsonLdConsts.NONE;
+ }
+
+ // create term selections for each mapping in the context, ordererd by
+ // shortest and then lexicographically least
+ final List terms = new ArrayList(termDefinitions.keySet());
+ Collections.sort(terms, new Comparator() {
+ @Override
+ public int compare(String a, String b) {
+ return compareShortestLeast(a, b);
+ }
+ });
+
+ for (final String term : terms) {
+ final Map definition = (Map) termDefinitions.get(term);
+ // 3.1)
+ if (definition == null) {
+ continue;
+ }
+
+ // 3.2)
+ String container = (String) definition.get(JsonLdConsts.CONTAINER);
+ if (container == null) {
+ container = JsonLdConsts.NONE;
+ }
+
+ // 3.3)
+ final String iri = (String) definition.get(JsonLdConsts.ID);
+
+ // 3.4 + 3.5)
+ Map containerMap = (Map) inverse.get(iri);
+ if (containerMap == null) {
+ containerMap = newMap();
+ inverse.put(iri, containerMap);
+ }
+
+ // 3.6 + 3.7)
+ Map typeLanguageMap = (Map) containerMap.get(container);
+ if (typeLanguageMap == null) {
+ typeLanguageMap = newMap();
+ typeLanguageMap.put(JsonLdConsts.LANGUAGE, newMap());
+ typeLanguageMap.put(JsonLdConsts.TYPE, newMap());
+ containerMap.put(container, typeLanguageMap);
+ }
+
+ // 3.8)
+ if (Boolean.TRUE.equals(definition.get(JsonLdConsts.REVERSE))) {
+ final Map typeMap = (Map) typeLanguageMap
+ .get(JsonLdConsts.TYPE);
+ if (!typeMap.containsKey(JsonLdConsts.REVERSE)) {
+ typeMap.put(JsonLdConsts.REVERSE, term);
+ }
+ // 3.9)
+ } else if (definition.containsKey(JsonLdConsts.TYPE)) {
+ final Map typeMap = (Map) typeLanguageMap
+ .get(JsonLdConsts.TYPE);
+ if (!typeMap.containsKey(definition.get(JsonLdConsts.TYPE))) {
+ typeMap.put((String) definition.get(JsonLdConsts.TYPE), term);
+ }
+ // 3.10)
+ } else if (definition.containsKey(JsonLdConsts.LANGUAGE)) {
+ final Map languageMap = (Map) typeLanguageMap
+ .get(JsonLdConsts.LANGUAGE);
+ String language = (String) definition.get(JsonLdConsts.LANGUAGE);
+ if (language == null) {
+ language = JsonLdConsts.NULL;
+ }
+ if (!languageMap.containsKey(language)) {
+ languageMap.put(language, term);
+ }
+ // 3.11)
+ } else {
+ // 3.11.1)
+ final Map languageMap = (Map) typeLanguageMap
+ .get(JsonLdConsts.LANGUAGE);
+ // 3.11.2)
+ if (!languageMap.containsKey(JsonLdConsts.LANGUAGE)) {
+ languageMap.put(JsonLdConsts.LANGUAGE, term);
+ }
+ // 3.11.3)
+ if (!languageMap.containsKey(JsonLdConsts.NONE)) {
+ languageMap.put(JsonLdConsts.NONE, term);
+ }
+ // 3.11.4)
+ final Map typeMap = (Map) typeLanguageMap
+ .get(JsonLdConsts.TYPE);
+ // 3.11.5)
+ if (!typeMap.containsKey(JsonLdConsts.NONE)) {
+ typeMap.put(JsonLdConsts.NONE, term);
+ }
+ }
+ }
+ // 4)
+ return inverse;
+ }
+
+ /**
+ * Term Selection
+ *
+ * http://json-ld.org/spec/latest/json-ld-api/#term-selection
+ *
+ * This algorithm, invoked via the IRI Compaction algorithm, makes use of an
+ * active context's inverse context to find the term that is best used to
+ * compact an IRI. Other information about a value associated with the IRI
+ * is given, including which container mappings and which type mapping or
+ * language mapping would be best used to express the value.
+ *
+ * @return the selected term.
+ */
+ private String selectTerm(String iri, List containers, String typeLanguage,
+ List preferredValues) {
+ final Map inv = getInverse();
+ // 1)
+ final Map containerMap = (Map) inv.get(iri);
+ // 2)
+ for (final String container : containers) {
+ // 2.1)
+ if (!containerMap.containsKey(container)) {
+ continue;
+ }
+ // 2.2)
+ final Map typeLanguageMap = (Map) containerMap
+ .get(container);
+ // 2.3)
+ final Map valueMap = (Map) typeLanguageMap
+ .get(typeLanguage);
+ // 2.4 )
+ for (final String item : preferredValues) {
+ // 2.4.1
+ if (!valueMap.containsKey(item)) {
+ continue;
+ }
+ // 2.4.2
+ return (String) valueMap.get(item);
+ }
+ }
+ // 3)
+ return null;
+ }
+
+ /**
+ * Retrieve container mapping.
+ *
+ * @param property
+ * The Property to get a container mapping for.
+ * @return The container mapping if any, else null
+ */
+ public String getContainer(String property) {
+ if (property == null) {
+ return null;
+ }
+ if (JsonLdConsts.GRAPH.equals(property)) {
+ return JsonLdConsts.SET;
+ }
+ if (!property.equals(JsonLdConsts.TYPE) && JsonLdUtils.isKeyword(property)) {
+ return property;
+ }
+ final Map td = (Map) termDefinitions.get(property);
+ if (td == null) {
+ return null;
+ }
+ return (String) td.get(JsonLdConsts.CONTAINER);
+ }
+
+ public Boolean isReverseProperty(String property) {
+ final Map td = (Map) termDefinitions.get(property);
+ if (td == null) {
+ return false;
+ }
+ final Object reverse = td.get(JsonLdConsts.REVERSE);
+ return reverse != null && (Boolean) reverse;
+ }
+
+ public String getTypeMapping(String property) {
+ final Map td = (Map) termDefinitions.get(property);
+ if (td == null) {
+ return null;
+ }
+ return (String) td.get(JsonLdConsts.TYPE);
+ }
+
+ public String getLanguageMapping(String property) {
+ final Map td = (Map) termDefinitions.get(property);
+ if (td == null) {
+ return null;
+ }
+ return (String) td.get(JsonLdConsts.LANGUAGE);
+ }
+
+ Map getTermDefinition(String key) {
+ return ((Map) termDefinitions.get(key));
+ }
+
+ public Object expandValue(String activeProperty, Object value) throws JsonLdError {
+ final Map rval = newMap();
+ final Map td = getTermDefinition(activeProperty);
+ // 1)
+ if (td != null && JsonLdConsts.ID.equals(td.get(JsonLdConsts.TYPE))) {
+ // TODO: i'm pretty sure value should be a string if the @type is
+ // @id
+ rval.put(JsonLdConsts.ID, expandIri(value.toString(), true, false, null, null));
+ return rval;
+ }
+ // 2)
+ if (td != null && JsonLdConsts.VOCAB.equals(td.get(JsonLdConsts.TYPE))) {
+ // TODO: same as above
+ rval.put(JsonLdConsts.ID, expandIri(value.toString(), true, true, null, null));
+ return rval;
+ }
+ // 3)
+ rval.put(JsonLdConsts.VALUE, value);
+ // 4)
+ if (td != null && td.containsKey(JsonLdConsts.TYPE)) {
+ rval.put(JsonLdConsts.TYPE, td.get(JsonLdConsts.TYPE));
+ }
+ // 5)
+ else if (value instanceof String) {
+ // 5.1)
+ if (td != null && td.containsKey(JsonLdConsts.LANGUAGE)) {
+ final String lang = (String) td.get(JsonLdConsts.LANGUAGE);
+ if (lang != null) {
+ rval.put(JsonLdConsts.LANGUAGE, lang);
+ }
+ }
+ // 5.2)
+ else if (this.get(JsonLdConsts.LANGUAGE) != null) {
+ rval.put(JsonLdConsts.LANGUAGE, this.get(JsonLdConsts.LANGUAGE));
+ }
+ }
+ return rval;
+ }
+
+ public Map serialize() {
+ final Map ctx = newMap();
+ if (this.get(JsonLdConsts.BASE) != null
+ && !this.get(JsonLdConsts.BASE).equals(options.getBase())) {
+ ctx.put(JsonLdConsts.BASE, this.get(JsonLdConsts.BASE));
+ }
+ if (this.get(JsonLdConsts.LANGUAGE) != null) {
+ ctx.put(JsonLdConsts.LANGUAGE, this.get(JsonLdConsts.LANGUAGE));
+ }
+ if (this.get(JsonLdConsts.VOCAB) != null) {
+ ctx.put(JsonLdConsts.VOCAB, this.get(JsonLdConsts.VOCAB));
+ }
+ for (final String term : termDefinitions.keySet()) {
+ final Map definition = (Map) termDefinitions.get(term);
+ if (definition.get(JsonLdConsts.LANGUAGE) == null
+ && definition.get(JsonLdConsts.CONTAINER) == null
+ && definition.get(JsonLdConsts.TYPE) == null
+ && (definition.get(JsonLdConsts.REVERSE) == null
+ || Boolean.FALSE.equals(definition.get(JsonLdConsts.REVERSE)))) {
+ final String cid = this.compactIri((String) definition.get(JsonLdConsts.ID));
+ ctx.put(term, term.equals(cid) ? definition.get(JsonLdConsts.ID) : cid);
+ } else {
+ final Map defn = newMap();
+ final String cid = this.compactIri((String) definition.get(JsonLdConsts.ID));
+ final Boolean reverseProperty = Boolean.TRUE
+ .equals(definition.get(JsonLdConsts.REVERSE));
+ if (!(term.equals(cid) && !reverseProperty)) {
+ defn.put(reverseProperty ? JsonLdConsts.REVERSE : JsonLdConsts.ID, cid);
+ }
+ final String typeMapping = (String) definition.get(JsonLdConsts.TYPE);
+ if (typeMapping != null) {
+ defn.put(JsonLdConsts.TYPE, JsonLdUtils.isKeyword(typeMapping) ? typeMapping
+ : compactIri(typeMapping, true));
+ }
+ if (definition.get(JsonLdConsts.CONTAINER) != null) {
+ defn.put(JsonLdConsts.CONTAINER, definition.get(JsonLdConsts.CONTAINER));
+ }
+ final Object lang = definition.get(JsonLdConsts.LANGUAGE);
+ if (definition.get(JsonLdConsts.LANGUAGE) != null) {
+ defn.put(JsonLdConsts.LANGUAGE, Boolean.FALSE.equals(lang) ? null : lang);
+ }
+ ctx.put(term, defn);
+ }
+ }
+
+ final Map rval = newMap();
+ if (!(ctx == null || ctx.isEmpty())) {
+ rval.put(JsonLdConsts.CONTEXT, ctx);
+ }
+ return rval;
+ }
+
+}
diff --git a/jsonldjava/src/main/java/com/github/jsonldjava/core/DocumentLoader.java b/jsonldjava/src/main/java/com/github/jsonldjava/core/DocumentLoader.java
new file mode 100644
index 0000000..06f3866
--- /dev/null
+++ b/jsonldjava/src/main/java/com/github/jsonldjava/core/DocumentLoader.java
@@ -0,0 +1,58 @@
+package com.github.jsonldjava.core;
+
+import com.github.jsonldjava.utils.JsonUtils;
+
+import java.net.URL;
+
+/**
+ * Resolves URLs to {@link RemoteDocument}s. Subclass this class to change the
+ * behaviour of loadDocument to suit your purposes.
+ */
+public class DocumentLoader {
+
+ //private final Map m_injectedDocs = new HashMap<>();
+
+ /**
+ * Identifies a system property that can be set to "true" in order to
+ * disallow remote context loading.
+ */
+ public static final String DISALLOW_REMOTE_CONTEXT_LOADING = "com.github.jsonldjava.disallowRemoteContextLoading";
+
+
+ /**
+ * Loads the URL if possible, returning it as a RemoteDocument.
+ *
+ * @param url
+ * The URL to load
+ * @return The resolved URL as a RemoteDocument
+ * @throws JsonLdError
+ * If there are errors loading or remote context loading has
+ * been disallowed.
+ */
+ public RemoteDocument loadDocument(String url) throws JsonLdError {
+
+ final String disallowRemote = System
+ .getProperty(DocumentLoader.DISALLOW_REMOTE_CONTEXT_LOADING);
+
+ if ("true".equalsIgnoreCase(disallowRemote)) {
+ throw new JsonLdError(JsonLdError.Error.LOADING_REMOTE_CONTEXT_FAILED, "Remote context loading has been disallowed (url was " + url + ")");
+ }
+
+ final RemoteDocument doc = new RemoteDocument(url, null);
+ try {
+ doc.setDocument(JsonUtils.fromURL(new URL(url)/*, getHttpClient()*/));
+ } catch (final Exception e) {
+ throw new JsonLdError(JsonLdError.Error.LOADING_REMOTE_CONTEXT_FAILED, url, e);
+ }
+ return doc;
+ }
+
+ /**
+ * An HTTP Accept header that prefers JSONLD.
+ *
+ * @deprecated Use {@link JsonUtils#ACCEPT_HEADER} instead.
+ */
+ @Deprecated
+ public static final String ACCEPT_HEADER = JsonUtils.ACCEPT_HEADER;
+
+}
diff --git a/jsonldjava/src/main/java/com/github/jsonldjava/core/IdentifierIssuer.java b/jsonldjava/src/main/java/com/github/jsonldjava/core/IdentifierIssuer.java
new file mode 100644
index 0000000..f73212c
--- /dev/null
+++ b/jsonldjava/src/main/java/com/github/jsonldjava/core/IdentifierIssuer.java
@@ -0,0 +1,112 @@
+package com.github.jsonldjava.core;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/*
+ * An IdentifierIssuer issues unique identifiers, keeping track of any
+ * previously issued identifiers.
+ */
+public class IdentifierIssuer implements Cloneable {
+
+ private String prefix;
+ private int counter;
+ private Map existing;
+ private List order;
+
+ public IdentifierIssuer(String prefix) {
+ /*
+ * Initializes a new IdentifierIssuer.
+ * :param prefix: the prefix to use ('').
+ */
+
+ this.prefix = prefix;
+ this.counter = 0;
+ this.existing = new HashMap<>();
+ this.order = new ArrayList<>();
+
+ /*
+ * Gets the new identifier for the given old identifier, where if no old
+ * identifier is given a new identifier will be generated.
+ * :param [old]: the old identifier to get the new identifier for.
+ * :return: the new identifier.
+ */
+ }
+
+ public String getId() {
+ return this.getId(null);
+ }
+
+ public String getId(String old) {
+
+ if(old != null && existing.containsKey(old)) {
+ return existing.get(old);
+ }
+
+ String id = this.prefix + Integer.toString(counter);
+ this.counter += 1;
+
+ if(old != null) {
+ /*
+ * Returns True if the given old identifier has already been assigned a
+ * new identifier.
+ * :param old: the old identifier to check.
+ * :return: True if the old identifier has been assigned a new identifier,
+ * False if not.
+ */
+
+ this.existing.put(old, id);
+ this.order.add(old);
+ }
+
+ return id;
+
+ }
+
+ public boolean hasID (String old) {
+ return this.existing.containsKey(old);
+
+ }
+
+ public List getOrder() {
+ return this.order;
+ }
+
+ public String getPrefix() {
+ return this.prefix;
+ }
+
+ public Object clone() {
+ try {
+ return super.clone();
+ } catch (CloneNotSupportedException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/jsonldjava/src/main/java/com/github/jsonldjava/core/JsonLdApi.java b/jsonldjava/src/main/java/com/github/jsonldjava/core/JsonLdApi.java
new file mode 100644
index 0000000..3092d69
--- /dev/null
+++ b/jsonldjava/src/main/java/com/github/jsonldjava/core/JsonLdApi.java
@@ -0,0 +1,2058 @@
+package com.github.jsonldjava.core;
+
+import com.github.jsonldjava.core.JsonLdError.Error;
+import com.github.jsonldjava.utils.Obj;
+
+import java.util.*;
+import java.util.logging.Logger;
+
+import static com.github.jsonldjava.core.JsonLdConsts.*;
+import static com.github.jsonldjava.core.JsonLdUtils.isKeyword;
+import static com.github.jsonldjava.utils.Obj.newMap;
+
+
+public class JsonLdApi {
+
+ private final Logger log = null;
+
+ JsonLdOptions opts;
+ Object value = null;
+ Context context = null;
+
+ /**
+ * Constructs an empty JsonLdApi object using the default JsonLdOptions, and
+ * without initialization.
+ */
+ public JsonLdApi() {
+ this(new JsonLdOptions(""));
+ }
+
+ /**
+ * Constructs a JsonLdApi object using the given object as the initial
+ * JSON-LD object, and the given JsonLdOptions.
+ *
+ * @param input The initial JSON-LD object.
+ * @param opts The JsonLdOptions to use.
+ * @throws JsonLdError If there is an error initializing using the object and
+ * options.
+ */
+ public JsonLdApi(Object input, JsonLdOptions opts) throws JsonLdError {
+ this(opts);
+ initialize(input, null);
+ }
+
+ /**
+ * Constructs a JsonLdApi object using the given object as the initial
+ * JSON-LD object, the given context, and the given JsonLdOptions.
+ *
+ * @param input The initial JSON-LD object.
+ * @param context The initial context.
+ * @param opts The JsonLdOptions to use.
+ * @throws JsonLdError If there is an error initializing using the object and
+ * options.
+ */
+ public JsonLdApi(Object input, Object context, JsonLdOptions opts) throws JsonLdError {
+ this(opts);
+ initialize(input, null);
+ }
+
+ /**
+ * Constructs an empty JsonLdApi object using the given JsonLdOptions, and
+ * without initialization.
+ * If the JsonLdOptions parameter is null, then the default options are
+ * used.
+ *
+ * @param opts The JsonLdOptions to use.
+ */
+ public JsonLdApi(JsonLdOptions opts) {
+ if (opts == null) {
+ opts = new JsonLdOptions("");
+ } else {
+ this.opts = opts;
+ }
+ }
+
+ /**
+ * @param input The initial object, which is to be cloned and used in
+ * operations.
+ * @param context The context object, which is to be parsed and used in
+ * operations.
+ * @throws JsonLdError If there was an error cloning the object, or in parsing the
+ * context.
+ */
+ private void initialize(Object input, Object context) throws JsonLdError {
+ if (input instanceof List || input instanceof Map) {
+ this.value = JsonLdUtils.clone(input);
+ }
+ // TODO: string/IO input
+ this.context = new Context(opts);
+ if (context != null) {
+ this.context = this.context.parse(context);
+ }
+ }
+
+ /***
+ * ____ _ _ _ _ _ _ / ___|___ _ __ ___ _ __ __ _ ___| |_ / \ | | __ _ ___ _
+ * __(_) |_| |__ _ __ ___ | | / _ \| '_ ` _ \| '_ \ / _` |/ __| __| / _ \ |
+ * |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \ | |__| (_) | | | | | | |_) | (_|
+ * | (__| |_ / ___ \| | (_| | (_) | | | | |_| | | | | | | | | \____\___/|_|
+ * |_| |_| .__/ \__,_|\___|\__| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_|
+ * |_| |_| |___/
+ */
+
+ /**
+ * Compaction Algorithm
+ *
+ * http://json-ld.org/spec/latest/json-ld-api/#compaction-algorithm
+ *
+ * @param activeCtx The Active Context
+ * @param activeProperty The Active Property
+ * @param element The current element
+ * @param compactArrays True to compact arrays.
+ * @return The compacted JSON-LD object.
+ * @throws JsonLdError If there was an error during compaction.
+ */
+ public Object compact(Context activeCtx, String activeProperty, Object element,
+ boolean compactArrays) throws JsonLdError {
+ // 2)
+ if (element instanceof List) {
+ // 2.1)
+ final List