diff --git a/README.md b/README.md
index a22157b9..63dfd0bd 100644
--- a/README.md
+++ b/README.md
@@ -87,8 +87,10 @@ JsonLd.compact("https://example/expanded.jsonld", "https://example/context.jsonl
// Flattening
JsonLd.flatten("https://example/document.jsonld").get();
-// JSON-LD to RDF
+// JSON-LD to RDF
JsonLd.toRdf("https://example/document.jsonld").get();
+// or, since 1.6.0
+JsonLd.toRdf("https://example/document.jsonld").process(RdfConsumer);
// RDF to JSON-LD
JsonLd.fromRdf("https://example/document.nq").options(options).get();
diff --git a/pom.xml b/pom.xml
index f1468022..3c2a87da 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
com.apicatalog
titanium
- 1.5.0
+ 1.6.0-SNAPSHOT
pom_parent.xml
titanium-json-ld
diff --git a/pom_jre8.xml b/pom_jre8.xml
index 8e63ab4f..57d07a6e 100644
--- a/pom_jre8.xml
+++ b/pom_jre8.xml
@@ -6,7 +6,7 @@
com.apicatalog
titanium
- 1.5.0
+ 1.6.0-SNAPSHOT
pom_parent.xml
titanium-json-ld-jre8
diff --git a/pom_parent.xml b/pom_parent.xml
index bf0cd88b..ae62de78 100644
--- a/pom_parent.xml
+++ b/pom_parent.xml
@@ -6,7 +6,7 @@
4.0.0
com.apicatalog
titanium
- 1.5.0
+ 1.6.0-SNAPSHOT
pom
Titanium JSON-LD 1.1
diff --git a/src/main/java/com/apicatalog/jsonld/api/ToRdfApi.java b/src/main/java/com/apicatalog/jsonld/api/ToRdfApi.java
index c30a70c8..c2472b52 100644
--- a/src/main/java/com/apicatalog/jsonld/api/ToRdfApi.java
+++ b/src/main/java/com/apicatalog/jsonld/api/ToRdfApi.java
@@ -26,11 +26,13 @@
import com.apicatalog.jsonld.loader.DocumentLoader;
import com.apicatalog.jsonld.processor.ToRdfProcessor;
import com.apicatalog.jsonld.uri.UriUtils;
+import com.apicatalog.rdf.RdfConsumer;
import com.apicatalog.rdf.RdfDataset;
+import com.apicatalog.rdf.RdfDatasetConsumer;
import jakarta.json.JsonStructure;
-public final class ToRdfApi implements CommonApi, LoaderApi, ContextApi{
+public final class ToRdfApi implements CommonApi, LoaderApi, ContextApi {
// required
private final Document document;
@@ -98,7 +100,9 @@ public ToRdfApi context(Document context) {
}
/**
- * If set to true, the JSON-LD processor may emit blank nodes for triple predicates, otherwise they will be omitted.
+ * If set to true, the JSON-LD processor may emit blank nodes for triple
+ * predicates, otherwise they will be omitted.
+ *
* @param enable
* @return builder instance
*/
@@ -117,7 +121,8 @@ public ToRdfApi produceGeneralizedRdf() {
}
/**
- * Determines how value objects containing a base direction are transformed to and from RDF.
+ * Determines how value objects containing a base direction are transformed to
+ * and from RDF.
*
* @param direction
* @return builder instance
@@ -154,23 +159,36 @@ public ToRdfApi ordered(boolean enable) {
/**
* Transform provided JSON-LD
document into {@link RdfDataset}.
*
- * @return {@link RdfDataset} representing provided JSON-LD
document
+ * @return {@link RdfDataset} representing provided JSON-LD
+ * document
* @throws JsonLdError
*/
public RdfDataset get() throws JsonLdError {
+ final RdfDatasetConsumer consumer = new RdfDatasetConsumer();
+ process(consumer);
+ return consumer.dataset();
+ }
+
+ /**
+ * Emit transformed JSON-LD
as RDF statements.
+ *
+ * @param consumer that accepts emitted RDF statements
+ * @throws JsonLdError
+ */
+ public void process(RdfConsumer consumer) throws JsonLdError {
if (documentUri != null) {
- return ToRdfProcessor.toRdf(documentUri, options);
- }
+ ToRdfProcessor.toRdf(consumer, documentUri, options);
- if (document != null) {
- return ToRdfProcessor.toRdf(document, options);
- }
+ } else if (document != null) {
+ ToRdfProcessor.toRdf(consumer, document, options);
- throw new IllegalArgumentException();
+ } else {
+ throw new IllegalArgumentException();
+ }
}
/**
- * Experimental: Accept numeric @id. Disabled by default.
+ * Experimental: Accept numeric @id
. Disabled by default.
*
* @return builder instance
*/
diff --git a/src/main/java/com/apicatalog/jsonld/deseralization/JsonLdToRdf.java b/src/main/java/com/apicatalog/jsonld/deseralization/JsonLdToRdf.java
index 5ba19cde..087632dc 100644
--- a/src/main/java/com/apicatalog/jsonld/deseralization/JsonLdToRdf.java
+++ b/src/main/java/com/apicatalog/jsonld/deseralization/JsonLdToRdf.java
@@ -15,8 +15,6 @@
*/
package com.apicatalog.jsonld.deseralization;
-import java.util.ArrayList;
-import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -31,10 +29,9 @@
import com.apicatalog.jsonld.uri.UriUtils;
import com.apicatalog.jsonld.uri.UriValidationPolicy;
import com.apicatalog.rdf.Rdf;
+import com.apicatalog.rdf.RdfConsumer;
import com.apicatalog.rdf.RdfDataset;
-import com.apicatalog.rdf.RdfResource;
-import com.apicatalog.rdf.RdfTriple;
-import com.apicatalog.rdf.RdfValue;
+import com.apicatalog.rdf.RdfDatasetConsumer;
import com.apicatalog.rdf.lang.RdfConstants;
import jakarta.json.JsonString;
@@ -46,13 +43,15 @@ public final class JsonLdToRdf {
// required
private final NodeMap nodeMap;
- private final RdfDataset dataset;
// optional
private boolean produceGeneralizedRdf;
private RdfDirection rdfDirection;
private UriValidationPolicy uriValidation;
+ // deprecated
+ private RdfDataset dataset;
+
private JsonLdToRdf(NodeMap nodeMap, RdfDataset dataset) {
this.nodeMap = nodeMap;
this.dataset = dataset;
@@ -62,10 +61,15 @@ private JsonLdToRdf(NodeMap nodeMap, RdfDataset dataset) {
this.uriValidation = JsonLdOptions.DEFAULT_URI_VALIDATION;
}
+ @Deprecated
public static final JsonLdToRdf with(NodeMap nodeMap, RdfDataset dataset) {
return new JsonLdToRdf(nodeMap, dataset);
}
+ public static final JsonLdToRdf with(NodeMap nodeMap) {
+ return new JsonLdToRdf(nodeMap, null);
+ }
+
public JsonLdToRdf produceGeneralizedRdf(boolean enable) {
this.produceGeneralizedRdf = enable;
return this;
@@ -76,135 +80,113 @@ public JsonLdToRdf rdfDirection(RdfDirection rdfDirection) {
return this;
}
- public RdfDataset build() throws JsonLdError {
+ public void process(RdfConsumer consumer) throws JsonLdError {
- // 1.
for (final String graphName : Utils.index(nodeMap.graphs(), true)) {
- // 1.2.
- final RdfResource rdfGraphName;
-
if (Keywords.DEFAULT.equals(graphName)) {
- rdfGraphName = null;
-
- } else {
-
- // 1.1.
- if (BlankNode.isWellFormed(graphName)) {
+ consumer.defaultGraph();
- rdfGraphName = Rdf.createBlankNode(graphName);
+ } else if (BlankNode.isWellFormed(graphName)) {
+ consumer.namedGraph(graphName, true);
- } else if (UriUtils.isAbsoluteUri(graphName, uriValidation)) {
+ } else if (UriUtils.isAbsoluteUri(graphName, uriValidation)) {
+ consumer.namedGraph(graphName, false);
- rdfGraphName = Rdf.createIRI(graphName);
-
- } else {
- continue;
- }
+ } else {
+ continue;
}
- // 1.3.
for (final String subject : Utils.index(nodeMap.subjects(graphName), true)) {
- final RdfResource rdfSubject;
+ boolean blankSubject = false;
- // 1.3.1.
if (BlankNode.isWellFormed(subject)) {
- rdfSubject = Rdf.createBlankNode(subject);
-
- } else if (UriUtils.isAbsoluteUri(subject, uriValidation)) {
- rdfSubject = Rdf.createIRI(subject);
+ blankSubject = true;
- } else {
+ } else if (UriUtils.isNotAbsoluteUri(subject, uriValidation)) {
LOGGER.log(Level.WARNING, "Non well-formed subject [{0}] has been skipped.", subject);
continue;
}
- // 1.3.2.
for (final String property : Utils.index(nodeMap.properties(graphName, subject), true)) {
- // 1.3.2.1.
if (Keywords.TYPE.equals(property)) {
- for (JsonValue type : nodeMap.get(graphName, subject, property).asJsonArray()) {
+ for (final JsonValue type : nodeMap.get(graphName, subject, property).asJsonArray()) {
if (JsonUtils.isNotString(type)) {
continue;
}
- final String typeString = ((JsonString)type).getString();
+ final String typeString = ((JsonString) type).getString();
- final RdfValue rdfObject;
+ boolean blankType = false;
if (BlankNode.isWellFormed(typeString)) {
- rdfObject = Rdf.createBlankNode(typeString);
+ blankType = true;
- } else if (UriUtils.isAbsoluteUri(typeString, uriValidation)) {
- rdfObject = Rdf.createIRI(typeString);
-
- } else {
+ } else if (UriUtils.isNotAbsoluteUri(typeString, uriValidation)) {
continue;
}
- dataset.add(Rdf.createNQuad(
- rdfSubject,
- Rdf.createIRI(RdfConstants.TYPE),
- rdfObject,
- rdfGraphName
- ));
+ consumer.accept(
+ subject,
+ blankSubject,
+ RdfConstants.TYPE,
+ false,
+ typeString,
+ blankType);
}
- // 1.3.2.2.
} else if (!Keywords.contains(property)) {
- final RdfResource rdfProperty;
-
- if (BlankNode.isWellFormed(property)) {
- rdfProperty = !produceGeneralizedRdf ? Rdf.createBlankNode(property) : null;
+ boolean blankProperty = false;
- } else if (UriUtils.isAbsoluteUri(property, uriValidation)) {
- rdfProperty = Rdf.createIRI(property);
+ if (BlankNode.isWellFormed(property) && !produceGeneralizedRdf) {
+ blankProperty = true;
- } else {
- rdfProperty = null;
+ } else if (UriUtils.isNotAbsoluteUri(property, uriValidation)) {
+ continue;
}
- if (rdfProperty != null) {
-
- // 1.3.2.5.
- for (JsonValue item : nodeMap.get(graphName, subject, property).asJsonArray()) {
-
- // 1.3.2.5.1.
- final List listTriples = new ArrayList<>();
-
- // 1.3.2.5.2.
- ObjectToRdf
- .with(item.asJsonObject(), listTriples, nodeMap)
- .rdfDirection(rdfDirection)
- .uriValidation(uriValidation)
- .build()
- .ifPresent(rdfObject ->
- dataset.add(Rdf.createNQuad(
- rdfSubject,
- rdfProperty,
- rdfObject,
- rdfGraphName
- )));
- // 1.3.2.5.3.
- listTriples.stream()
- .map(triple -> Rdf.createNQuad(triple, rdfGraphName))
- .forEach(dataset::add);
- }
+ for (final JsonValue item : nodeMap.get(graphName, subject, property).asJsonArray()) {
+
+ ObjectToRdf
+ .with(item.asJsonObject(), consumer, nodeMap)
+ .rdfDirection(rdfDirection)
+ .uriValidation(uriValidation)
+ .produce(
+ subject,
+ blankSubject,
+ property,
+ blankProperty);
}
}
}
}
}
+ }
+
+ /**
+ * @deprecated since 1.6.0, use {@link #process(RdfConsumer)}.
+ * @return
+ * @throws JsonLdError
+ */
+ @Deprecated
+ public RdfDataset build() throws JsonLdError {
+
+ if (dataset == null) {
+ dataset = Rdf.createDataset();
+ }
+
+ process(new RdfDatasetConsumer(dataset));
+
return dataset;
}
/**
- * @deprecated since 1.5.0, use JsonLdToRdf#uriValidation(com.apicatalog.jsonld.uri.UriValidationPolicy)
+ * @deprecated since 1.5.0, use {@link #uriValidation(UriValidationPolicy)}.
*/
@Deprecated
public JsonLdToRdf uriValidation(boolean enabled) {
diff --git a/src/main/java/com/apicatalog/jsonld/deseralization/ListToRdf.java b/src/main/java/com/apicatalog/jsonld/deseralization/ListToRdf.java
index aafe654f..d8e90061 100644
--- a/src/main/java/com/apicatalog/jsonld/deseralization/ListToRdf.java
+++ b/src/main/java/com/apicatalog/jsonld/deseralization/ListToRdf.java
@@ -15,8 +15,6 @@
*/
package com.apicatalog.jsonld.deseralization;
-import java.util.ArrayList;
-import java.util.List;
import java.util.stream.IntStream;
import com.apicatalog.jsonld.JsonLdError;
@@ -25,9 +23,7 @@
import com.apicatalog.jsonld.flattening.NodeMap;
import com.apicatalog.jsonld.json.JsonUtils;
import com.apicatalog.jsonld.uri.UriValidationPolicy;
-import com.apicatalog.rdf.Rdf;
-import com.apicatalog.rdf.RdfTriple;
-import com.apicatalog.rdf.RdfValue;
+import com.apicatalog.rdf.RdfConsumer;
import com.apicatalog.rdf.lang.RdfConstants;
import jakarta.json.JsonArray;
@@ -42,16 +38,16 @@ final class ListToRdf {
// required
private JsonArray list;
- private List triples;
+ private RdfConsumer consumer;
private NodeMap nodeMap;
// optional
private RdfDirection rdfDirection;
private UriValidationPolicy uriValidation;
- private ListToRdf(final JsonArray list, final List triples, NodeMap nodeMap) {
+ private ListToRdf(final JsonArray list, final RdfConsumer consumer, NodeMap nodeMap) {
this.list = list;
- this.triples = triples;
+ this.consumer = consumer;
this.nodeMap = nodeMap;
// default values
@@ -59,8 +55,8 @@ private ListToRdf(final JsonArray list, final List triples, NodeMap n
this.uriValidation = JsonLdOptions.DEFAULT_URI_VALIDATION;
}
- public static final ListToRdf with(final JsonArray list, final List triples, NodeMap nodeMap) {
- return new ListToRdf(list, triples, nodeMap);
+ public static final ListToRdf with(final JsonArray list, final RdfConsumer consumer, NodeMap nodeMap) {
+ return new ListToRdf(list, consumer, nodeMap);
}
public ListToRdf rdfDirection(RdfDirection rdfDirection) {
@@ -68,11 +64,15 @@ public ListToRdf rdfDirection(RdfDirection rdfDirection) {
return this;
}
- public RdfValue build() throws JsonLdError {
+ public void process(
+ String subject, boolean blankSubject,
+ String predicate, boolean blankPredicate
+ ) throws JsonLdError {
// 1.
if (JsonUtils.isEmptyArray(list)) {
- return Rdf.createIRI(RdfConstants.NIL);
+ consumer.accept(subject, blankSubject, predicate, blankPredicate, RdfConstants.NIL, false);
+ return;
}
// 2.
@@ -80,53 +80,29 @@ public RdfValue build() throws JsonLdError {
IntStream.range(0, bnodes.length).forEach(i -> bnodes[i] = nodeMap.createIdentifier());
+ consumer.accept(subject, blankSubject, predicate, blankPredicate, bnodes[0], true);
+
// 3.
int index = 0;
for (final JsonValue item : list) {
- final String subject = bnodes[index];
+ final String blankNodeSubject = bnodes[index];
index++;
- // 3.1.
- final List embeddedTriples = new ArrayList<>();
-
- // 3.2.
ObjectToRdf
- .with(item.asJsonObject(), embeddedTriples, nodeMap)
+ .with(item.asJsonObject(), consumer, nodeMap)
.rdfDirection(rdfDirection)
.uriValidation(uriValidation)
- .build()
- .ifPresent(object ->
- triples.add(Rdf.createTriple(
- Rdf.createBlankNode(subject),
- Rdf.createIRI(RdfConstants.FIRST),
- object)));
-
+ .produce(blankNodeSubject, true, RdfConstants.FIRST, false);
+
// 3.4.
- final RdfValue rest = (index < bnodes.length) ? Rdf.createBlankNode(bnodes[index])
- : Rdf.createIRI(RdfConstants.NIL)
- ;
-
- triples.add(Rdf.createTriple(
- Rdf.createBlankNode(subject),
- Rdf.createIRI(RdfConstants.REST),
- rest
- ));
-
- // 3.5.
- triples.addAll(embeddedTriples);
+ if (index < bnodes.length) {
+ consumer.accept(blankNodeSubject, true, RdfConstants.REST, false, bnodes[index], true);
+
+ } else {
+ consumer.accept(blankNodeSubject, true, RdfConstants.REST, false, RdfConstants.NIL, false);
+ }
}
-
- // 4.
- return Rdf.createBlankNode(bnodes[0]);
- }
-
- /**
- * @deprecated since 1.5.0, use ListToRdf#uriValidation(com.apicatalog.jsonld.uri.UriValidationPolicy)
- */
- @Deprecated
- public ListToRdf uriValidation(boolean enabled) {
- return uriValidation(enabled ? UriValidationPolicy.Full : UriValidationPolicy.SchemeOnly);
}
public ListToRdf uriValidation(UriValidationPolicy uriValidation) {
diff --git a/src/main/java/com/apicatalog/jsonld/deseralization/ObjectToRdf.java b/src/main/java/com/apicatalog/jsonld/deseralization/ObjectToRdf.java
index 22d9c1ed..eb33ceee 100644
--- a/src/main/java/com/apicatalog/jsonld/deseralization/ObjectToRdf.java
+++ b/src/main/java/com/apicatalog/jsonld/deseralization/ObjectToRdf.java
@@ -18,9 +18,7 @@
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
-import java.util.List;
import java.util.Locale;
-import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -38,11 +36,7 @@
import com.apicatalog.jsonld.lang.ValueObject;
import com.apicatalog.jsonld.uri.UriUtils;
import com.apicatalog.jsonld.uri.UriValidationPolicy;
-import com.apicatalog.rdf.Rdf;
-import com.apicatalog.rdf.RdfLiteral;
-import com.apicatalog.rdf.RdfResource;
-import com.apicatalog.rdf.RdfTriple;
-import com.apicatalog.rdf.RdfValue;
+import com.apicatalog.rdf.RdfConsumer;
import com.apicatalog.rdf.lang.RdfConstants;
import com.apicatalog.rdf.lang.XsdConstants;
@@ -70,16 +64,16 @@ final class ObjectToRdf {
// required
private JsonObject item;
- private List triples;
+ private RdfConsumer consumer;
private NodeMap nodeMap;
// optional
private RdfDirection rdfDirection;
private UriValidationPolicy uriValidation;
- private ObjectToRdf(JsonObject item, List triples, NodeMap nodeMap) {
+ private ObjectToRdf(JsonObject item, RdfConsumer consumer, NodeMap nodeMap) {
this.item = item;
- this.triples = triples;
+ this.consumer = consumer;
this.nodeMap = nodeMap;
// default values
@@ -87,8 +81,8 @@ private ObjectToRdf(JsonObject item, List triples, NodeMap nodeMap) {
this.uriValidation = JsonLdOptions.DEFAULT_URI_VALIDATION;
}
- public static final ObjectToRdf with(JsonObject item, List triples, NodeMap nodeMap) {
- return new ObjectToRdf(item, triples, nodeMap);
+ public static final ObjectToRdf with(JsonObject item, RdfConsumer consumer, NodeMap nodeMap) {
+ return new ObjectToRdf(item, consumer, nodeMap);
}
public ObjectToRdf rdfDirection(RdfDirection rdfDirection) {
@@ -96,7 +90,11 @@ public ObjectToRdf rdfDirection(RdfDirection rdfDirection) {
return this;
}
- public Optional build() throws JsonLdError {
+ public void produce(
+ final String subject,
+ final boolean blankSubject,
+ final String predicate,
+ final boolean blankPredicate) throws JsonLdError {
// 1. - 2.
if (NodeObject.isNodeObject(item)) {
@@ -104,33 +102,33 @@ public Optional build() throws JsonLdError {
JsonValue id = item.get(Keywords.ID);
if (JsonUtils.isNotString(id) || JsonUtils.isNull(id)) {
- return Optional.empty();
+ return;
}
String idString = ((JsonString) id).getString();
if (BlankNode.isWellFormed(idString)) {
- return Optional.of(Rdf.createBlankNode(idString));
+ consumer.accept(subject, blankSubject, predicate, blankPredicate, idString, true);
} else if (UriUtils.isAbsoluteUri(idString, uriValidation)) {
- return Optional.of(Rdf.createIRI(idString));
+ consumer.accept(subject, blankSubject, predicate, blankPredicate, idString, false);
}
- return Optional.empty();
+ return;
}
// 3.
if (ListObject.isListObject(item)) {
- return Optional.of(ListToRdf
- .with(item.get(Keywords.LIST).asJsonArray(), triples, nodeMap)
+ ListToRdf
+ .with(item.get(Keywords.LIST).asJsonArray(), consumer, nodeMap)
.rdfDirection(rdfDirection)
.uriValidation(uriValidation)
- .build());
+ .process(subject, blankSubject, predicate, blankPredicate);
}
// 4.
if (!ValueObject.isValueObject(item)) {
- return Optional.empty();
+ return;
}
final JsonValue value = item.get(Keywords.VALUE);
@@ -143,7 +141,7 @@ public Optional build() throws JsonLdError {
// 6.
if (datatype != null && !Keywords.JSON.equals(datatype) && !UriUtils.isAbsoluteUri(datatype, uriValidation)) {
LOGGER.log(Level.WARNING, "Datatype [{0}] is not an absolute IRI nor @json and value is skipped.", datatype);
- return Optional.empty();
+ return;
}
// 7.
@@ -151,7 +149,7 @@ public Optional build() throws JsonLdError {
&& (JsonUtils.isNotString(item.get(Keywords.LANGUAGE))
|| !LanguageTag.isWellFormed(item.getString(Keywords.LANGUAGE)))) {
LOGGER.log(Level.WARNING, "Language tag [{0}] is not well formed string and value is skipped.", item.get(Keywords.LANGUAGE));
- return Optional.empty();
+ return;
}
String valueString = null;
@@ -217,14 +215,12 @@ public Optional build() throws JsonLdError {
if (valueString == null) {
if (JsonUtils.isNotString(value)) {
- return Optional.empty();
+ return;
}
valueString = ((JsonString) value).getString();
}
- RdfLiteral rdfLiteral = null;
-
// 13.
if (item.containsKey(Keywords.DIRECTION) && rdfDirection != null) {
@@ -239,67 +235,73 @@ public Optional build() throws JsonLdError {
.concat("_")
.concat(item.getString(Keywords.DIRECTION));
- rdfLiteral = Rdf.createTypedString(valueString, datatype);
+ consumer.accept(
+ subject, blankSubject,
+ predicate, blankPredicate,
+ valueString, datatype, null);
// 13.3.
} else if (RdfDirection.COMPOUND_LITERAL == rdfDirection) {
final String blankNodeId = nodeMap.createIdentifier();
- // 13.3.1.
- final RdfResource subject = Rdf.createBlankNode(blankNodeId);
-
// 13.3.2.
- triples.add(Rdf.createTriple(
- subject,
- Rdf.createIRI(RdfConstants.VALUE),
- Rdf.createString(valueString)));
+ consumer.accept(
+ blankNodeId,
+ true,
+ RdfConstants.VALUE,
+ false,
+ valueString,
+ XsdConstants.STRING,
+ null);
// 13.3.3.
if (item.containsKey(Keywords.LANGUAGE) && JsonUtils.isString(item.get(Keywords.LANGUAGE))) {
- triples.add(Rdf.createTriple(
- subject,
- Rdf.createIRI(RdfConstants.LANGUAGE),
- Rdf.createString(item.getString(Keywords.LANGUAGE).toLowerCase())));
+ consumer.accept(
+ blankNodeId,
+ true,
+ RdfConstants.LANGUAGE,
+ false,
+ item.getString(Keywords.LANGUAGE).toLowerCase(),
+ XsdConstants.STRING,
+ null);
}
// 13.3.4.
- triples.add(Rdf.createTriple(
- subject,
- Rdf.createIRI(RdfConstants.DIRECTION),
- Rdf.createString(item.getString(Keywords.DIRECTION))));
-
- return Optional.of(Rdf.createBlankNode(blankNodeId));
+ consumer.accept(
+ blankNodeId,
+ true,
+ RdfConstants.DIRECTION,
+ false,
+ item.getString(Keywords.DIRECTION),
+ XsdConstants.STRING,
+ null);
+
+ consumer.accept(subject, blankSubject, predicate, blankPredicate, blankNodeId, true);
+ return;
}
// 14.
} else {
if (item.containsKey(Keywords.LANGUAGE) && JsonUtils.isString(item.get(Keywords.LANGUAGE))) {
-
- rdfLiteral = Rdf.createLangString(valueString, item.getString(Keywords.LANGUAGE));
+ consumer.accept(
+ subject, blankSubject,
+ predicate, blankPredicate,
+ valueString, RdfConstants.LANG_STRING, item.getString(Keywords.LANGUAGE));
} else {
- rdfLiteral = Rdf.createTypedString(valueString, datatype);
+ consumer.accept(
+ subject, blankSubject,
+ predicate, blankPredicate,
+ valueString, datatype, null);
}
}
-
- // 15.
- return Optional.ofNullable(rdfLiteral);
}
private static final String toXsdDouble(BigDecimal bigDecimal) {
return xsdNumberFormat.format(bigDecimal);
}
- /**
- * @deprecated since 1.5.0, use
- * Object#uriValidation(com.apicatalog.jsonld.uri.UriValidationPolicy)
- */
- @Deprecated
- public ObjectToRdf uriValidation(boolean enabled) {
- return uriValidation(enabled ? UriValidationPolicy.Full : UriValidationPolicy.SchemeOnly);
- }
-
public ObjectToRdf uriValidation(UriValidationPolicy uriValidation) {
this.uriValidation = uriValidation;
return this;
diff --git a/src/main/java/com/apicatalog/jsonld/processor/ToRdfProcessor.java b/src/main/java/com/apicatalog/jsonld/processor/ToRdfProcessor.java
index 863b9d8a..855dccca 100644
--- a/src/main/java/com/apicatalog/jsonld/processor/ToRdfProcessor.java
+++ b/src/main/java/com/apicatalog/jsonld/processor/ToRdfProcessor.java
@@ -25,14 +25,16 @@
import com.apicatalog.jsonld.flattening.NodeMap;
import com.apicatalog.jsonld.flattening.NodeMapBuilder;
import com.apicatalog.jsonld.loader.DocumentLoaderOptions;
-import com.apicatalog.rdf.Rdf;
+import com.apicatalog.rdf.RdfConsumer;
import com.apicatalog.rdf.RdfDataset;
+import com.apicatalog.rdf.RdfDatasetConsumer;
import jakarta.json.JsonArray;
/**
*
- * @see JsonLdProcessor.toRdf()
+ * @see JsonLdProcessor.toRdf()
*
*/
public final class ToRdfProcessor {
@@ -40,8 +42,16 @@ public final class ToRdfProcessor {
private ToRdfProcessor() {
}
+ @Deprecated
public static final RdfDataset toRdf(final URI input, final JsonLdOptions options) throws JsonLdError {
+ final RdfDatasetConsumer consumer = new RdfDatasetConsumer();
+ toRdf(consumer, input, options);
+ return consumer.dataset();
+
+ }
+
+ public static final void toRdf(final RdfConsumer consumer, final URI input, final JsonLdOptions options) throws JsonLdError {
if (options.getDocumentLoader() == null) {
throw new JsonLdError(JsonLdErrorCode.LOADING_DOCUMENT_FAILED, "Document loader is null. Cannot fetch [" + input + "].");
}
@@ -55,11 +65,17 @@ public static final RdfDataset toRdf(final URI input, final JsonLdOptions option
throw new JsonLdError(JsonLdErrorCode.LOADING_DOCUMENT_FAILED);
}
- return toRdf(remoteDocument, options);
+ toRdf(consumer, remoteDocument, options);
}
+ @Deprecated
public static final RdfDataset toRdf(Document input, final JsonLdOptions options) throws JsonLdError {
+ final RdfDatasetConsumer consumer = new RdfDatasetConsumer();
+ toRdf(consumer, input, options);
+ return consumer.dataset();
+ }
+ public static final void toRdf(RdfConsumer consumer, Document input, final JsonLdOptions options) throws JsonLdError {
final JsonLdOptions expansionOptions = new JsonLdOptions(options);
expansionOptions.setProcessingMode(options.getProcessingMode());
@@ -68,14 +84,11 @@ public static final RdfDataset toRdf(Document input, final JsonLdOptions options
final JsonArray expandedInput = ExpansionProcessor.expand(input, expansionOptions, false);
- return JsonLdToRdf
- .with(
- NodeMapBuilder.with(expandedInput, new NodeMap()).build(),
- Rdf.createDataset()
- )
- .produceGeneralizedRdf(options.isProduceGeneralizedRdf())
- .rdfDirection(options.getRdfDirection())
- .uriValidation(options.getUriValidation())
- .build();
+ JsonLdToRdf
+ .with(NodeMapBuilder.with(expandedInput, new NodeMap()).build())
+ .produceGeneralizedRdf(options.isProduceGeneralizedRdf())
+ .rdfDirection(options.getRdfDirection())
+ .uriValidation(options.getUriValidation())
+ .process(consumer);
}
}
diff --git a/src/main/java/com/apicatalog/rdf/RdfConsumer.java b/src/main/java/com/apicatalog/rdf/RdfConsumer.java
new file mode 100644
index 00000000..264ef806
--- /dev/null
+++ b/src/main/java/com/apicatalog/rdf/RdfConsumer.java
@@ -0,0 +1,70 @@
+package com.apicatalog.rdf;
+
+/**
+ * RDF dataset consumer interface designed for
+ * speed, streamlined processing, and efficiency.
+ *
+ * This interface minimizes unnecessary object instantiation
+ * and facilitates seamless integration with third-party libraries,
+ * enabling efficient RDF data processing.
+ */
+public interface RdfConsumer {
+
+ /**
+ * Sets the default graph as the active scope.
+ * Invoked when triples belong to the unnamed, default graph.
+ */
+ void defaultGraph();
+
+ /**
+ * Sets a named graph as the active scope.
+ * Ensures that subsequent triples are associated with the specified graph.
+ *
+ * @param graph The name of the graph (IRI or blank node identifier).
+ * @param blankGraph {@code true} if the graph name is a blank node identifier.
+ */
+ void namedGraph(String graph, boolean blankGraph);
+
+ /**
+ * Accepts a new RDF triple where the object is an IRI or a blank node.
+ * The triple is processed within the currently active graph scope.
+ *
+ * @param subject The subject of the triple (IRI or blank node identifier).
+ * @param blankSubject {@code true} if the subject is a blank node identifier.
+ * @param predicate The predicate of the triple (IRI or blank node identifier).
+ * @param blankPredicate {@code true} if the predicate is a blank node identifier.
+ * @param object The object of the triple (IRI or blank node identifier).
+ * @param blankObject {@code true} if the object is a blank node identifier.
+ */
+ void accept(
+ String subject,
+ boolean blankSubject,
+ String predicate,
+ boolean blankPredicate,
+ String object,
+ boolean blankObject
+ );
+
+ /**
+ * Accepts a new RDF triple where the object is a literal value.
+ * The triple is processed within the currently active graph scope.
+ * Optimized for efficient handling of typed and language-tagged literals.
+ *
+ * @param subject The subject of the triple (IRI or blank node identifier).
+ * @param blankSubject {@code true} if the subject is a blank node identifier.
+ * @param predicate The predicate of the triple (IRI or blank node identifier).
+ * @param blankPredicate {@code true} if the predicate is a blank node identifier.
+ * @param literal The literal value of the object.
+ * @param datatype The datatype IRI of the literal, never {@code null}.
+ * @param language The language tag of the literal (optional, may be {@code null}).
+ */
+ void accept(
+ String subject,
+ boolean blankSubject,
+ String predicate,
+ boolean blankPredicate,
+ String literal,
+ String datatype,
+ String language
+ );
+}
diff --git a/src/main/java/com/apicatalog/rdf/RdfDatasetConsumer.java b/src/main/java/com/apicatalog/rdf/RdfDatasetConsumer.java
new file mode 100644
index 00000000..81d72004
--- /dev/null
+++ b/src/main/java/com/apicatalog/rdf/RdfDatasetConsumer.java
@@ -0,0 +1,57 @@
+package com.apicatalog.rdf;
+
+public class RdfDatasetConsumer implements RdfConsumer {
+
+ protected final RdfDataset dataset;
+
+ protected RdfResource graphName;
+
+ public RdfDatasetConsumer() {
+ this(Rdf.createDataset());
+ }
+
+ public RdfDatasetConsumer(RdfDataset dataset) {
+ this.dataset = dataset;
+ this.graphName = null;
+ }
+
+ public RdfDataset dataset() {
+ return dataset;
+ }
+
+ protected static final RdfResource createResource(String name, boolean blank) {
+ return blank ? Rdf.createBlankNode(name) : Rdf.createIRI(name);
+ }
+
+ @Override
+ public void namedGraph(String graph, boolean blankGraph) {
+ this.graphName = createResource(graph, blankGraph);
+ }
+
+ @Override
+ public void defaultGraph() {
+ this.graphName = null;
+ }
+
+ @Override
+ public void accept(String subject, boolean blankSubject, String predicate, boolean blankPredicate, String literal, String datatype, String language) {
+ dataset.add(
+ Rdf.createNQuad(
+ createResource(subject, blankSubject),
+ createResource(predicate, blankPredicate),
+ language != null
+ ? Rdf.createLangString(literal, language)
+ : Rdf.createTypedString(literal, datatype),
+ graphName));
+ }
+
+ @Override
+ public void accept(String subject, boolean blankSubject, String predicate, boolean blankPredicate, String object, boolean blankObject) {
+ dataset.add(
+ Rdf.createNQuad(
+ createResource(subject, blankSubject),
+ createResource(predicate, blankPredicate),
+ createResource(object, blankObject),
+ graphName));
+ }
+}