Skip to content

Commit

Permalink
Merge pull request #389 from filip26/feat/rdf
Browse files Browse the repository at this point in the history
Feat/rdf
  • Loading branch information
filip26 authored Feb 23, 2025
2 parents feeccc5 + ce4d2ca commit c186d32
Show file tree
Hide file tree
Showing 22 changed files with 457 additions and 294 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,18 @@ JsonLd.flatten("https://example/document.jsonld").get();
// JSON-LD to RDF
JsonLd.toRdf("https://example/document.jsonld").get();
// or, since 1.6.0
JsonLd.toRdf("https://example/document.jsonld").process(RdfConsumer);
JsonLd.toRdf("https://example/document.jsonld").provide(RdfConsumer);

// Standard RDF Dataset Canonicalization with Titanium RDFC, since 1.6.0
var canonicalizer = new RdfCanonicalizer();
JsonLd.toRdf("https://example/document.jsonld").provide(canonicalizer);
canonicalizer.canonize(RdfConsumer);
// or, since 1.7.0
var rdfWriter = Rdf.createWriter(MediaType.N_QUADS, writer);
canonicalizer.canonize(rdfWriter);

// RDF to JSON-LD
JsonLd.fromRdf("https://example/document.nq").options(options).get();
JsonLd.fromRdf("https://example/document.nq").get();

// Framing
JsonLd.frame("https://example/document.jsonld", "https://example/frame.jsonld").get();
Expand Down
26 changes: 19 additions & 7 deletions src/main/java/com/apicatalog/jsonld/api/ToRdfApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@
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.RdfTripleConsumer;
import com.apicatalog.rdf.RdfDataset;
import com.apicatalog.rdf.RdfDatasetProducer;
import com.apicatalog.rdf.RdfDatasetSupplier;
import com.apicatalog.rdf.RdfQuadConsumer;
import com.apicatalog.rdf.RdfQuadEmitter;

import jakarta.json.JsonStructure;

