com.apicatalog.jsonld.compaction.UriCompaction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of titanium-json-ld Show documentation
Show all versions of titanium-json-ld Show documentation
A JSON-LD 1.1 Processor & API
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.apicatalog.jsonld.compaction;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import com.apicatalog.jsonld.JsonLdError;
import com.apicatalog.jsonld.JsonLdErrorCode;
import com.apicatalog.jsonld.context.ActiveContext;
import com.apicatalog.jsonld.context.InverseContext;
import com.apicatalog.jsonld.context.TermDefinition;
import com.apicatalog.jsonld.json.JsonUtils;
import com.apicatalog.jsonld.lang.BlankNode;
import com.apicatalog.jsonld.lang.GraphObject;
import com.apicatalog.jsonld.lang.Keywords;
import com.apicatalog.jsonld.lang.ListObject;
import com.apicatalog.jsonld.lang.NodeObject;
import com.apicatalog.jsonld.lang.ValueObject;
import com.apicatalog.jsonld.uri.UriRelativizer;
import jakarta.json.JsonArray;
import jakarta.json.JsonString;
import jakarta.json.JsonValue;
/**
*
* @see IRI
* Compaction
*
*/
public final class UriCompaction {
// required
private final ActiveContext activeContext;
// optional
private JsonValue value;
private boolean vocab;
private boolean reverse;
private UriCompaction(final ActiveContext activeContext) {
this.activeContext = activeContext;
// default values
this.value = null;
this.vocab = false;
this.reverse = false;
}
public static UriCompaction with(final ActiveContext activeContext) {
return new UriCompaction(activeContext);
}
public UriCompaction value(JsonValue value) {
this.value = value;
return this;
}
public UriCompaction vocab(boolean vocab) {
this.vocab = vocab;
return this;
}
public UriCompaction reverse(boolean reverse) {
this.reverse = reverse;
return this;
}
public String compact(final String variable) throws JsonLdError {
// 1.
if (variable == null) {
return null;
}
// 2.
if (activeContext.getInverseContext() == null) {
activeContext.createInverseContext();
}
// 3.
InverseContext inverseContext = activeContext.getInverseContext();
// 4.
if (vocab && inverseContext.contains(variable)) {
// 4.1.
String defaultLanguage = Keywords.NONE;
if (activeContext.getDefaultLanguage() != null) {
defaultLanguage = activeContext.getDefaultLanguage().toLowerCase();
if (activeContext.getDefaultBaseDirection() != null) {
defaultLanguage += "_".concat(activeContext.getDefaultBaseDirection().name().toLowerCase());
}
} else if (activeContext.getDefaultBaseDirection() != null) {
defaultLanguage = "_".concat(activeContext.getDefaultBaseDirection().name().toLowerCase());
}
// 4.2.
if (JsonUtils.containsKey(value, Keywords.PRESERVE)) {
JsonValue preserve = value.asJsonObject().get(Keywords.PRESERVE);
if (JsonUtils.isNotNull(preserve)) {
value = JsonUtils.toJsonArray(preserve).get(0);
}
}
// 4.3.
Collection containers = new ArrayList<>();
// 4.4.
String typeLanguage = Keywords.LANGUAGE;
String typeLanguageValue = Keywords.NULL;
// 4.5.
if (JsonUtils.containsKey(value, Keywords.INDEX) && !GraphObject.isGraphObject(value)) {
containers.add(Keywords.INDEX);
containers.add(Keywords.INDEX.concat(Keywords.SET));
}
// 4.6.
if (reverse) {
typeLanguage = Keywords.TYPE;
typeLanguageValue = Keywords.REVERSE;
containers.add(Keywords.SET);
// 4.7.
} else if (ListObject.isListObject(value)) {
// 4.7.1.
if (!value.asJsonObject().containsKey(Keywords.INDEX)) {
containers.add(Keywords.LIST);
}
// 4.7.2.
JsonArray list = value.asJsonObject().get(Keywords.LIST).asJsonArray();
// 4.7.3.
String commonType = null;
String commonLanguage = list.isEmpty()
? defaultLanguage
: null;
// 4.7.4.
for (JsonValue item : list) {
// 4.7.4.1.
String itemLanguage = Keywords.NONE;
String itemType = Keywords.NONE;
// 4.7.4.2.
if (JsonUtils.containsKey(item, Keywords.VALUE)) {
// 4.7.4.2.1.
if (item.asJsonObject().containsKey(Keywords.DIRECTION)) {
itemLanguage = "";
if (item.asJsonObject().containsKey(Keywords.LANGUAGE)) {
itemLanguage = item.asJsonObject().getString(Keywords.LANGUAGE).toLowerCase();
}
itemLanguage += "_".concat(item.asJsonObject().getString(Keywords.DIRECTION).toLowerCase());
// 4.7.4.2.2.
} else if (item.asJsonObject().containsKey(Keywords.LANGUAGE)) {
itemLanguage = item.asJsonObject().getString(Keywords.LANGUAGE).toLowerCase();
// 4.7.4.2.3.
} else if (item.asJsonObject().containsKey(Keywords.TYPE)) {
itemType = item.asJsonObject().getString(Keywords.TYPE);
// 4.7.4.2.4.
} else {
itemLanguage = Keywords.NULL;
}
// 4.7.4.3.
} else {
itemType = Keywords.ID;
}
// 4.7.4.4.
if (commonLanguage == null) {
commonLanguage = itemLanguage;
// 4.7.4.5.
} else if (!Objects.equals(itemLanguage, commonLanguage)
&& JsonUtils.containsKey(item, Keywords.VALUE)) {
commonLanguage = Keywords.NONE;
}
// 4.7.4.6.
if (commonType == null) {
commonType = itemType;
// 4.7.4.7.
} else if (!Objects.equals(itemType, commonType)) {
commonType = Keywords.NONE;
}
// 4.7.4.8.
if (Keywords.NONE.equals(commonLanguage) && Keywords.NONE.equals(commonType)) {
break;
}
}
// 4.7.5.
if (commonLanguage == null) {
commonLanguage = Keywords.NONE;
}
// 4.7.6.
if (commonType == null) {
commonType = Keywords.NONE;
}
// 4.7.7.
if (!Keywords.NONE.equals(commonType)) {
typeLanguage = Keywords.TYPE;
typeLanguageValue = commonType;
// 4.7.8.
} else {
typeLanguageValue = commonLanguage;
}
// 4.8.
} else if (GraphObject.isGraphObject(value)) {
// 4.8.1.
if (value.asJsonObject().containsKey(Keywords.INDEX)) {
containers.add(Keywords.GRAPH.concat(Keywords.INDEX));
containers.add(Keywords.GRAPH.concat(Keywords.INDEX).concat(Keywords.SET));
}
// 4.8.2.
if (value.asJsonObject().containsKey(Keywords.ID)) {
containers.add(Keywords.GRAPH.concat(Keywords.ID));
containers.add(Keywords.GRAPH.concat(Keywords.ID).concat(Keywords.SET));
}
// 4.8.3.
containers.add(Keywords.GRAPH);
containers.add(Keywords.GRAPH.concat(Keywords.SET));
containers.add(Keywords.SET);
// 4.8.4.
if (!value.asJsonObject().containsKey(Keywords.INDEX)) {
containers.add(Keywords.GRAPH.concat(Keywords.INDEX));
containers.add(Keywords.GRAPH.concat(Keywords.INDEX).concat(Keywords.SET));
}
// 4.8.5.
if (!value.asJsonObject().containsKey(Keywords.ID)) {
containers.add(Keywords.GRAPH.concat(Keywords.ID));
containers.add(Keywords.GRAPH.concat(Keywords.ID).concat(Keywords.SET));
}
// 4.8.6.
containers.add(Keywords.INDEX);
containers.add(Keywords.INDEX.concat(Keywords.SET));
// 4.8.7.
typeLanguage = Keywords.TYPE;
typeLanguageValue = Keywords.ID;
// 4.9.
} else {
// 4.9.1.
if (ValueObject.isValueObject(value)) {
// 4.9.1.1.
if (JsonUtils.contains(Keywords.DIRECTION, value)
&& !JsonUtils.contains(Keywords.INDEX, value)) {
typeLanguageValue = "";
if (JsonUtils.contains(Keywords.LANGUAGE, value)) {
JsonValue language = value.asJsonObject().get(Keywords.LANGUAGE);
if (JsonUtils.isString(language)) {
typeLanguageValue = ((JsonString) language).getString().toLowerCase();
}
}
JsonValue direction = value.asJsonObject().get(Keywords.DIRECTION);
if (JsonUtils.isString(direction)) {
typeLanguageValue += "_".concat(((JsonString) direction).getString().toLowerCase());
}
containers.add(Keywords.LANGUAGE);
containers.add(Keywords.LANGUAGE.concat(Keywords.SET));
// 4.9.1.2.
} else if (JsonUtils.contains(Keywords.LANGUAGE, value)
&& !JsonUtils.contains(Keywords.INDEX, value)) {
if (JsonUtils.contains(Keywords.LANGUAGE, value)) {
JsonValue language = value.asJsonObject().get(Keywords.LANGUAGE);
if (JsonUtils.isString(language)) {
typeLanguageValue = ((JsonString) language).getString().toLowerCase();
}
}
containers.add(Keywords.LANGUAGE);
containers.add(Keywords.LANGUAGE.concat(Keywords.SET));
// 4.9.1.3.
} else if (JsonUtils.contains(Keywords.TYPE, value)) {
typeLanguage = Keywords.TYPE;
typeLanguageValue = value.asJsonObject().getString(Keywords.TYPE);
}
// 4.9.2.
} else {
typeLanguage = Keywords.TYPE;
typeLanguageValue = Keywords.ID;
containers.add(Keywords.ID);
containers.add(Keywords.ID.concat(Keywords.SET));
containers.add(Keywords.TYPE);
containers.add(Keywords.SET.concat(Keywords.TYPE));
}
// 4.9.3.
containers.add(Keywords.SET);
}
// 4.10.
containers.add(Keywords.NONE);
// 4.11.
if (!activeContext.runtime().isV10()
&& (JsonUtils.isNotObject(value)
|| !value.asJsonObject().containsKey(Keywords.INDEX))) {
containers.add(Keywords.INDEX);
containers.add(Keywords.INDEX.concat(Keywords.SET));
}
// 4.12.
if (!activeContext.runtime().isV10()
&& JsonUtils.containsKey(value, Keywords.VALUE)
&& value.asJsonObject().size() == 1) {
containers.add(Keywords.LANGUAGE);
containers.add(Keywords.LANGUAGE.concat(Keywords.SET));
}
// 4.13.
if (typeLanguageValue == null) {
typeLanguageValue = Keywords.NULL;
}
// 4.14.
Collection preferredValues = new ArrayList<>();
// 4.15.
if (Keywords.REVERSE.equals(typeLanguageValue)) {
preferredValues.add(Keywords.REVERSE);
}
// 4.16.
if ((Keywords.REVERSE.equals(typeLanguageValue) || Keywords.ID.equals(typeLanguageValue))
&& JsonUtils.containsKey(value, Keywords.ID)) {
final JsonValue idValue = value.asJsonObject().get(Keywords.ID);
// json-ld-star
if (activeContext.runtime().isRdfStar() && NodeObject.isEmbeddedNode(idValue)) {
preferredValues.add(Keywords.ID);
preferredValues.add(Keywords.VOCAB);
} else if (JsonUtils.isString(idValue)) {
// 4.16.1.
final String idString = ((JsonString) idValue).getString();
final String compactedIdValue = activeContext.uriCompaction().vocab(true).compact(idString);
final Optional compactedIdValueTermDefinition = activeContext.getTerm(compactedIdValue);
if (compactedIdValueTermDefinition
.map(TermDefinition::getUriMapping)
.filter(idString::equals)
.isPresent()) {
preferredValues.add(Keywords.VOCAB);
preferredValues.add(Keywords.ID);
// 4.16.2.
} else {
preferredValues.add(Keywords.ID);
preferredValues.add(Keywords.VOCAB);
}
} else {
throw new JsonLdError(JsonLdErrorCode.INVALID_KEYWORD_ID_VALUE, "An @id entry was encountered whose value was not a string but [" + idValue + "].");
}
preferredValues.add(Keywords.NONE);
// 4.17.
} else {
preferredValues.add(typeLanguageValue);
preferredValues.add(Keywords.NONE);
if (ListObject.isListObject(value)
&& JsonUtils.isEmptyArray(value.asJsonObject().get(Keywords.LIST))) {
typeLanguage = Keywords.ANY;
}
}
// 4.18.
preferredValues.add(Keywords.ANY);
// 4.19.
for (final String preferredValue : new ArrayList<>(preferredValues)) {
int index = preferredValue.indexOf('_');
if (index == -1) {
continue;
}
preferredValues.add(preferredValue.substring(index));
}
// 4.20.
final Optional term = activeContext.termSelector(variable, containers, typeLanguage).match(preferredValues);
// 4.21.
if (term.isPresent()) {
return term.get();
}
}
// 5., 5.1.
if ((vocab && activeContext.getVocabularyMapping() != null)
&& (variable.startsWith(activeContext.getVocabularyMapping())
&& variable.length() > activeContext.getVocabularyMapping().length())) {
String suffix = variable.substring(activeContext.getVocabularyMapping().length());
if (!activeContext.containsTerm(suffix)) {
return suffix;
}
}
// 6.
String compactUri = null;
// 7.
for (Entry termEntry : activeContext.getTermsMapping().entrySet()) {
TermDefinition termDefinition = termEntry.getValue();
// 7.1.
if (termDefinition.getUriMapping() == null
|| variable.equals(termDefinition.getUriMapping())
|| !variable.startsWith(termDefinition.getUriMapping())
|| termDefinition.isNotPrefix()) {
continue;
}
// 7.2.
String compactUriCandidate = termEntry.getKey()
.concat(":")
.concat(variable.substring(termDefinition.getUriMapping().length()));
// 7.3.
if (((compactUri == null || (compactUriCandidate.compareTo(compactUri) < 0))
&& !activeContext.containsTerm(compactUriCandidate))
|| (activeContext
.getTerm(compactUriCandidate)
.map(TermDefinition::getUriMapping)
.filter(u -> u.equals(variable))
.isPresent()
&& JsonUtils.isNull(value))) {
compactUri = compactUriCandidate;
}
}
/// 8.
if (compactUri != null) {
return compactUri;
}
// 9.
try {
final URI uri = URI.create(variable);
if (uri != null
&& uri.isAbsolute()
&& uri.getScheme() != null
&& uri.getAuthority() == null
&& activeContext.getTerm(uri.getScheme()).filter(TermDefinition::isPrefix).isPresent()) {
throw new JsonLdError(JsonLdErrorCode.IRI_CONFUSED_WITH_PREFIX);
}
} catch (IllegalArgumentException e) {
/* variable is not URI */ }
// 10.
if (!vocab && activeContext.getBaseUri() != null && !BlankNode.hasPrefix(variable)) {
final String relativeUri = UriRelativizer.relativize(activeContext.getBaseUri(), variable);
return Keywords.matchForm(relativeUri) ? "./".concat(relativeUri) : relativeUri;
}
// 11.
return variable;
}
}