Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .scala-steward.conf

This file was deleted.

4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,9 @@ steps:

## RDF-star/RDF 1.2 compatibility

`jelly-cli` is based on [Apache Jena](https://jena.apache.org/) 5.3.0, which is the last version of Jena that supports RDF-star. Later versions removed RDF-star support in favor of draft support for RDF 1.2, which is not directly compatible with RDF-star. Because RDF 1.2 is not yet a W3C Recommendation, we stick to RDF-star for now and will update to RDF 1.2 once it is finalized.
`jelly-cli` includes partial support for RDF 1.2 (triple terms only).

**[v0.10.0](https://github.com/Jelly-RDF/cli/releases/tag/v0.10.0) is the last release that supported RDF-star.** It is based on Jena 5.3.0, the last version of Jena to support RDF-star.

## Contributing

Expand Down
5 changes: 2 additions & 3 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ ThisBuild / scalaVersion := scalaV
resolvers +=
"Sonatype OSS Snapshots" at "https://s01.oss.sonatype.org/content/repositories/snapshots"

lazy val jenaV = "5.3.0"
lazy val jenaV = "6.2.0"
lazy val jellyV = "3.7.3"
lazy val graalvmV = "25.2.4"

Expand Down Expand Up @@ -60,8 +60,7 @@ lazy val root = (project in file("."))
"org.slf4j" % "slf4j-simple" % "2.0.18",
"org.apache.jena" % "jena-core" % jenaV,
"org.apache.jena" % "jena-arq" % jenaV,
// Jelly-JVM >= 3.4.1 includes Jena 5.5.x as a dependency, we must exclude it, because
// we use Jena 5.3.0.
// Jelly-JVM 3.7.x pins Jena 5.6.x as a dependency, we must exclude it, because we use Jena 6.x.
("eu.neverblink.jelly" % "jelly-jena" % jellyV).excludeAll(ExclusionRule("org.apache.jena")),
"eu.neverblink.jelly" % "jelly-core-protos-google" % jellyV,
"com.github.alexarchambault" %% "case-app" % "2.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,20 @@ object RdfValidate extends JellyCommand[RdfValidateOptions]:
val t = Triple.create(subject, predicate, `object`)
if !opt.getGeneralizedStatements && StatementUtils.isGeneralized(t) then
throw CriticalException(s"Unexpected generalized triple in frame $currentPosition: $t")
if !opt.getRdfStar && StatementUtils.isRdfStar(t) then
throw CriticalException(s"Unexpected RDF-star triple in frame $currentPosition: $t")
if !opt.getRdfStar && StatementUtils.hasTripleTerms(t) then
throw CriticalException(
s"Unexpected triple term in triple in frame $currentPosition: $t",
)
// Add the triple to the comparison set, if we are in the compare range
if currentPosition >= startFrom then jellyStreamConsumer.triple(t)
}

override def handleQuad(subject: Node, predicate: Node, `object`: Node, graph: Node): Unit = {
val q = new Quad(graph, subject, predicate, `object`)
val q = Quad.create(graph, subject, predicate, `object`)
if !opt.getGeneralizedStatements && StatementUtils.isGeneralized(q) then
throw CriticalException(s"Unexpected generalized quad in frame $currentPosition: $q")
if !opt.getRdfStar && StatementUtils.isRdfStar(q) then
throw CriticalException(s"Unexpected RDF-star quad in frame $currentPosition: $q")
if !opt.getRdfStar && StatementUtils.hasTripleTerms(q) then
throw CriticalException(s"Unexpected triple term in quad in frame $currentPosition: $q")
// Add the quad to the comparison set, if we are in the compare range
if currentPosition >= startFrom then jellyStreamConsumer.quad(q)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ class MetricsPrinter(val formatter: Formatter):
"stream_name" -> YamlString(options.getStreamName),
"physical_type" -> YamlEnum(options.getPhysicalType.toString, options.getPhysicalTypeValue),
"generalized_statements" -> YamlBool(options.getGeneralizedStatements),
"rdf_star" -> YamlBool(options.getRdfStar),
"triple_terms" -> YamlBool(options.getRdfStar),
"max_name_table_size" -> YamlInt(options.getMaxNameTableSize),
"max_prefix_table_size" -> YamlInt(options.getMaxPrefixTableSize),
"max_datatype_table_size" -> YamlInt(options.getMaxDatatypeTableSize),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import eu.neverblink.jelly.core.utils.LogicalStreamTypeUtils
import eu.neverblink.jelly.core.JellyOptions

private val `default.opt.streamName`: String = ""
private val `default.opt.rdfStar`: Boolean = true
private val `default.opt.tripleTerms`: Boolean = true
private val `default.opt.maxNameTableSize`: Int = JellyOptions.BIG_STRICT.getMaxNameTableSize
private val `default.opt.maxPrefixTableSize`: Int = JellyOptions.BIG_STRICT.getMaxPrefixTableSize
private val `default.opt.maxDatatypeTableSize`: Int =
Expand All @@ -22,9 +22,10 @@ case class RdfJellySerializationOptions(
)
`opt.generalizedStatements`: Option[Boolean] = None,
@HelpMessage(
"Whether the stream may contain RDF-star statements. Default: " + `default.opt.rdfStar`,
"Whether the stream may contain RDF 1.2 triple terms. Default: " +
`default.opt.tripleTerms`,
)
`opt.rdfStar`: Option[Boolean] = None,
`opt.tripleTerms`: Option[Boolean] = None,
@HelpMessage(
"Maximum size of the name lookup table. Default: " + `default.opt.maxNameTableSize`,
)
Expand Down Expand Up @@ -105,7 +106,7 @@ case class RdfJellySerializationOptions(
RdfStreamOptions.newInstance()
.setStreamName(`opt.streamName`.getOrElse(`default.opt.streamName`))
.setGeneralizedStatements(`opt.generalizedStatements`.getOrElse(inferred.generalized))
.setRdfStar(`opt.rdfStar`.getOrElse(`default.opt.rdfStar`))
.setRdfStar(`opt.tripleTerms`.getOrElse(`default.opt.tripleTerms`))
.setMaxNameTableSize(`opt.maxNameTableSize`.getOrElse(`default.opt.maxNameTableSize`))
.setMaxPrefixTableSize(`opt.maxPrefixTableSize`.getOrElse(`default.opt.maxPrefixTableSize`))
.setMaxDatatypeTableSize(
Expand All @@ -121,8 +122,8 @@ case class RdfJellySerializationOptions(
cloned.setGeneralizedStatements(`opt.generalizedStatements`.get)
if `opt.streamName`.isDefined then // comment to stop scalafmt from making this a mess
cloned.setStreamName(`opt.streamName`.get)
if `opt.rdfStar`.isDefined then // comment to stop scalafmt from making this a mess
cloned.setRdfStar(`opt.rdfStar`.get)
if `opt.tripleTerms`.isDefined then // comment to stop scalafmt from making this a mess
cloned.setRdfStar(`opt.tripleTerms`.get)
if `opt.maxNameTableSize`.isDefined then
cloned.setMaxNameTableSize(`opt.maxNameTableSize`.get)
if `opt.maxPrefixTableSize`.isDefined then
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ object OrderedRdfCompare extends RdfCompare:
s"expected $e, got $a. $eId is already mapped to ${bNodeMap(eId)}.",
)
else bNodeMap(eId) = aId
else if et.isNodeTriple && at.isNodeTriple then
// Recurse into the RDF-star quoted triple
else if et.isTripleTerm && at.isTripleTerm then
// Recurse into the RDF 1.2 triple term
tryIsomorphism(
iterateTerms(et.getTriple),
iterateTerms(at.getTriple),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ object StatementUtils:
q.getSubject :: q.getPredicate :: q.getObject :: q.getGraph :: Nil

def isGeneralized(t: Triple): Boolean =
(!t.getSubject.isBlank && !t.getSubject.isURI && !t.getSubject.isNodeTriple)
(!t.getSubject.isBlank && !t.getSubject.isURI && !t.getSubject.isTripleTerm)
|| !t.getPredicate.isURI

def isGeneralized(q: Quad): Boolean =
(!q.getSubject.isBlank && !q.getSubject.isURI && !q.getSubject.isNodeTriple)
(!q.getSubject.isBlank && !q.getSubject.isURI && !q.getSubject.isTripleTerm)
|| !q.getPredicate.isURI
|| (!q.getGraph.isBlank && !q.getGraph.isURI)

def isRdfStar(t: Triple): Boolean = iterateTerms(t).exists(_.isNodeTriple)
def hasTripleTerms(t: Triple): Boolean = iterateTerms(t).exists(_.isTripleTerm)

def isRdfStar(q: Quad): Boolean = iterateTerms(q).exists(_.isNodeTriple)
def hasTripleTerms(q: Quad): Boolean = iterateTerms(q).exists(_.isTripleTerm)
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class StreamRdfBatchWriter(val outputStream: OutputStream, val lang: Lang) exten
override def triple(triple: Triple): Unit = datasetStream.triple(triple)
override def prefix(prefix: String, iri: String): Unit = datasetStream.prefix(prefix, iri)
override def base(base: String): Unit = datasetStream.base(base)
override def version(version: String): Unit = datasetStream.version(version)
override def finish(): Unit = writeOutput()
override def start(): Unit = ()
def writeOutput(): Unit =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ final class StreamRdfCollector extends StreamRDF:

override def base(base: String): Unit = ()

override def version(version: String): Unit = ()

override def prefix(prefix: String, iri: String): Unit =
buffer += NamespaceDeclaration(prefix, iri)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ final class JellyStreamWriterGraphs(opt: JellyFormatVariant, out: OutputStream)
// Not supported
override def base(base: String): Unit = ()

// Not supported – Jelly has no equivalent of the RDF 1.2 version directive
override def version(version: String): Unit = ()

override def prefix(prefix: String, iri: String): Unit =
if opt.isEnableNamespaceDeclarations then
encoder.handleNamespace(prefix, NodeFactory.createURI(iri))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,17 @@ final class LangNQuadsGeneralized(tokens: Tokenizer, profile: ParserProfile, des

override protected def parseOne: Quad =
val sToken = nextToken
val s = parseNode(sToken)
val p = parseNode(nextToken)
val o = parseNode(nextToken)
val s = parseNode("subject", sToken)
val p = parseNode("predicate", nextToken)
val o = parseNode("object", nextToken)
var xToken = nextToken // Maybe DOT
if (xToken.getType eq TokenType.EOF)
exception(xToken, "Premature end of file: Quad not terminated by DOT: %s", xToken)
// Process graph node first, before S,P,O
// to set bnode label scope (if not global)
var c: Node = null
if (xToken.getType ne TokenType.DOT) {
c = parseNode(xToken)
c = parseNode("graph", xToken)
xToken = nextToken
currentGraph = c
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ import org.apache.jena.riot.tokens.{Token, TokenType, Tokenizer}
abstract class LangNTupleGeneralized[T](tokens: Tokenizer, profile: ParserProfile, dest: StreamRDF)
extends LangNTuple[T](tokens, profile, dest):

protected final def parseNode(token: Token): Node =
protected final def parseNode(posn: String, token: Token): Node =
if (token.isEOF) exception(token, "Premature end of file: %s", token)
if (token.hasType(TokenType.LT2)) parseTripleTermGeneralized
if (token.hasType(TokenType.L_TRIPLE)) parseTripleTermGeneralized
else
checkRDFTerm(token)
checkRDFTerm(posn, token)
tokenAsNode(token)

protected final def parseTripleGeneralized: Triple =
val sToken = nextToken
val s = parseNode(sToken)
val p = parseNode(nextToken)
val o = parseNode(nextToken)
val s = parseNode("subject", sToken)
val p = parseNode("predicate", nextToken)
val o = parseNode("object", nextToken)
profile.createTriple(s, p, o, sToken.getLine, sToken.getColumn)

protected final def parseTripleTermGeneralized: Node =
val t = parseTripleGeneralized
val x = nextToken
if (x.getType ne TokenType.GT2) exception(x, "Triple term not terminated by >>: %s", x)
NodeFactory.createTripleNode(t)
if (x.getType ne TokenType.R_TRIPLE) exception(x, "Triple term not terminated by )>>: %s", x)
NodeFactory.createTripleTerm(t)
4 changes: 2 additions & 2 deletions src/test/resources/generalized.nq
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<http://example.org/resource/r1> _:b1 <http://example.org/resource/r2> .
"Resource 1" <http://example.org/property/p> <http://example.org/resource/r3> .
<http://example.org/resource/r3> "Property Label" <http://example.org/resource/r1> .
_:b1 << _:b1 _:b2 _:b3 >> <http://example.org/resource/r4> .
_:b1 <<( _:b1 _:b2 _:b3 )>> <http://example.org/resource/r4> .
<http://example.org/resource/r1> _:b1 <http://example.org/resource/r2> _:b1 .
"Resource 1" <http://example.org/property/p> <http://example.org/resource/r3> "literal graph"^^<http://example.org> .
<http://example.org/resource/r3> "Property Label" <http://example.org/resource/r1> <http://example.org> .
_:b1 << _:b1 _:b2 _:b3 >> <http://example.org/resource/r4> "literal"@en .
_:b1 <<( _:b1 _:b2 _:b3 )>> <http://example.org/resource/r4> "literal"@en .
2 changes: 1 addition & 1 deletion src/test/resources/generalized.nt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<http://example.org/resource/r1> _:b1 <http://example.org/resource/r2> .
"Resource 1" <http://example.org/property/p> <http://example.org/resource/r3> .
<http://example.org/resource/r3> "Property Label" <http://example.org/resource/r1> .
_:b1 << _:b1 _:b2 _:b3 >> <http://example.org/resource/r4> .
_:b1 <<( _:b1 _:b2 _:b3 )>> <http://example.org/resource/r4> .
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ class RdfToJellySpec extends AnyWordSpec with TestFixtureHelper with Matchers:
f,
"--opt.stream-name=testName",
"--opt.generalized-statements=false",
"--opt.rdf-star=false",
"--opt.triple-terms=false",
"--opt.max-name-table-size=100",
"--opt.max-prefix-table-size=100",
"--opt.max-datatype-table-size=100",
Expand Down Expand Up @@ -494,7 +494,7 @@ class RdfToJellySpec extends AnyWordSpec with TestFixtureHelper with Matchers:
"--options-from",
optionsFile,
jenaFile,
"--opt.rdf-star",
"--opt.triple-terms",
"false",
),
)
Expand Down
Loading
Loading