Skip to content

Commit 2f3668b

Browse files
committed
GH-5573: support to refine the @context of a JSON-LD document
This change introduces a new setting for the JSONLDWriter, that allows to configure a JSON-LD Context as Hasmac JsonDocument.
1 parent 7410ce4 commit 2f3668b

File tree

3 files changed

+93
-7
lines changed

3 files changed

+93
-7
lines changed

core/rio/jsonld/src/main/java/org/eclipse/rdf4j/rio/jsonld/JSONLDSettings.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ public class JSONLDSettings {
6363
public static final RioSetting<Document> FRAME = new ClassRioSetting<>(
6464
"org.eclipse.rdf4j.rio.jsonld.frame_document",
6565
"A no.hasmac.jsonld.document.Document that contains the frame used for framing as specified in https://www.w3.org/TR/json-ld11-framing/",
66+
null);
67+
68+
public static final RioSetting<Document> CONTEXT = new ClassRioSetting<>(
69+
"org.eclipse.rdf4j.rio.jsonld.context_document",
70+
"A no.hasmac.jsonld.document.Document that contains the JSON-LD context as specified in https://www.w3.org/TR/json-ld11/#the-context. If not defined, the context is created using the namespaces defined in the model",
6671
null);;
6772

6873
/**

core/rio/jsonld/src/main/java/org/eclipse/rdf4j/rio/jsonld/JSONLDWriter.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -267,15 +267,24 @@ public int size() {
267267
jsonld = JsonLd.flatten(JsonDocument.of(jsonld)).options(opts).get();
268268
break;
269269
case COMPACT:
270-
JsonObjectBuilder context = Json.createObjectBuilder();
271-
for (Namespace namespace : model.getNamespaces()) {
272-
if (namespace.getPrefix().isEmpty()) {
273-
context.add("@vocab", namespace.getName());
274-
} else {
275-
context.add(namespace.getPrefix(), namespace.getName());
270+
Document context = writerConfig.get(JSONLDSettings.CONTEXT);
271+
if (context == null) {
272+
273+
// define a default context using namespaces provided in the
274+
// model if none is provided to the writer settings
275+
JsonObjectBuilder contextBuilder = Json.createObjectBuilder();
276+
for (Namespace namespace : model.getNamespaces()) {
277+
if (namespace.getPrefix().isEmpty()) {
278+
contextBuilder.add("@vocab", namespace.getName());
279+
} else {
280+
contextBuilder.add(namespace.getPrefix(), namespace.getName());
281+
}
276282
}
283+
284+
context = JsonDocument.of(contextBuilder.build());
277285
}
278-
jsonld = JsonLd.compact(JsonDocument.of(jsonld), JsonDocument.of(context.build())).options(opts).get();
286+
287+
jsonld = JsonLd.compact(JsonDocument.of(jsonld), context).options(opts).get();
279288
break;
280289
}
281290

core/rio/jsonld/src/test/java/org/eclipse/rdf4j/rio/jsonld/JSONLDWriterTest.java

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,15 @@
2222
import org.eclipse.rdf4j.model.IRI;
2323
import org.eclipse.rdf4j.model.Literal;
2424
import org.eclipse.rdf4j.model.Model;
25+
import org.eclipse.rdf4j.model.Namespace;
2526
import org.eclipse.rdf4j.model.Statement;
2627
import org.eclipse.rdf4j.model.impl.LinkedHashModel;
28+
import org.eclipse.rdf4j.model.util.ModelBuilder;
29+
import org.eclipse.rdf4j.model.util.Values;
2730
import org.eclipse.rdf4j.model.vocabulary.DCTERMS;
31+
import org.eclipse.rdf4j.model.vocabulary.FOAF;
32+
import org.eclipse.rdf4j.model.vocabulary.RDF;
33+
import org.eclipse.rdf4j.model.vocabulary.RDFS;
2834
import org.eclipse.rdf4j.model.vocabulary.XSD;
2935
import org.eclipse.rdf4j.rio.ParserConfig;
3036
import org.eclipse.rdf4j.rio.RDFFormat;
@@ -39,9 +45,12 @@
3945
import org.eclipse.rdf4j.rio.helpers.BasicParserSettings;
4046
import org.eclipse.rdf4j.rio.helpers.BasicWriterSettings;
4147
import org.eclipse.rdf4j.rio.helpers.StatementCollector;
48+
import org.junit.jupiter.api.Assertions;
4249
import org.junit.jupiter.api.Disabled;
4350
import org.junit.jupiter.api.Test;
4451

52+
import jakarta.json.Json;
53+
import jakarta.json.JsonObjectBuilder;
4554
import no.hasmac.jsonld.JsonLdError;
4655
import no.hasmac.jsonld.document.Document;
4756
import no.hasmac.jsonld.document.JsonDocument;
@@ -238,6 +247,69 @@ public void testFraming() throws IOException, JsonLdError {
238247

239248
}
240249

250+
@Test
251+
public void testContextRefine() throws Exception {
252+
253+
Model model = new ModelBuilder()
254+
.subject(Values.iri("https://example.com/bob"))
255+
.add(RDF.TYPE, FOAF.PERSON)
256+
.add(RDFS.LABEL, Values.literal("Bob", "en"))
257+
.add(FOAF.NAME, Values.literal("Bob"))
258+
.build();
259+
260+
model.setNamespace("rdfs", RDFS.NAMESPACE);
261+
model.setNamespace("foaf", FOAF.NAMESPACE);
262+
model.setNamespace("", "https://example.com/");
263+
264+
JsonDocument context = JsonDocument.of(new StringReader(""
265+
+ "{\n"
266+
+ " \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n"
267+
+ " \"foaf\": \"http://xmlns.com/foaf/0.1/\",\n"
268+
+ " \"@vocab\": \"https://example.com/\",\n"
269+
+ " \"label\": {\n"
270+
+ " \"@id\": \"rdfs:label\",\n"
271+
+ " \"@container\": \"@language\"\n"
272+
+ " },\n"
273+
+ " \"name\": \"foaf:name\",\n"
274+
+ " \"Person\": \"foaf:Person\"\n"
275+
+ "}"));
276+
277+
StringWriter sw = new StringWriter();
278+
279+
JSONLDWriter mpJsonLd = new JSONLDWriter(sw);
280+
mpJsonLd.set(JSONLDSettings.JSONLD_MODE, JSONLDMode.COMPACT);
281+
mpJsonLd.set(BasicWriterSettings.PRETTY_PRINT, true);
282+
mpJsonLd.set(JSONLDSettings.CONTEXT, context);
283+
284+
Rio.write(model, mpJsonLd);
285+
286+
Assertions.assertEquals(
287+
"{\n"
288+
+ " \"@id\": \"https://example.com/bob\",\n"
289+
+ " \"@type\": \"Person\",\n"
290+
+ " \"label\": {\n"
291+
+ " \"en\": \"Bob\"\n"
292+
+ " },\n"
293+
+ " \"name\": \"Bob\",\n"
294+
+ " \"@context\": {\n"
295+
+ " \"rdfs\": \"http://www.w3.org/2000/01/rdf-schema#\",\n"
296+
+ " \"foaf\": \"http://xmlns.com/foaf/0.1/\",\n"
297+
+ " \"@vocab\": \"https://example.com/\",\n"
298+
+ " \"label\": {\n"
299+
+ " \"@id\": \"rdfs:label\",\n"
300+
+ " \"@container\": \"@language\"\n"
301+
+ " },\n"
302+
+ " \"name\": \"foaf:name\",\n"
303+
+ " \"Person\": \"foaf:Person\"\n"
304+
+ " }\n"
305+
+ "}",
306+
sw.toString());
307+
308+
// test round-trip
309+
Model parsed = Rio.parse(new StringReader(sw.toString()), RDFFormat.JSONLD);
310+
Assertions.assertEquals(model, parsed);
311+
}
312+
241313
@Override
242314
protected RioSetting<?>[] getExpectedSupportedSettings() {
243315
return new RioSetting[] {

0 commit comments

Comments
 (0)