Expand Down Expand Up @@ -164,18 +166,18 @@ public ToRdfApi ordered(boolean enable) {
* @throws JsonLdError
*/
public RdfDataset get() throws JsonLdError {
final RdfDatasetProducer consumer = new RdfDatasetProducer();
process(consumer);
return consumer.dataset();
final RdfDatasetSupplier consumer = new RdfDatasetSupplier();
provide(consumer);
return consumer.get();
}

/**
* Emit transformed <code>JSON-LD</code> as RDF statements.
* Emit transformed <code>JSON-LD</code> as RDF graph scoped triples.
*
* @param consumer that accepts emitted RDF statements
* @throws JsonLdError
*/
public void process(RdfConsumer consumer) throws JsonLdError {
public void provide(RdfTripleConsumer consumer) throws JsonLdError {
if (documentUri != null) {
ToRdfProcessor.toRdf(consumer, documentUri, options);

Expand All @@ -187,6 +189,16 @@ public void process(RdfConsumer consumer) throws JsonLdError {
}
}

/**
* Emit transformed <code>JSON-LD</code> as RDF quads.
*
* @param consumer that accepts emitted RDF statements
* @throws JsonLdError
*/
public void provide(RdfQuadConsumer consumer) throws JsonLdError {
provide(new RdfQuadEmitter(consumer));
}

/**
* Experimental: Accept numeric <code>@id</code>. Disabled by default.
*
Expand Down
141 changes: 49 additions & 92 deletions src/main/java/com/apicatalog/jsonld/deseralization/JsonLdToRdf.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,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.RdfDatasetProducer;
import com.apicatalog.rdf.RdfDatasetSupplier;
import com.apicatalog.rdf.RdfTripleConsumer;
import com.apicatalog.rdf.lang.RdfConstants;
import com.apicatalog.rdf.lang.XsdConstants;

Expand Down Expand Up @@ -83,7 +83,7 @@ private JsonLdToRdf(NodeMap nodeMap, RdfDataset dataset) {

/**
* @deprecated since 1.6.0, use {@link #with(NodeMap)} and
* {@link #process(RdfConsumer)}.
* {@link #provide(RdfTripleConsumer)}.
* @param nodeMap
* @param dataset
* @return
Expand All @@ -107,31 +107,26 @@ public JsonLdToRdf rdfDirection(RdfDirection rdfDirection) {
return this;
}

public void process(RdfConsumer consumer) throws JsonLdError {
public void provide(RdfTripleConsumer consumer) throws JsonLdError {

for (final String graphName : Utils.index(nodeMap.graphs(), true)) {

if (Keywords.DEFAULT.equals(graphName)) {
consumer.defaultGraph();

} else if (BlankNode.isWellFormed(graphName)) {
consumer.namedGraph(graphName, true);
consumer.namedGraph(graphName);

} else if (UriUtils.isAbsoluteUri(graphName, uriValidation)) {
consumer.namedGraph(graphName, false);
consumer.namedGraph(graphName);

} else {
continue;
}

for (final String subject : Utils.index(nodeMap.subjects(graphName), true)) {

boolean blankSubject = false;

if (BlankNode.isWellFormed(subject)) {
blankSubject = true;

} else if (UriUtils.isNotAbsoluteUri(subject, uriValidation)) {
if (!BlankNode.isWellFormed(subject) && UriUtils.isNotAbsoluteUri(subject, uriValidation)) {
LOGGER.log(Level.WARNING, "Non well-formed subject [{0}] has been skipped.", subject);
continue;
}
Expand All @@ -148,43 +143,28 @@ public void process(RdfConsumer consumer) throws JsonLdError {

final String typeString = ((JsonString) type).getString();

boolean blankType = false;

if (BlankNode.isWellFormed(typeString)) {
blankType = true;

} else if (UriUtils.isNotAbsoluteUri(typeString, uriValidation)) {
if (!BlankNode.isWellFormed(typeString) && UriUtils.isNotAbsoluteUri(typeString, uriValidation)) {
continue;
}

consumer.accept(
consumer.triple(
subject,
blankSubject,
RdfConstants.TYPE,
false,
typeString,
blankType);
typeString);
}

} else if (!Keywords.contains(property)) {

boolean blankProperty = false;

if (BlankNode.isWellFormed(property) && !produceGeneralizedRdf) {
blankProperty = true;

} else if (UriUtils.isNotAbsoluteUri(property, uriValidation)) {
if ((!BlankNode.isWellFormed(property) || produceGeneralizedRdf) && UriUtils.isNotAbsoluteUri(property, uriValidation)) {
continue;
}

for (final JsonValue item : nodeMap.get(graphName, subject, property).asJsonArray()) {
processObject(
fromObject(
consumer,
item.asJsonObject(),
subject,
blankSubject,
property,
blankProperty);
property);
}
}
}
Expand All @@ -193,7 +173,7 @@ public void process(RdfConsumer consumer) throws JsonLdError {
}

/**
* @deprecated since 1.6.0, use {@link #process(RdfConsumer)}.
* @deprecated since 1.6.0, use {@link #provide(RdfTripleConsumer)}.
* @return
* @throws JsonLdError
*/
Expand All @@ -204,7 +184,7 @@ public RdfDataset build() throws JsonLdError {
dataset = Rdf.createDataset();
}

process(new RdfDatasetProducer(dataset));
provide(new RdfDatasetSupplier(dataset));

return dataset;
}
Expand All @@ -227,13 +207,11 @@ public JsonLdToRdf uriValidation(UriValidationPolicy uriValidation) {
* "https://w3c.github.io/json-ld-api/#deserialize-json-ld-to-rdf-algorithm">
* Object to RDF Conversion</a>
*/
private void processObject(
final RdfConsumer consumer,
private void fromObject(
final RdfTripleConsumer consumer,
final JsonObject item,
final String subject,
final boolean blankSubject,
final String predicate,
final boolean blankPredicate) throws JsonLdError {
final String predicate) throws JsonLdError {

// 1. - 2.
if (NodeObject.isNodeObject(item)) {
Expand All @@ -246,19 +224,16 @@ private void processObject(

String idString = ((JsonString) id).getString();

if (BlankNode.isWellFormed(idString)) {
consumer.accept(subject, blankSubject, predicate, blankPredicate, idString, true);

} else if (UriUtils.isAbsoluteUri(idString, uriValidation)) {
consumer.accept(subject, blankSubject, predicate, blankPredicate, idString, false);
if (BlankNode.isWellFormed(idString) || UriUtils.isAbsoluteUri(idString, uriValidation)) {
consumer.triple(subject, predicate, idString);
}

return;
}

// 3.
if (ListObject.isListObject(item)) {
processList(consumer, item.get(Keywords.LIST).asJsonArray(), subject, blankSubject, predicate, blankPredicate);
fromList(consumer, item.get(Keywords.LIST).asJsonArray(), subject, predicate);
}

// 4.
Expand Down Expand Up @@ -365,70 +340,56 @@ private void processObject(
: "";
// 13.2.
if (RdfDirection.I18N_DATATYPE == rdfDirection) {
datatype = "https://www.w3.org/ns/i18n#"
.concat(language)
.concat("_")
.concat(item.getString(Keywords.DIRECTION));

consumer.accept(
subject, blankSubject,
predicate, blankPredicate,
valueString, datatype, null);
consumer.triple(
subject,
predicate,
valueString, language, item.getString(Keywords.DIRECTION));

// 13.3.
} else if (RdfDirection.COMPOUND_LITERAL == rdfDirection) {

final String blankNodeId = nodeMap.createIdentifier();

// 13.3.2.
consumer.accept(
consumer.triple(
blankNodeId,
true,
RdfConstants.VALUE,
false,
valueString,
XsdConstants.STRING,
null);
XsdConstants.STRING);

// 13.3.3.
if (item.containsKey(Keywords.LANGUAGE) && JsonUtils.isString(item.get(Keywords.LANGUAGE))) {
consumer.accept(
consumer.triple(
blankNodeId,
true,
RdfConstants.LANGUAGE,
false,
item.getString(Keywords.LANGUAGE).toLowerCase(),
XsdConstants.STRING,
null);
XsdConstants.STRING);
}

// 13.3.4.
consumer.accept(
consumer.triple(
blankNodeId,
true,
RdfConstants.DIRECTION,
false,
item.getString(Keywords.DIRECTION),
XsdConstants.STRING,
null);
XsdConstants.STRING);

consumer.accept(subject, blankSubject, predicate, blankPredicate, blankNodeId, true);
consumer.triple(subject, predicate, blankNodeId);
return;
}

// 14.
} else {
if (item.containsKey(Keywords.LANGUAGE) && JsonUtils.isString(item.get(Keywords.LANGUAGE))) {
consumer.accept(
subject, blankSubject,
predicate, blankPredicate,
valueString, RdfConstants.LANG_STRING, item.getString(Keywords.LANGUAGE));
consumer.triple(
subject,
predicate,
valueString, item.getString(Keywords.LANGUAGE), null);

} else {
consumer.accept(
subject, blankSubject,
predicate, blankPredicate,
valueString, datatype, null);
consumer.triple(
subject,
predicate,
valueString, datatype);
}
}
}
Expand All @@ -437,17 +398,15 @@ private void processObject(
* @see <a href="https://w3c.github.io/json-ld-api/#list-to-rdf-conversion">List
* to RDF Conversion</a>
*/
private void processList(
final RdfConsumer consumer,
private void fromList(
final RdfTripleConsumer consumer,
final JsonArray list,
final String subject,
final boolean blankSubject,
final String predicate,
final boolean blankPredicate) throws JsonLdError {
final String predicate) throws JsonLdError {

// 1.
if (JsonUtils.isEmptyArray(list)) {
consumer.accept(subject, blankSubject, predicate, blankPredicate, RdfConstants.NIL, false);
consumer.triple(subject, predicate, RdfConstants.NIL);
return;
}

Expand All @@ -456,7 +415,7 @@ private void processList(

IntStream.range(0, bnodes.length).forEach(i -> bnodes[i] = nodeMap.createIdentifier());

consumer.accept(subject, blankSubject, predicate, blankPredicate, bnodes[0], true);
consumer.triple(subject, predicate, bnodes[0]);

// 3.
int index = 0;
Expand All @@ -465,20 +424,18 @@ private void processList(
final String blankNodeSubject = bnodes[index];
index++;

processObject(
fromObject(
consumer,
item.asJsonObject(),
blankNodeSubject,
true,
RdfConstants.FIRST,
false);
RdfConstants.FIRST);

// 3.4.
if (index < bnodes.length) {
consumer.accept(blankNodeSubject, true, RdfConstants.REST, false, bnodes[index], true);
consumer.triple(blankNodeSubject, RdfConstants.REST, bnodes[index]);

} else {
consumer.accept(blankNodeSubject, true, RdfConstants.REST, false, RdfConstants.NIL, false);
consumer.triple(blankNodeSubject, RdfConstants.REST, RdfConstants.NIL);
}
}
}
Expand Down
Loading

0 comments on commit c186d32

Please sign in to comment.