Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: SPARQL restriction expands wrong SPARQL pattern #867

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -55,17 +58,29 @@ object SparqlRestriction {
val strippedRestrictions = restrictions.trim.stripSuffix(".").trim
val cleanedRestrictions = if (strippedRestrictions.isEmpty) "" else strippedRestrictions + " ."

var restrictionsFull = cleanedRestrictions
val prefixRegex = """(?<!<)(?<![\p{L}\d])([a-zA-Z][a-zA-Z0-9]*):([^\s/<>"';]+)(?![^<]*>)(?![^"']*["'](?:[^"']*["'][^"']*["'])*[^"']*$)""".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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {

Expand Down Expand Up @@ -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 <http://www.w3.org/2002/07/owl#sameAs>/<http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://www.w3.org/2002/07/owl#Thing> .")
}

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 <urn:test:prop1> <http://www.example.com/someValue> ."
resolve(restriction) should be (restriction)
}

private def resolve(sparql: String) = SparqlRestriction.fromSparql("a", sparql).toSparql

}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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))
}
}
}