diff --git a/silk-core/src/main/scala/org/silkframework/entity/rdf/SparqlRestriction.scala b/silk-core/src/main/scala/org/silkframework/entity/rdf/SparqlRestriction.scala index 6b877093ae..cb99367940 100644 --- a/silk-core/src/main/scala/org/silkframework/entity/rdf/SparqlRestriction.scala +++ b/silk-core/src/main/scala/org/silkframework/entity/rdf/SparqlRestriction.scala @@ -15,8 +15,11 @@ package org.silkframework.entity.rdf import org.silkframework.config.Prefixes +import org.silkframework.runtime.validation.BadUserInputException import org.silkframework.util.Uri +import scala.util.matching.Regex + /** * Represents a SPARQL restriction. */ @@ -55,17 +58,29 @@ object SparqlRestriction { val strippedRestrictions = restrictions.trim.stripSuffix(".").trim val cleanedRestrictions = if (strippedRestrictions.isEmpty) "" else strippedRestrictions + " ." - var restrictionsFull = cleanedRestrictions + val prefixRegex = """(?"';]+)(?![^<]*>)(?![^"']*["'](?:[^"']*["'][^"']*["'])*[^"']*$)""".r + + // Replace all prefixes with their full URIs + val restrictionsFull = prefixRegex.replaceAllIn(cleanedRestrictions, replacePrefix _) + + // Replace full URIs with their prefixed names var restrictionsQualified = cleanedRestrictions for ((id, namespace) <- prefixes.toSeq.sortBy(_._1.length).reverse) { - // Replace prefixes in properties and types - restrictionsFull = restrictionsFull.replaceAll("([\\s^])" + id + ":" + "([^;\\s\\{\\}+*]+)([+*]*\\s+\\.;)?", "$1<" + namespace + "$2>$3") restrictionsQualified = restrictionsQualified.replaceAll("<" + namespace + "([^>]+)>", id + ":" + "$1") } new SparqlRestriction(variable, restrictionsFull, restrictionsQualified) } + private def replacePrefix(m: Regex.Match)(implicit prefixes: Prefixes = Prefixes.empty): String = { + val prefix = m.group(1) + val name = m.group(2) + prefixes.get(prefix) match { + case Some(namespace) => s"<$namespace$name>" + case None => throw new BadUserInputException(s"Unknown prefix '$prefix' in SPARQL restriction.") + } + } + /** Restrict entity to a specific type */ def forType(typeUri: Uri): SparqlRestriction = { if(typeUri.uri.isEmpty) { diff --git a/silk-core/src/test/scala/org/silkframework/entity/rdf/SparqlRestrictionTest.scala b/silk-core/src/test/scala/org/silkframework/entity/rdf/SparqlRestrictionTest.scala index 7b25193fa1..eea8195a53 100644 --- a/silk-core/src/test/scala/org/silkframework/entity/rdf/SparqlRestrictionTest.scala +++ b/silk-core/src/test/scala/org/silkframework/entity/rdf/SparqlRestrictionTest.scala @@ -4,6 +4,7 @@ package org.silkframework.entity.rdf import org.silkframework.config.Prefixes import org.scalatest.flatspec.AnyFlatSpec import org.scalatest.matchers.should.Matchers +import org.silkframework.runtime.validation.BadUserInputException class SparqlRestrictionTest extends AnyFlatSpec with Matchers { @@ -33,6 +34,21 @@ class SparqlRestrictionTest extends AnyFlatSpec with Matchers { resolve(restriction) should be (restriction) } + it should "resolve prefixes correctly if using property paths with prefixed names" in { + val restriction = "?a owl:sameAs/rdf:type owl:Thing ." + resolve(restriction) should be ("?a / .") + } + + it should "fail if a prefix in a property path is not defined" in { + val restriction = "?a rdf:type/schema:additionalType owl:Class ." + an[BadUserInputException] should be thrownBy resolve(restriction) + } + + it should "not replace prefixes in full URIs" in { + val restriction = "?a ." + resolve(restriction) should be (restriction) + } + private def resolve(sparql: String) = SparqlRestriction.fromSparql("a", sparql).toSparql } diff --git a/silk-workspace/src/test/scala/org/silkframework/workspace/TestWorkspaceProviderTestTrait.scala b/silk-workspace/src/test/scala/org/silkframework/workspace/TestWorkspaceProviderTestTrait.scala index 0f8e22f66e..9778996779 100644 --- a/silk-workspace/src/test/scala/org/silkframework/workspace/TestWorkspaceProviderTestTrait.scala +++ b/silk-workspace/src/test/scala/org/silkframework/workspace/TestWorkspaceProviderTestTrait.scala @@ -1,7 +1,7 @@ package org.silkframework.workspace import org.scalatest.{BeforeAndAfterAll, TestSuite} -import org.silkframework.config.MetaData +import org.silkframework.config.{MetaData, Prefixes} import org.silkframework.runtime.activity.UserContext import org.silkframework.runtime.plugin.{ParameterValues, PluginContext, PluginRegistry, TestPluginContext} import org.silkframework.runtime.resource.InMemoryResourceManager @@ -78,10 +78,10 @@ trait TestWorkspaceProviderTestTrait extends BeforeAndAfterAll { this: TestSuite super.afterAll() } - def retrieveOrCreateProject(projectId: Identifier)(implicit userContext: UserContext): Project = { + def retrieveOrCreateProject(projectId: Identifier, prefixes: Prefixes = Prefixes.default)(implicit userContext: UserContext): Project = { WorkspaceFactory().workspace(userContext).findProject(projectId) match{ case Some(p) => p - case None => WorkspaceFactory().workspace(userContext).createProject(new ProjectConfig(projectId, metaData = MetaData(Some(projectId)))) + case None => WorkspaceFactory().workspace(userContext).createProject(new ProjectConfig(projectId, metaData = MetaData(Some(projectId)), projectPrefixes = prefixes)) } } }