Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.github.jsonldjava.core.Context Maven / Gradle / Ivy
package com.github.jsonldjava.core;
import static com.github.jsonldjava.core.JsonLdUtils.compareShortestLeast;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.github.jsonldjava.core.JsonLdError.Error;
import com.github.jsonldjava.utils.JsonLdUrl;
import com.github.jsonldjava.utils.Obj;
/**
* A helper class which still stores all the values in a map but gives member
* variables easily access certain keys
*
* @author tristan
*
*/
public class Context extends LinkedHashMap {
private JsonLdOptions options;
private Map termDefinitions;
public Map inverse = null;
public Context() {
this(new JsonLdOptions());
}
public Context(JsonLdOptions opts) {
super();
init(opts);
}
public Context(Map map, JsonLdOptions opts) {
super(map);
init(opts);
}
public Context(Map map) {
super(map);
init(new JsonLdOptions());
}
public Context(Object context, JsonLdOptions opts) {
// TODO: load remote context
super(context instanceof Map ? (Map) context : null);
init(opts);
}
private void init(JsonLdOptions options) {
this.options = options;
if (options.getBase() != null) {
this.put("@base", options.getBase());
}
this.termDefinitions = new LinkedHashMap();
}
/**
* Value Compaction Algorithm
*
* http://json-ld.org/spec/latest/json-ld-api/#value-compaction
*
* @param activeProperty
* The Active Property
* @param value
* The value to compact
* @return The compacted value
*/
public Object compactValue(String activeProperty, Map value) {
// 1)
int numberMembers = value.size();
// 2)
if (value.containsKey("@index") && "@index".equals(this.getContainer(activeProperty))) {
numberMembers--;
}
// 3)
if (numberMembers > 2) {
return value;
}
// 4)
final String typeMapping = getTypeMapping(activeProperty);
final String languageMapping = getLanguageMapping(activeProperty);
if (value.containsKey("@id")) {
// 4.1)
if (numberMembers == 1 && "@id".equals(typeMapping)) {
return compactIri((String) value.get("@id"));
}
// 4.2)
if (numberMembers == 1 && "@vocab".equals(typeMapping)) {
return compactIri((String) value.get("@id"), true);
}
// 4.3)
return value;
}
final Object valueValue = value.get("@value");
// 5)
if (value.containsKey("@type") && Obj.equals(value.get("@type"), typeMapping)) {
return valueValue;
}
// 6)
if (value.containsKey("@language")) {
// TODO: SPEC: doesn't specify to check default language as well
if (Obj.equals(value.get("@language"), languageMapping)
|| Obj.equals(value.get("@language"), this.get("@language"))) {
return valueValue;
}
}
// 7)
if (numberMembers == 1
&& (!(valueValue instanceof String) || !this.containsKey("@language") || (termDefinitions
.containsKey(activeProperty)
&& getTermDefinition(activeProperty).containsKey("@language") && languageMapping == null))) {
return valueValue;
}
// 8)
return value;
}
/**
* Context Processing Algorithm
*
* http://json-ld.org/spec/latest/json-ld-api/#context-processing-algorithms
*
* @param localContext
* The Local Context object.
* @param remoteContexts
* The list of Strings denoting the remote Context URLs.
* @return The parsed and merged Context.
* @throws JsonLdError
* If there is an error parsing the contexts.
*/
public Context parse(Object localContext, List remoteContexts) throws JsonLdError {
if (remoteContexts == null) {
remoteContexts = new ArrayList();
}
// 1. Initialize result to the result of cloning active context.
Context result = this.clone(); // TODO: clone?
// 2)
if (!(localContext instanceof List)) {
final Object temp = localContext;
localContext = new ArrayList();
((List) localContext).add(temp);
}
// 3)
for (Object context : ((List) localContext)) {
// 3.1)
if (context == null) {
result = new Context(this.options);
continue;
} else if (context instanceof Context) {
result = ((Context) context).clone();
}
// 3.2)
else if (context instanceof String) {
String uri = (String) result.get("@base");
uri = JsonLdUrl.resolve(uri, (String) context);
// 3.2.2
if (remoteContexts.contains(uri)) {
throw new JsonLdError(Error.RECURSIVE_CONTEXT_INCLUSION, uri);
}
remoteContexts.add(uri);
// 3.2.3: Dereference context
final RemoteDocument rd = this.options.getDocumentLoader().loadDocument(uri);
final Object remoteContext = rd.document;
if (!(remoteContext instanceof Map)
|| !((Map) remoteContext).containsKey("@context")) {
// If the dereferenced document has no top-level JSON object
// with an @context member
throw new JsonLdError(Error.INVALID_REMOTE_CONTEXT, context);
}
context = ((Map) remoteContext).get("@context");
// 3.2.4
result = result.parse(context, remoteContexts);
// 3.2.5
continue;
} else if (!(context instanceof Map)) {
// 3.3
throw new JsonLdError(Error.INVALID_LOCAL_CONTEXT, context);
}
// 3.4
if (remoteContexts.isEmpty() && ((Map) context).containsKey("@base")) {
final Object value = ((Map) context).get("@base");
if (value == null) {
result.remove("@base");
} else if (value instanceof String) {
if (JsonLdUtils.isAbsoluteIri((String) value)) {
result.put("@base", value);
} else {
final String baseUri = (String) result.get("@base");
if (!JsonLdUtils.isAbsoluteIri(baseUri)) {
throw new JsonLdError(Error.INVALID_BASE_IRI, baseUri);
}
result.put("@base", JsonLdUrl.resolve(baseUri, (String) value));
}
} else {
throw new JsonLdError(JsonLdError.Error.INVALID_BASE_IRI,
"@base must be a string");
}
}
// 3.5
if (((Map) context).containsKey("@vocab")) {
final Object value = ((Map) context).get("@vocab");
if (value == null) {
result.remove("@vocab");
} else if (value instanceof String) {
if (JsonLdUtils.isAbsoluteIri((String) value)) {
result.put("@vocab", value);
} else {
throw new JsonLdError(Error.INVALID_VOCAB_MAPPING,
"@value must be an absolute IRI");
}
} else {
throw new JsonLdError(Error.INVALID_VOCAB_MAPPING,
"@vocab must be a string or null");
}
}
// 3.6
if (((Map) context).containsKey("@language")) {
final Object value = ((Map) context).get("@language");
if (value == null) {
result.remove("@language");
} else if (value instanceof String) {
result.put("@language", ((String) value).toLowerCase());
} else {
throw new JsonLdError(Error.INVALID_DEFAULT_LANGUAGE, value);
}
}
// 3.7
final Map defined = new LinkedHashMap();
for (final String key : ((Map) context).keySet()) {
if ("@base".equals(key) || "@vocab".equals(key) || "@language".equals(key)) {
continue;
}
result.createTermDefinition((Map) context, key, defined);
}
}
return result;
}
public Context parse(Object localContext) throws JsonLdError {
return this.parse(localContext, new ArrayList());
}
/**
* Create Term Definition Algorithm
*
* http://json-ld.org/spec/latest/json-ld-api/#create-term-definition
*
* @param result
* @param context
* @param key
* @param defined
* @throws JsonLdError
*/
private void createTermDefinition(Map context, String term,
Map defined) throws JsonLdError {
if (defined.containsKey(term)) {
if (Boolean.TRUE.equals(defined.get(term))) {
return;
}
throw new JsonLdError(Error.CYCLIC_IRI_MAPPING, term);
}
defined.put(term, false);
if (JsonLdUtils.isKeyword(term)) {
throw new JsonLdError(Error.KEYWORD_REDEFINITION, term);
}
this.termDefinitions.remove(term);
Object value = context.get(term);
if (value == null
|| (value instanceof Map && ((Map) value).containsKey("@id") && ((Map) value)
.get("@id") == null)) {
this.termDefinitions.put(term, null);
defined.put(term, true);
return;
}
if (value instanceof String) {
final Map tmp = new LinkedHashMap();
tmp.put("@id", value);
value = tmp;
}
if (!(value instanceof Map)) {
throw new JsonLdError(Error.INVALID_TERM_DEFINITION, value);
}
// casting the value so it doesn't have to be done below everytime
final Map val = (Map) value;
// 9) create a new term definition
final Map definition = new LinkedHashMap();
// 10)
if (val.containsKey("@type")) {
if (!(val.get("@type") instanceof String)) {
throw new JsonLdError(Error.INVALID_TYPE_MAPPING, val.get("@type"));
}
String type = (String) val.get("@type");
try {
type = this.expandIri((String) val.get("@type"), false, true, context, defined);
} catch (final JsonLdError error) {
if (error.getType() != Error.INVALID_IRI_MAPPING) {
throw error;
}
throw new JsonLdError(Error.INVALID_TYPE_MAPPING, type);
}
// TODO: fix check for absoluteIri (blank nodes shouldn't count, at
// least not here!)
if ("@id".equals(type) || "@vocab".equals(type)
|| (!type.startsWith("_:") && JsonLdUtils.isAbsoluteIri(type))) {
definition.put("@type", type);
} else {
throw new JsonLdError(Error.INVALID_TYPE_MAPPING, type);
}
}
// 11)
if (val.containsKey("@reverse")) {
if (val.containsKey("@id")) {
throw new JsonLdError(Error.INVALID_REVERSE_PROPERTY, val);
}
if (!(val.get("@reverse") instanceof String)) {
throw new JsonLdError(Error.INVALID_IRI_MAPPING,
"Expected String for @reverse value. got "
+ (val.get("@reverse") == null ? "null" : val.get("@reverse")
.getClass()));
}
final String reverse = this.expandIri((String) val.get("@reverse"), false, true,
context, defined);
if (!JsonLdUtils.isAbsoluteIri(reverse)) {
throw new JsonLdError(Error.INVALID_IRI_MAPPING, "Non-absolute @reverse IRI: "
+ reverse);
}
definition.put("@id", reverse);
if (val.containsKey("@container")) {
final String container = (String) val.get("@container");
if (container == null || "@set".equals(container) || "@index".equals(container)) {
definition.put("@container", container);
} else {
throw new JsonLdError(Error.INVALID_REVERSE_PROPERTY,
"reverse properties only support set- and index-containers");
}
}
definition.put("@reverse", true);
this.termDefinitions.put(term, definition);
defined.put(term, true);
return;
}
// 12)
definition.put("@reverse", false);
// 13)
if (val.get("@id") != null && !term.equals(val.get("@id"))) {
if (!(val.get("@id") instanceof String)) {
throw new JsonLdError(Error.INVALID_IRI_MAPPING,
"expected value of @id to be a string");
}
final String res = this.expandIri((String) val.get("@id"), false, true, context,
defined);
if (JsonLdUtils.isKeyword(res) || JsonLdUtils.isAbsoluteIri(res)) {
if ("@context".equals(res)) {
throw new JsonLdError(Error.INVALID_KEYWORD_ALIAS, "cannot alias @context");
}
definition.put("@id", res);
} else {
throw new JsonLdError(Error.INVALID_IRI_MAPPING,
"resulting IRI mapping should be a keyword, absolute IRI or blank node");
}
}
// 14)
else if (term.indexOf(":") >= 0) {
final int colIndex = term.indexOf(":");
final String prefix = term.substring(0, colIndex);
final String suffix = term.substring(colIndex + 1);
if (context.containsKey(prefix)) {
this.createTermDefinition(context, prefix, defined);
}
if (termDefinitions.containsKey(prefix)) {
definition.put("@id",
((Map) termDefinitions.get(prefix)).get("@id") + suffix);
} else {
definition.put("@id", term);
}
// 15)
} else if (this.containsKey("@vocab")) {
definition.put("@id", this.get("@vocab") + term);
} else {
throw new JsonLdError(Error.INVALID_IRI_MAPPING,
"relative term definition without vocab mapping");
}
// 16)
if (val.containsKey("@container")) {
final String container = (String) val.get("@container");
if (!"@list".equals(container) && !"@set".equals(container)
&& !"@index".equals(container) && !"@language".equals(container)) {
throw new JsonLdError(Error.INVALID_CONTAINER_MAPPING,
"@container must be either @list, @set, @index, or @language");
}
definition.put("@container", container);
}
// 17)
if (val.containsKey("@language") && !val.containsKey("@type")) {
if (val.get("@language") == null || val.get("@language") instanceof String) {
final String language = (String) val.get("@language");
definition.put("@language", language != null ? language.toLowerCase() : null);
} else {
throw new JsonLdError(Error.INVALID_LANGUAGE_MAPPING,
"@language must be a string or null");
}
}
// 18)
this.termDefinitions.put(term, definition);
defined.put(term, true);
}
/**
* IRI Expansion Algorithm
*
* http://json-ld.org/spec/latest/json-ld-api/#iri-expansion
*
* @param value
* @param relative
* @param vocab
* @param context
* @param defined
* @return
* @throws JsonLdError
*/
String expandIri(String value, boolean relative, boolean vocab, Map context,
Map defined) throws JsonLdError {
// 1)
if (value == null || JsonLdUtils.isKeyword(value)) {
return value;
}
// 2)
if (context != null && context.containsKey(value)
&& !Boolean.TRUE.equals(defined.get(value))) {
this.createTermDefinition(context, value, defined);
}
// 3)
if (vocab && this.termDefinitions.containsKey(value)) {
final Map td = (LinkedHashMap) this.termDefinitions
.get(value);
if (td != null) {
return (String) td.get("@id");
} else {
return null;
}
}
// 4)
final int colIndex = value.indexOf(":");
if (colIndex >= 0) {
// 4.1)
final String prefix = value.substring(0, colIndex);
final String suffix = value.substring(colIndex + 1);
// 4.2)
if ("_".equals(prefix) || suffix.startsWith("//")) {
return value;
}
// 4.3)
if (context != null && context.containsKey(prefix)
&& (!defined.containsKey(prefix) || defined.get(prefix) == false)) {
this.createTermDefinition(context, prefix, defined);
}
// 4.4)
if (this.termDefinitions.containsKey(prefix)) {
return (String) ((LinkedHashMap) this.termDefinitions.get(prefix))
.get("@id") + suffix;
}
// 4.5)
return value;
}
// 5)
if (vocab && this.containsKey("@vocab")) {
return this.get("@vocab") + value;
}
// 6)
else if (relative) {
return JsonLdUrl.resolve((String) this.get("@base"), value);
} else if (context != null && JsonLdUtils.isRelativeIri(value)) {
throw new JsonLdError(Error.INVALID_IRI_MAPPING, "not an absolute IRI: " + value);
}
// 7)
return value;
}
/**
* IRI Compaction Algorithm
*
* http://json-ld.org/spec/latest/json-ld-api/#iri-compaction
*
* Compacts an IRI or keyword into a term or prefix if it can be. If the IRI
* has an associated value it may be passed.
*
* @param iri
* the IRI to compact.
* @param value
* the value to check or null.
* @param relativeTo
* options for how to compact IRIs: vocab: true to split after
* @vocab, false not to.
* @param reverse
* true if a reverse property is being compacted, false if not.
*
* @return the compacted term, prefix, keyword alias, or the original IRI.
*/
String compactIri(String iri, Object value, boolean relativeToVocab, boolean reverse) {
// 1)
if (iri == null) {
return null;
}
// 2)
if (relativeToVocab && getInverse().containsKey(iri)) {
// 2.1)
String defaultLanguage = (String) this.get("@language");
if (defaultLanguage == null) {
defaultLanguage = "@none";
}
// 2.2)
final List containers = new ArrayList();
// 2.3)
String typeLanguage = "@language";
String typeLanguageValue = "@null";
// 2.4)
if (value instanceof Map && ((Map) value).containsKey("@index")) {
containers.add("@index");
}
// 2.5)
if (reverse) {
typeLanguage = "@type";
typeLanguageValue = "@reverse";
containers.add("@set");
}
// 2.6)
else if (value instanceof Map && ((Map) value).containsKey("@list")) {
// 2.6.1)
if (!((Map) value).containsKey("@index")) {
containers.add("@list");
}
// 2.6.2)
final List list = (List) ((Map) value).get("@list");
// 2.6.3)
String commonLanguage = (list.size() == 0) ? defaultLanguage : null;
String commonType = null;
// 2.6.4)
for (final Object item : list) {
// 2.6.4.1)
String itemLanguage = "@none";
String itemType = "@none";
// 2.6.4.2)
if (JsonLdUtils.isValue(item)) {
// 2.6.4.2.1)
if (((Map) item).containsKey("@language")) {
itemLanguage = (String) ((Map) item).get("@language");
}
// 2.6.4.2.2)
else if (((Map) item).containsKey("@type")) {
itemType = (String) ((Map) item).get("@type");
}
// 2.6.4.2.3)
else {
itemLanguage = "@null";
}
}
// 2.6.4.3)
else {
itemType = "@id";
}
// 2.6.4.4)
if (commonLanguage == null) {
commonLanguage = itemLanguage;
}
// 2.6.4.5)
else if (!commonLanguage.equals(itemLanguage) && JsonLdUtils.isValue(item)) {
commonLanguage = "@none";
}
// 2.6.4.6)
if (commonType == null) {
commonType = itemType;
}
// 2.6.4.7)
else if (!commonType.equals(itemType)) {
commonType = "@none";
}
// 2.6.4.8)
if ("@none".equals(commonLanguage) && "@none".equals(commonType)) {
break;
}
}
// 2.6.5)
commonLanguage = (commonLanguage != null) ? commonLanguage : "@none";
// 2.6.6)
commonType = (commonType != null) ? commonType : "@none";
// 2.6.7)
if (!"@none".equals(commonType)) {
typeLanguage = "@type";
typeLanguageValue = commonType;
}
// 2.6.8)
else {
typeLanguageValue = commonLanguage;
}
}
// 2.7)
else {
// 2.7.1)
if (value instanceof Map && ((Map) value).containsKey("@value")) {
// 2.7.1.1)
if (((Map) value).containsKey("@language")
&& !((Map) value).containsKey("@index")) {
containers.add("@language");
typeLanguageValue = (String) ((Map) value).get("@language");
}
// 2.7.1.2)
else if (((Map) value).containsKey("@type")) {
typeLanguage = "@type";
typeLanguageValue = (String) ((Map) value).get("@type");
}
}
// 2.7.2)
else {
typeLanguage = "@type";
typeLanguageValue = "@id";
}
// 2.7.3)
containers.add("@set");
}
// 2.8)
containers.add("@none");
// 2.9)
if (typeLanguageValue == null) {
typeLanguageValue = "@null";
}
// 2.10)
final List preferredValues = new ArrayList();
// 2.11)
if ("@reverse".equals(typeLanguageValue)) {
preferredValues.add("@reverse");
}
// 2.12)
if (("@reverse".equals(typeLanguageValue) || "@id".equals(typeLanguageValue))
&& (value instanceof Map) && ((Map) value).containsKey("@id")) {
// 2.12.1)
final String result = this.compactIri(
(String) ((Map) value).get("@id"), null, true, true);
if (termDefinitions.containsKey(result)
&& ((Map) termDefinitions.get(result)).containsKey("@id")
&& ((Map) value).get("@id").equals(
((Map) termDefinitions.get(result)).get("@id"))) {
preferredValues.add("@vocab");
preferredValues.add("@id");
}
// 2.12.2)
else {
preferredValues.add("@id");
preferredValues.add("@vocab");
}
}
// 2.13)
else {
preferredValues.add(typeLanguageValue);
}
preferredValues.add("@none");
// 2.14)
final String term = selectTerm(iri, containers, typeLanguage, preferredValues);
// 2.15)
if (term != null) {
return term;
}
}
// 3)
if (relativeToVocab && this.containsKey("@vocab")) {
// determine if vocab is a prefix of the iri
final String vocab = (String) this.get("@vocab");
// 3.1)
if (iri.indexOf(vocab) == 0 && !iri.equals(vocab)) {
// use suffix as relative iri if it is not a term in the
// active context
final String suffix = iri.substring(vocab.length());
if (!termDefinitions.containsKey(suffix)) {
return suffix;
}
}
}
// 4)
String compactIRI = null;
// 5)
for (final String term : termDefinitions.keySet()) {
final Map termDefinition = (Map) termDefinitions
.get(term);
// 5.1)
if (term.contains(":")) {
continue;
}
// 5.2)
if (termDefinition == null || iri.equals(termDefinition.get("@id"))
|| !iri.startsWith((String) termDefinition.get("@id"))) {
continue;
}
// 5.3)
final String candidate = term + ":"
+ iri.substring(((String) termDefinition.get("@id")).length());
// 5.4)
if ((compactIRI == null || compareShortestLeast(candidate, compactIRI) < 0)
&& (!termDefinitions.containsKey(candidate) || (iri
.equals(((Map) termDefinitions.get(candidate))
.get("@id")) && value == null))) {
compactIRI = candidate;
}
}
// 6)
if (compactIRI != null) {
return compactIRI;
}
// 7)
if (!relativeToVocab) {
return JsonLdUrl.removeBase(this.get("@base"), iri);
}
// 8)
return iri;
}
/**
* 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("@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 = new LinkedHashMap();
// 2)
String defaultLanguage = (String) this.get("@language");
if (defaultLanguage == null) {
defaultLanguage = "@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("@container");
if (container == null) {
container = "@none";
}
// 3.3)
final String iri = (String) definition.get("@id");
// 3.4 + 3.5)
Map containerMap = (Map) inverse.get(iri);
if (containerMap == null) {
containerMap = new LinkedHashMap();
inverse.put(iri, containerMap);
}
// 3.6 + 3.7)
Map typeLanguageMap = (Map) containerMap.get(container);
if (typeLanguageMap == null) {
typeLanguageMap = new LinkedHashMap();
typeLanguageMap.put("@language", new LinkedHashMap());
typeLanguageMap.put("@type", new LinkedHashMap());
containerMap.put(container, typeLanguageMap);
}
// 3.8)
if (Boolean.TRUE.equals(definition.get("@reverse"))) {
final Map typeMap = (Map) typeLanguageMap
.get("@type");
if (!typeMap.containsKey("@reverse")) {
typeMap.put("@reverse", term);
}
// 3.9)
} else if (definition.containsKey("@type")) {
final Map typeMap = (Map) typeLanguageMap
.get("@type");
if (!typeMap.containsKey(definition.get("@type"))) {
typeMap.put((String) definition.get("@type"), term);
}
// 3.10)
} else if (definition.containsKey("@language")) {
final Map languageMap = (Map) typeLanguageMap
.get("@language");
String language = (String) definition.get("@language");
if (language == null) {
language = "@null";
}
if (!languageMap.containsKey(language)) {
languageMap.put(language, term);
}
// 3.11)
} else {
// 3.11.1)
final Map languageMap = (Map) typeLanguageMap
.get("@language");
// 3.11.2)
if (!languageMap.containsKey("@language")) {
languageMap.put("@language", term);
}
// 3.11.3)
if (!languageMap.containsKey("@none")) {
languageMap.put("@none", term);
}
// 3.11.4)
final Map typeMap = (Map) typeLanguageMap
.get("@type");
// 3.11.5)
if (!typeMap.containsKey("@none")) {
typeMap.put("@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
*/
public String getContainer(String property) {
if ("@graph".equals(property)) {
return "@set";
}
if (JsonLdUtils.isKeyword(property)) {
return property;
}
final Map td = (Map) termDefinitions.get(property);
if (td == null) {
return null;
}
return (String) td.get("@container");
}
public Boolean isReverseProperty(String property) {
final Map td = (Map) termDefinitions.get(property);
if (td == null) {
return false;
}
final Object reverse = td.get("@reverse");
return reverse != null && (Boolean) reverse;
}
private String getTypeMapping(String property) {
final Map td = (Map) termDefinitions.get(property);
if (td == null) {
return null;
}
return (String) td.get("@type");
}
private String getLanguageMapping(String property) {
final Map td = (Map) termDefinitions.get(property);
if (td == null) {
return null;
}
return (String) td.get("@language");
}
Map getTermDefinition(String key) {
return ((Map) termDefinitions.get(key));
}
public Object expandValue(String activeProperty, Object value) throws JsonLdError {
final Map rval = new LinkedHashMap();
final Map td = getTermDefinition(activeProperty);
// 1)
if (td != null && "@id".equals(td.get("@type"))) {
// TODO: i'm pretty sure value should be a string if the @type is
// @id
rval.put("@id", expandIri(value.toString(), true, false, null, null));
return rval;
}
// 2)
if (td != null && "@vocab".equals(td.get("@type"))) {
// TODO: same as above
rval.put("@id", expandIri(value.toString(), true, true, null, null));
return rval;
}
// 3)
rval.put("@value", value);
// 4)
if (td != null && td.containsKey("@type")) {
rval.put("@type", td.get("@type"));
}
// 5)
else if (value instanceof String) {
// 5.1)
if (td != null && td.containsKey("@language")) {
final String lang = (String) td.get("@language");
if (lang != null) {
rval.put("@language", lang);
}
}
// 5.2)
else if (this.get("@language") != null) {
rval.put("@language", this.get("@language"));
}
}
return rval;
}
public Object getContextValue(String activeProperty, String string) throws JsonLdError {
throw new JsonLdError(Error.NOT_IMPLEMENTED,
"getContextValue is only used by old code so far and thus isn't implemented");
}
public Map serialize() {
final Map ctx = new LinkedHashMap();
if (this.get("@base") != null && !this.get("@base").equals(options.getBase())) {
ctx.put("@base", this.get("@base"));
}
if (this.get("@language") != null) {
ctx.put("@language", this.get("@language"));
}
if (this.get("@vocab") != null) {
ctx.put("@vocab", this.get("@vocab"));
}
for (final String term : termDefinitions.keySet()) {
final Map definition = (Map) termDefinitions.get(term);
if (definition.get("@language") == null
&& definition.get("@container") == null
&& definition.get("@type") == null
&& (definition.get("@reverse") == null || Boolean.FALSE.equals(definition
.get("@reverse")))) {
final String cid = this.compactIri((String) definition.get("@id"));
ctx.put(term, term.equals(cid) ? definition.get("@id") : cid);
} else {
final Map defn = new LinkedHashMap();
final String cid = this.compactIri((String) definition.get("@id"));
final Boolean reverseProperty = Boolean.TRUE.equals(definition.get("@reverse"));
if (!(term.equals(cid) && !reverseProperty)) {
defn.put(reverseProperty ? "@reverse" : "@id", cid);
}
final String typeMapping = (String) definition.get("@type");
if (typeMapping != null) {
defn.put("@type", JsonLdUtils.isKeyword(typeMapping) ? typeMapping
: compactIri(typeMapping, true));
}
if (definition.get("@container") != null) {
defn.put("@container", definition.get("@container"));
}
final Object lang = definition.get("@language");
if (definition.get("@language") != null) {
defn.put("@language", Boolean.FALSE.equals(lang) ? null : lang);
}
ctx.put(term, defn);
}
}
final Map rval = new LinkedHashMap();
if (!(ctx == null || ctx.isEmpty())) {
rval.put("@context", ctx);
}
return rval;
}
}