diff --git a/src/main/scala/eu/neverblink/jelly/cli/util/jena/riot/RiotParserUtil.scala b/src/main/scala/eu/neverblink/jelly/cli/util/jena/riot/RiotParserUtil.scala index 99d43e2..1c757c1 100644 --- a/src/main/scala/eu/neverblink/jelly/cli/util/jena/riot/RiotParserUtil.scala +++ b/src/main/scala/eu/neverblink/jelly/cli/util/jena/riot/RiotParserUtil.scala @@ -1,6 +1,7 @@ package eu.neverblink.jelly.cli.util.jena.riot import eu.neverblink.jelly.cli.command.rdf.util.RdfFormat +import org.apache.jena.irix.IRIs import org.apache.jena.riot.lang.LabelToNode import org.apache.jena.riot.{RDFParser, RDFParserRegistry, RIOT} import org.apache.jena.riot.system.StreamRDF @@ -18,9 +19,14 @@ object RiotParserUtil: ): Unit = { // Only really enable IRI resolution if the format supports it if resolveIris && format.supportsBaseIri then - // Parser with full IRI resolution + // Parser with full IRI resolution. + // We set the base explicitly to the system base (the current working directory), which is + // what Jena uses by default for stream-based Turtle/TriG parsing. Without this, readers that + // do their own base handling (notably RDF/XML via ARP) receive a null base and fail to + // resolve relative IRIs (e.g. "#foo"), throwing "Relative URI encountered". RDFParser.source(source) .lang(format.jenaLang) + .base(IRIs.getBaseStr) .labelToNode(LabelToNode.createUseLabelAsGiven()) .checking(false) .strict(false) diff --git a/src/test/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJellySpec.scala b/src/test/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJellySpec.scala index c9aace6..9ab1d72 100644 --- a/src/test/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJellySpec.scala +++ b/src/test/scala/eu/neverblink/jelly/cli/command/rdf/RdfToJellySpec.scala @@ -8,6 +8,7 @@ import eu.neverblink.jelly.core.proto.v1.{LogicalStreamType, PhysicalStreamType, import eu.neverblink.jelly.core.JellyOptions import eu.neverblink.jelly.core.proto.google.v1 as google import eu.neverblink.jelly.core.utils.IoUtils +import org.apache.jena.irix.IRIs import org.apache.jena.rdf.model.{Model, ModelFactory} import org.apache.jena.riot.{RDFLanguages, RDFParser} import org.apache.jena.sparql.core.DatasetGraphFactory @@ -934,5 +935,26 @@ class RdfToJellySpec extends AnyWordSpec with TestFixtureHelper with Matchers: stmts.head.getPredicate.getURI should be("http://example.org/p") stmts.head.getObject.asResource().getURI should be("b") } + + "IRI resolution enabled (default), input RDF/XML stream with relative IRIs" in + withEmptyJellyFile { j => + val input = + """ + | + | + | <__g0:test.org xmlns:__g0="http://">test + | + |""".stripMargin + RdfToJelly.setStdIn(ByteArrayInputStream(input.getBytes)) + RdfToJelly.runTestCommand( + List("rdf", "to-jelly", "--in-format", RdfFormat.RdfXml.cliOptions.head, "--to", j), + ) + val content = translateJellyBack(new FileInputStream(j)) + val stmts = content.listStatements().asScala.toSeq + stmts.size should be(1) + stmts.head.getSubject.getURI should be(s"${IRIs.getBaseStr}#relative") + stmts.head.getPredicate.getURI should be("http://test.org") + stmts.head.getObject.asLiteral().getString should be("test") + } } }