diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml
index 30b7012..457e8ad 100644
--- a/.github/workflows/deploy.yaml
+++ b/.github/workflows/deploy.yaml
@@ -17,7 +17,7 @@ jobs:
- name: Set up JDK, for pushing into github package registry
uses: actions/setup-java@v5
with:
- java-version: '25'
+ java-version: '21'
distribution: 'temurin'
cache: maven
diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml
index df45c47..0c05581 100644
--- a/.github/workflows/test.yaml
+++ b/.github/workflows/test.yaml
@@ -16,10 +16,10 @@ jobs:
steps:
- uses: actions/checkout@v6
- - name: Set up JDK 17
+ - name: Set up JDK 21
uses: actions/setup-java@v5
with:
- java-version: '17'
+ java-version: '21'
distribution: 'temurin'
cache: maven
diff --git a/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java b/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java
index 68eb2ef..5e2c4e6 100644
--- a/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java
+++ b/cli/src/main/java/de/wwu/scdh/annotation/selection/cli/NormalizeWADM.java
@@ -1,13 +1,12 @@
package de.wwu.scdh.annotation.selection.cli;
import com.apicatalog.jsonld.JsonLd;
+import com.apicatalog.jsonld.JsonLdEmbed;
+import com.apicatalog.jsonld.JsonLdOptions;
import com.apicatalog.jsonld.api.FramingApi;
-import com.apicatalog.jsonld.document.Document;
import com.apicatalog.jsonld.document.JsonDocument;
-import com.apicatalog.jsonld.document.RdfDocument;
-import com.apicatalog.jsonld.lang.Keywords;
-import com.apicatalog.rdf.RdfDataset;
import de.wwu.scdh.annotation.selection.Resource;
+import de.wwu.scdh.annotation.selection.utils.StaticDocumentLoader;
import de.wwu.scdh.annotation.selection.wadm.NormalizeAnnotation;
import jakarta.json.Json;
import jakarta.json.JsonArray;
@@ -30,9 +29,11 @@
import org.apache.jena.riot.RDFLanguages;
import org.apache.jena.riot.RDFWriterRegistry;
import org.apache.jena.riot.WriterDatasetRIOT;
-import org.apache.jena.riot.system.JenaTitanium;
import org.apache.jena.riot.system.PrefixMap;
import org.apache.jena.riot.system.PrefixMapZero;
+import org.apache.jena.riot.system.jsonld.JenaToTitanium;
+import org.apache.jena.sparql.core.DatasetGraph;
+import org.apache.jena.sparql.core.DatasetGraphFactory;
import org.apache.jena.sparql.core.DatasetImpl;
import org.apache.jena.sparql.util.Context;
import picocli.CommandLine;
@@ -123,17 +124,19 @@ public Integer call() throws Exception {
// do the framing and serialization with Titanium
try {
- RdfDataset rdfds = JenaTitanium.convert(ds.asDatasetGraph());
- Document rdfdoc = RdfDocument.of(rdfds);
- // The Titanium API for framing does not allow
- // RdfDocuments. Thus, we make a JsonDocument
- // representing the graph like for plain output
- JsonArray array = JsonLd.fromRdf(rdfdoc).get();
- JsonObject jsonStructure =
- Json.createObjectBuilder().add(Keywords.GRAPH, array).build();
- JsonDocument jsonDocument = JsonDocument.of(jsonStructure);
+ // use titanium for framing
+ JsonLdOptions options = new JsonLdOptions();
+ // options.setBase(null);
+ options.setDocumentLoader(new StaticDocumentLoader());
+ options.setOmitGraph(true);
+ options.setEmbed(JsonLdEmbed.ALWAYS);
+ // add more options here!
+ DatasetGraph dsg = DatasetGraphFactory.create(model.getGraph());
+ JsonArray ja = JenaToTitanium.convert(dsg, options);
+ JsonDocument jDoc = JsonDocument.of(ja);
// do the framing
- FramingApi api = JsonLd.frame(jsonDocument, JsonDocument.of(framingUri.openStream()));
+ FramingApi api = JsonLd.frame(jDoc, JsonDocument.of(framingUri.openStream()));
+ api.loader(options.getDocumentLoader()); // important to set loader!
final JsonObject output = api.get();
// JsonOutput.print(System.out, true);
diff --git a/core/src/main/java/de/wwu/scdh/annotation/selection/utils/StaticDocumentLoader.java b/core/src/main/java/de/wwu/scdh/annotation/selection/utils/StaticDocumentLoader.java
new file mode 100644
index 0000000..ac06cdc
--- /dev/null
+++ b/core/src/main/java/de/wwu/scdh/annotation/selection/utils/StaticDocumentLoader.java
@@ -0,0 +1,148 @@
+package de.wwu.scdh.annotation.selection.utils;
+
+import com.apicatalog.jsonld.JsonLdError;
+import com.apicatalog.jsonld.JsonLdOptions;
+import com.apicatalog.jsonld.document.Document;
+import com.apicatalog.jsonld.loader.DocumentLoader;
+import com.apicatalog.jsonld.loader.DocumentLoaderOptions;
+import com.apicatalog.jsonld.loader.FileLoader;
+import jakarta.json.Json;
+import jakarta.json.JsonObject;
+import jakarta.json.JsonReader;
+import jakarta.json.JsonStructure;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.HashMap;
+import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The {@link StaticDocumentLoader} is a {@link DocumentLoader} that returns local assets instead of remote one.
+ * It is configured with a resource mapping that maps URIs to local assets. Its purpose is to speed up
+ * JSON-LD processing with version pinned contexts, as for Web Annotations.
+ *
+ * The loader delegated to a fallback loader when the requested URI is not in the resource mapping.
+ *
+ * The structure of the resource mapping JSON file:
+ *
+ *
+ * {
+ * "https://www.w3.org/ns/anno.jsonld": {
+ * "path": "anno.jsonld"
+ * },
+ * "http://www.w3.org/ns/anno.jsonld": {
+ * "path": "anno.jsonld"
+ * }
+ * }
+ *
+ */
+public class StaticDocumentLoader implements DocumentLoader {
+
+ private static final Logger LOG = LoggerFactory.getLogger(StaticDocumentLoader.class);
+
+ /**
+ * A default context mapping resource.
+ */
+ public static final URL CONTEXT_MAPPING = StaticDocumentLoader.class.getResource("/context/context-map.json");
+
+ private final DocumentLoader fallbackLoader;
+
+ private final Map contextMapping;
+
+ private final boolean delegateOnError;
+
+ /**
+ * Creates a new {@link StaticDocumentLoader} from a resource mapping given by {@link File}.
+ * @param contextMap - a JSON {@link File>} with the resource mapping
+ * @param fallbackLoader - a {@link DocumentLoader} used to handle request for non-mapped resources
+ * @param delegateOnError - whether to delegate the request to the fallback, when loading of a local asset failed.
+ */
+ public StaticDocumentLoader(final File contextMap, final DocumentLoader fallbackLoader, boolean delegateOnError) {
+ this.fallbackLoader = fallbackLoader;
+ this.delegateOnError = delegateOnError;
+ contextMapping = setup(contextMap);
+ }
+
+ /**
+ * Creates a new {@link StaticDocumentLoader} from the {@link StaticDocumentLoader#CONTEXT_MAPPING}.
+ */
+ public StaticDocumentLoader() {
+ fallbackLoader = (new JsonLdOptions()).getDocumentLoader(); // default loader
+ delegateOnError = true;
+ File defaultContextMapping = new File(CONTEXT_MAPPING.getPath());
+ contextMapping = setup(defaultContextMapping);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Document loadDocument(URI url, DocumentLoaderOptions options) throws JsonLdError {
+ if (contextMapping.containsKey(url)) {
+ URI file = contextMapping.get(url);
+ FileLoader fileLoader = new FileLoader();
+ try {
+ return fileLoader.loadDocument(file, options);
+ } catch (JsonLdError e) {
+ LOG.error("failed to load static asset for {}: {}", url, e.getMessage());
+ if (delegateOnError) {
+ return fallbackLoader.loadDocument(url, options);
+ } else {
+ throw new JsonLdError(e.getCode(), e.getMessage());
+ }
+ }
+ } else {
+ // delegate to fallback loader
+ return fallbackLoader.loadDocument(url, options);
+ }
+ }
+
+ private Map setup(File contextMap) {
+ Path path = contextMap.toPath().getParent();
+ Map assets = new HashMap<>();
+
+ try {
+ JsonReader jsonReader = Json.createReader(new FileReader(contextMap));
+ JsonStructure jsonStructure = jsonReader.read();
+ JsonObject root = jsonStructure.asJsonObject();
+ for (String url : root.keySet()) {
+ try {
+ URI remote = new URI(url);
+ String relative = root.get(url).asJsonObject().getString("path");
+ File resolved = path.resolve(relative).toFile();
+ if (resolved.isFile()) {
+ assets.put(remote, resolved.toURI());
+ } else {
+ LOG.error(
+ "context map entry {} configures file {}, which resolves to {}. File not present",
+ url,
+ relative,
+ resolved);
+ }
+ } catch (URISyntaxException e) {
+ LOG.error("context map entry {} is not a valid URI. Continuing without this entry", url);
+ } catch (Exception e) {
+ LOG.error("invalid context map entry {}. Continuing without this entry", url);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ LOG.error("file not found: {}\nContinuing without context map", contextMap);
+ }
+ return Map.copyOf(assets); // makes map unmodifiable
+ }
+
+ /**
+ * Tells whether this instance has a local version for a URI.
+ * @param uri - the remote URI
+ * @return - true if a local version is available.
+ */
+ public boolean hasLocal(URI uri) {
+ return contextMapping.containsKey(uri);
+ }
+}
diff --git a/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java b/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java
index 77521bd..dc7793a 100644
--- a/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java
+++ b/core/src/main/java/de/wwu/scdh/annotation/selection/wadm/NormalizeAnnotation.java
@@ -1,18 +1,17 @@
package de.wwu.scdh.annotation.selection.wadm;
+import com.apicatalog.jsonld.JsonLdOptions;
import de.wwu.scdh.annotation.selection.*;
+import de.wwu.scdh.annotation.selection.utils.StaticDocumentLoader;
import java.io.InputStream;
import java.net.URI;
import java.util.Optional;
import java.util.function.Consumer;
-import org.apache.jena.ontology.OntModelSpec;
-import org.apache.jena.ontology.impl.OntModelImpl;
import org.apache.jena.rdf.model.Model;
import org.apache.jena.rdf.model.ResIterator;
import org.apache.jena.rdf.model.Resource;
-import org.apache.jena.riot.Lang;
-import org.apache.jena.riot.RDFDataMgr;
-import org.apache.jena.riot.RDFLanguages;
+import org.apache.jena.riot.*;
+import org.apache.jena.riot.system.jsonld.TitaniumJsonLdOptions;
import org.apache.jena.vocabulary.OA;
import org.apache.jena.vocabulary.RDF;
import org.slf4j.Logger;
@@ -134,7 +133,12 @@ public static Model rewrite(
/**
* Normalize all annotations in a {@link Model} given by a URI
* as {@link String} which may reference a local file (file URI)
- * or an online resource.
+ * or an online resource.
+ *
+ * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD
+ * document loader. If you want full control over RDF parsing, the use
+ * {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, Model)}
+ * instead.
*
* @param resource - the resource the rewriting has to done with
* @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on
@@ -151,12 +155,10 @@ public static Model normalize(
RewriterConfig normalizerConfig,
String graph,
Optional lang) {
- Model model;
- if (lang.isEmpty()) {
- model = RDFDataMgr.loadModel(graph);
- } else {
- model = RDFDataMgr.loadModel(graph, RDFLanguages.nameToLang(lang.get()));
- }
+ RDFParserBuilder parserBuilder = RDFParser.source(graph);
+ setParserOptions(parserBuilder);
+ lang.ifPresent(l -> parserBuilder.lang(RDFLanguages.nameToLang(l)));
+ Model model = parserBuilder.toModel();
return normalize(resource, iri, rewriterFactory, normalizerConfig, model);
}
@@ -164,7 +166,12 @@ public static Model normalize(
* Rewrite all annotations in the provided {@link Model}. In contrast to
* {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, String, Optional)}
* this method also rewrites the oa:hasSource property and is thus suitable for transforming selectors
- * between representations.
+ * between representations.
+ *
+ * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD
+ * document loader. If you want full control over RDF parsing, the use
+ * {@link NormalizeAnnotation#rewrite(de.wwu.scdh.annotation.selection.Resource, URI, URI, RewriterFactory, RewriterConfig, Model)}
+ * instead.
*
* @param resource - the resource the rewriting has to done with. Should be a {@link MappedResource}.
* @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on
@@ -183,18 +190,21 @@ public static Model rewrite(
RewriterConfig normalizerConfig,
String graph,
Optional lang) {
- Model model;
- if (lang.isEmpty()) {
- model = RDFDataMgr.loadModel(graph);
- } else {
- model = RDFDataMgr.loadModel(graph, RDFLanguages.nameToLang(lang.get()));
- }
+ RDFParserBuilder parserBuilder = RDFParser.source(graph);
+ setParserOptions(parserBuilder);
+ lang.ifPresent(l -> parserBuilder.lang(RDFLanguages.nameToLang(l)));
+ Model model = parserBuilder.toModel();
return rewrite(resource, iri, rewriteIri, rewriterFactory, normalizerConfig, model);
}
/**
* Normalize all annotations in a {@link Model} which is read from
- * an {@link InputStream}.
+ * an {@link InputStream}.
+ *
+ * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD
+ * document loader. If you want full control over RDF parsing, the use
+ * {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, Model)}
+ * instead.
*
* @param resource - the resource the rewriting has to done with
* @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on
@@ -213,18 +223,20 @@ public static Model normalize(
InputStream input,
Optional lang,
Optional modelBase) {
- Model model = new OntModelImpl(OntModelSpec.OWL_DL_MEM);
- Lang langHint;
- if (lang.isEmpty()) {
-
- langHint = RDFLanguages.nameToLang(lang.get());
+ RDFParserBuilder parserBuilder = RDFParser.source(input);
+ modelBase.ifPresent(parserBuilder::base);
+ setParserOptions(parserBuilder);
+ if (lang.isPresent()) {
+ parserBuilder.lang(RDFLanguages.nameToLang(lang.get()));
} else {
- langHint = RDFLanguages.NTRIPLES;
+ parserBuilder.lang(Lang.NTRIPLES);
}
- if (modelBase.isEmpty()) {
- RDFDataMgr.read(model, input, langHint);
- } else {
- RDFDataMgr.read(model, input, modelBase.get(), langHint);
+ Model model = parserBuilder.toModel();
+ try {
+ input.close();
+ LOG.warn("closed input stream");
+ } catch (Exception ignored) {
+ LOG.warn("failed to close input stream");
}
return normalize(resource, iri, rewriterFactory, normalizerConfig, model);
}
@@ -233,8 +245,13 @@ public static Model normalize(
* Rewrite all annotations in the provided {@link Model}. In contrast to
* {@link NormalizeAnnotation#normalize(de.wwu.scdh.annotation.selection.Resource, URI, RewriterFactory, RewriterConfig, InputStream, Optional, Optional)}
* this method also rewrites the oa:hasSource property and is thus suitable for transforming selectors
- * between representations.
+ * between representations.
*
+ * Note, that this method sets options to the RDF parser, e.g., the {@link StaticDocumentLoader} as JSON-LD
+ * document loader. If you want full control over RDF parsing, the use
+ * {@link NormalizeAnnotation#rewrite(de.wwu.scdh.annotation.selection.Resource, URI, URI, RewriterFactory, RewriterConfig, Model)}
+ * instead.
+ * *
* @param resource - the resource the rewriting has to done with. Should be a {@link MappedResource}.
* @param iri - the IRI of sources (oa:hasSource) the rewriting has to done on
* @param rewriterFactory - a factory that returns a rewriter for a point
@@ -253,19 +270,25 @@ public static Model rewrite(
InputStream input,
Optional lang,
Optional modelBase) {
- Model model = new OntModelImpl(OntModelSpec.OWL_DL_MEM);
- Lang langHint;
- if (lang.isEmpty()) {
-
- langHint = RDFLanguages.nameToLang(lang.get());
- } else {
- langHint = RDFLanguages.NTRIPLES;
- }
- if (modelBase.isEmpty()) {
- RDFDataMgr.read(model, input, langHint);
+ RDFParserBuilder parserBuilder = RDFParser.source(input);
+ modelBase.ifPresent(parserBuilder::base);
+ setParserOptions(parserBuilder);
+ if (lang.isPresent()) {
+ parserBuilder.lang(RDFLanguages.nameToLang(lang.get()));
} else {
- RDFDataMgr.read(model, input, modelBase.get(), langHint);
+ parserBuilder.lang(Lang.NTRIPLES);
}
+ Model model = parserBuilder.toModel();
return rewrite(resource, iri, rewriteIri, rewriterFactory, normalizerConfig, model);
}
+
+ /**
+ * Sets RDF parser options.
+ * @param parserBuilder - the Apache Jena {@link RDFParserBuilder}
+ */
+ private static void setParserOptions(RDFParserBuilder parserBuilder) {
+ JsonLdOptions options = new JsonLdOptions();
+ options.setDocumentLoader(new StaticDocumentLoader());
+ parserBuilder.set(TitaniumJsonLdOptions.JSONLD_OPTIONS, options);
+ }
}
diff --git a/core/src/main/resources/context/anno.jsonld b/core/src/main/resources/context/anno.jsonld
new file mode 100644
index 0000000..1bd517e
--- /dev/null
+++ b/core/src/main/resources/context/anno.jsonld
@@ -0,0 +1,126 @@
+{
+ "@context": {
+ "oa": "http://www.w3.org/ns/oa#",
+ "dc": "http://purl.org/dc/elements/1.1/",
+ "dcterms": "http://purl.org/dc/terms/",
+ "dctypes": "http://purl.org/dc/dcmitype/",
+ "foaf": "http://xmlns.com/foaf/0.1/",
+ "rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+ "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
+ "skos": "http://www.w3.org/2004/02/skos/core#",
+ "xsd": "http://www.w3.org/2001/XMLSchema#",
+ "iana": "http://www.iana.org/assignments/relation/",
+ "owl": "http://www.w3.org/2002/07/owl#",
+ "as": "http://www.w3.org/ns/activitystreams#",
+ "schema": "http://schema.org/",
+
+ "id": {"@type": "@id", "@id": "@id"},
+ "type": {"@type": "@id", "@id": "@type"},
+
+ "Annotation": "oa:Annotation",
+ "Dataset": "dctypes:Dataset",
+ "Image": "dctypes:StillImage",
+ "Video": "dctypes:MovingImage",
+ "Audio": "dctypes:Sound",
+ "Text": "dctypes:Text",
+ "TextualBody": "oa:TextualBody",
+ "ResourceSelection": "oa:ResourceSelection",
+ "SpecificResource": "oa:SpecificResource",
+ "FragmentSelector": "oa:FragmentSelector",
+ "CssSelector": "oa:CssSelector",
+ "XPathSelector": "oa:XPathSelector",
+ "TextQuoteSelector": "oa:TextQuoteSelector",
+ "TextPositionSelector": "oa:TextPositionSelector",
+ "DataPositionSelector": "oa:DataPositionSelector",
+ "SvgSelector": "oa:SvgSelector",
+ "RangeSelector": "oa:RangeSelector",
+ "TimeState": "oa:TimeState",
+ "HttpRequestState": "oa:HttpRequestState",
+ "CssStylesheet": "oa:CssStyle",
+ "Choice": "oa:Choice",
+ "Person": "foaf:Person",
+ "Software": "as:Application",
+ "Organization": "foaf:Organization",
+ "AnnotationCollection": "as:OrderedCollection",
+ "AnnotationPage": "as:OrderedCollectionPage",
+ "Audience": "schema:Audience",
+
+ "Motivation": "oa:Motivation",
+ "bookmarking": "oa:bookmarking",
+ "classifying": "oa:classifying",
+ "commenting": "oa:commenting",
+ "describing": "oa:describing",
+ "editing": "oa:editing",
+ "highlighting": "oa:highlighting",
+ "identifying": "oa:identifying",
+ "linking": "oa:linking",
+ "moderating": "oa:moderating",
+ "questioning": "oa:questioning",
+ "replying": "oa:replying",
+ "reviewing": "oa:reviewing",
+ "assessing": "oa:assessing",
+ "tagging": "oa:tagging",
+
+ "auto": "oa:autoDirection",
+ "ltr": "oa:ltrDirection",
+ "rtl": "oa:rtlDirection",
+
+ "body": {"@type": "@id", "@id": "oa:hasBody"},
+ "target": {"@type": "@id", "@id": "oa:hasTarget"},
+ "source": {"@type": "@id", "@id": "oa:hasSource"},
+ "selector": {"@type": "@id", "@id": "oa:hasSelector"},
+ "state": {"@type": "@id", "@id": "oa:hasState"},
+ "scope": {"@type": "@id", "@id": "oa:hasScope"},
+ "refinedBy": {"@type": "@id", "@id": "oa:refinedBy"},
+ "startSelector": {"@type": "@id", "@id": "oa:hasStartSelector"},
+ "endSelector": {"@type": "@id", "@id": "oa:hasEndSelector"},
+ "renderedVia": {"@type": "@id", "@id": "oa:renderedVia"},
+ "creator": {"@type": "@id", "@id": "dcterms:creator"},
+ "generator": {"@type": "@id", "@id": "as:generator"},
+ "rights": {"@type": "@id", "@id": "dcterms:rights"},
+ "homepage": {"@type": "@id", "@id": "foaf:homepage"},
+ "via": {"@type": "@id", "@id": "oa:via"},
+ "canonical": {"@type": "@id", "@id": "oa:canonical"},
+ "stylesheet": {"@type": "@id", "@id": "oa:styledBy"},
+ "cached": {"@type": "@id", "@id": "oa:cachedSource"},
+ "conformsTo": {"@type": "@id", "@id": "dcterms:conformsTo"},
+ "items": {"@type": "@id", "@id": "as:items", "@container": "@list"},
+ "partOf": {"@type": "@id", "@id": "as:partOf"},
+ "first": {"@type": "@id", "@id": "as:first"},
+ "last": {"@type": "@id", "@id": "as:last"},
+ "next": {"@type": "@id", "@id": "as:next"},
+ "prev": {"@type": "@id", "@id": "as:prev"},
+ "audience": {"@type": "@id", "@id": "schema:audience"},
+ "motivation": {"@type": "@vocab", "@id": "oa:motivatedBy"},
+ "purpose": {"@type": "@vocab", "@id": "oa:hasPurpose"},
+ "textDirection": {"@type": "@vocab", "@id": "oa:textDirection"},
+
+ "accessibility": "schema:accessibilityFeature",
+ "bodyValue": "oa:bodyValue",
+ "format": "dc:format",
+ "language": "dc:language",
+ "processingLanguage": "oa:processingLanguage",
+ "value": "rdf:value",
+ "exact": "oa:exact",
+ "prefix": "oa:prefix",
+ "suffix": "oa:suffix",
+ "styleClass": "oa:styleClass",
+ "name": "foaf:name",
+ "email": "foaf:mbox",
+ "email_sha1": "foaf:mbox_sha1sum",
+ "nickname": "foaf:nick",
+ "label": "rdfs:label",
+
+ "created": {"@id": "dcterms:created", "@type": "xsd:dateTime"},
+ "modified": {"@id": "dcterms:modified", "@type": "xsd:dateTime"},
+ "generated": {"@id": "dcterms:issued", "@type": "xsd:dateTime"},
+ "sourceDate": {"@id": "oa:sourceDate", "@type": "xsd:dateTime"},
+ "sourceDateStart": {"@id": "oa:sourceDateStart", "@type": "xsd:dateTime"},
+ "sourceDateEnd": {"@id": "oa:sourceDateEnd", "@type": "xsd:dateTime"},
+
+ "start": {"@id": "oa:start", "@type": "xsd:nonNegativeInteger"},
+ "end": {"@id": "oa:end", "@type": "xsd:nonNegativeInteger"},
+ "total": {"@id": "as:totalItems", "@type": "xsd:nonNegativeInteger"},
+ "startIndex": {"@id": "as:startIndex", "@type": "xsd:nonNegativeInteger"}
+ }
+}
diff --git a/core/src/main/resources/context/context-map.json b/core/src/main/resources/context/context-map.json
new file mode 100644
index 0000000..22a9b71
--- /dev/null
+++ b/core/src/main/resources/context/context-map.json
@@ -0,0 +1,8 @@
+{
+ "https://www.w3.org/ns/anno.jsonld": {
+ "path": "anno.jsonld"
+ },
+ "http://www.w3.org/ns/anno.jsonld": {
+ "path": "anno.jsonld"
+ }
+}
\ No newline at end of file
diff --git a/core/src/test/java/de/wwu/scdh/annotation/selection/utils/TestStaticDocumentLoader.java b/core/src/test/java/de/wwu/scdh/annotation/selection/utils/TestStaticDocumentLoader.java
new file mode 100644
index 0000000..9ba47c4
--- /dev/null
+++ b/core/src/test/java/de/wwu/scdh/annotation/selection/utils/TestStaticDocumentLoader.java
@@ -0,0 +1,26 @@
+package de.wwu.scdh.annotation.selection.utils;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import org.junit.jupiter.api.Test;
+
+public class TestStaticDocumentLoader {
+
+ @Test
+ public void testDefaultContextMapping() {
+ assertNotNull(StaticDocumentLoader.CONTEXT_MAPPING, "context mapping exists and is accessible");
+ }
+
+ @Test
+ public void testNoArgumentConstructor() throws URISyntaxException {
+ StaticDocumentLoader loader = new StaticDocumentLoader();
+ assertTrue(
+ loader.hasLocal(new URI("https://www.w3.org/ns/anno.jsonld")),
+ "has local version of Web Annotations context (https)");
+ assertTrue(
+ loader.hasLocal(new URI("http://www.w3.org/ns/anno.jsonld")),
+ "has local version of Web Annotations context (http)");
+ }
+}
diff --git a/pom.xml b/pom.xml
index 0a0a989..eb0354b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -64,7 +64,7 @@
4.5.1
1.4.01
3.18.0
- 5.2.0
+ 6.0.0
6.0.1
3.4.0
2.90.0