--- a/src/main/scala/SPARQL.scala Sun Jun 13 19:42:52 2010 -0400
+++ b/src/main/scala/SPARQL.scala Tue Jun 15 16:11:39 2010 -0700
@@ -22,8 +22,8 @@
{ if (distinct) "DISTINCT " else "" }+
attrs+"\n"+gp+" "+
{ if (order.size > 0) {order.map(o => o.toString).mkString("ORDER BY ", " ", " ") } else "" }+
- { if (offset.isDefined) {"OFFSET " + offset + " "} else "" }+
- { if (limit.isDefined) {"LIMIT " + limit + " "} else "" }
+ { if (offset.isDefined) {"OFFSET " + offset.get + " "} else "" }+
+ { if (limit.isDefined) {"LIMIT " + limit.get + " "} else "" }
}
case class Construct(head:TriplesBlock, gp:GraphPattern)
case class SparqlAttributeList(attributelist:List[Var]) {
--- a/src/main/scala/SparqlToSparql.scala Sun Jun 13 19:42:52 2010 -0400
+++ b/src/main/scala/SparqlToSparql.scala Tue Jun 15 16:11:39 2010 -0700
@@ -9,6 +9,21 @@
import scala.util.parsing.combinator._
import w3c.sw.sparql
+case class MapTarget (term:sparql.Term, nm:Option[NodePattern])
+
+case class NodePatternMap (m:Map[sparql.Var, NodePattern]) {
+ def var2maptarget (t:sparql.Term) : MapTarget = {
+ t match {
+ case sparql.TermVar(v) => MapTarget(t, m.get(v))
+ case _ => MapTarget(t, None)
+ }
+ }
+}
+
+case class NodePattern (iface:String, direct:String)
+
+case class SparqlMap (construct:sparql.Construct, nodemap:NodePatternMap)
+
object SparqlToSparql {
/**
@@ -27,53 +42,95 @@
/**
* Substitute the terms in a triple pattern or a graph pattern with other terms.
*/
- def substituteTerm (changeMe:sparql.Term, from:sparql.Term, to:sparql.Term):sparql.Term = {
- if (changeMe == from) to
- else changeMe
+ def substituteTerm (changeMe:sparql.Term, from:sparql.Term, to:sparql.Term, nm:Option[NodePattern]):sparql.Term = {
+ if (changeMe == from) {
+ from match {
+ case sparql.TermVar(v) => {
+ if (nm.isDefined) {
+ val nodeMap = nm.get
+ to match {
+ case sparql.TermVar(v2) => {
+ println("reverse map(" + v2 + ",\n " + nodeMap.direct + ",\n " + nodeMap.iface)
+ to
+ }
+ case sparql.TermBNode(b) => {
+ println("reverse map(" + b + ",\n " + nodeMap.direct + ",\n " + nodeMap.iface)
+ to
+ }
+ case sparql.TermUri(u) => {
+ val s:String = u.s
+ val r = u.s.replaceAll(nodeMap.iface, nodeMap.direct)
+ //println("\"" + u.s + "\".replaceAll("+nodeMap.iface+", "+nodeMap.direct+") = \""+r+"\"")
+ sparql.TermUri(sparql.Uri(u.s.replaceAll(nodeMap.iface, nodeMap.direct))) // !!! failure here should error()
+ }
+ case sparql.TermLit(l) =>
+ error("variable " + v + " bound to literlal " + l + " but should be a node as indicated by " + nodeMap)
+ }
+ } else to
+ }
+ case _ => to
+ }
+ } else changeMe
}
- def substitute (gp:sparql.GraphPattern, from:sparql.Term, to:sparql.Term) = {
+
+ def substitute (gp:sparql.GraphPattern, from:sparql.Term, target:MapTarget) = {
gp match {
case sparql.TriplesBlock(triplepatterns) => sparql.TriplesBlock(
triplepatterns.map((tp) => {
// println("sub(" + tp.o + ", " + from + ", " + to + ") => ")
- // println(substituteTerm(toTerm(tp.o), tp.o, from, to))
- sparql.TriplePattern(substituteTerm(tp.s, from, to),
+ // println(substituteTerm(toTerm(tp.o), tp.o, from, target.term))
+ sparql.TriplePattern(substituteTerm(tp.s, from, target.term, target.nm),
tp.p,
- substituteTerm(tp.o, from, to))
+ substituteTerm(tp.o, from, target.term, target.nm))
}
))
case _ => error("not implemented" + gp)
}
}
- type VarMap = Map[sparql.Var, sparql.Term]
+ type VarMap = Map[sparql.Var, MapTarget]
- def substituteGraphPattern (gp:sparql.GraphPattern, vartermmap:VarMap, varPrefix:String):sparql.GraphPattern = {
+ def substituteGraphPattern (gp:sparql.GraphPattern, vartargetmap:VarMap, varPrefix:String):sparql.GraphPattern = {
/**
* Substitute gp (the rule body) with the variables and constants from the
* query which matched variables in the rule head.
*/
- val mapped = vartermmap.foldLeft(gp)((incrementalGP, varterm) => {
- val (varr, term) = varterm
- substitute(incrementalGP, sparql.TermVar(varr), term)
+ val mapped = vartargetmap.foldLeft(gp)((incrementalGP, vartarget) => {
+ val (varr, target) = vartarget
+ val ret = substitute(incrementalGP, sparql.TermVar(varr), target)
+ //println("^^incrementalGP: " + incrementalGP + "\nvartarget: " + vartarget + "\nret: " + ret)
+ ret;
})
/**
* "Uniquely" prefix unmapped vars to void conflict with other rules.
*/
- // val bound = Set[sparql.Var](vartermmap.map((varterm) => varterm._1))
- val bound = vartermmap.foldLeft(Set[sparql.Var]())((s, varterm) => s + varterm._1)
- val mappedTo = vartermmap.foldLeft(Set[sparql.Term]())((s, varterm) => s + varterm._2)
+ // val bound = Set[sparql.Var](vartargetmap.map((vartarget) => vartarget._1))
+ val bound = vartargetmap.foldLeft(Set[sparql.Var]())((s, vartarget) => s + vartarget._1)
+ val mappedTo = vartargetmap.foldLeft(Set[sparql.Term]())((s, vartarget) => {
+ val MapTarget(term, optnp) = vartarget._2
+ (term, optnp) match {
+ case (sparql.TermUri(u), Some(np)) => {
+ s + sparql.TermUri(sparql.Uri(u.s.replaceAll(np.iface, np.direct))) // !!! failure here should error()
+ }
+ case (_, _) => s + vartarget._2.term
+ }
+ })
val vars = gp.findVars
val diff = vars -- bound
diff.foldLeft(mapped)((incrementalGP, varr) => {
- substitute(incrementalGP, sparql.TermVar(varr), sparql.TermVar(sparql.Var(varPrefix + varr.s))).trim(mappedTo)
+ val full = substitute(incrementalGP, sparql.TermVar(varr),
+ MapTarget(sparql.TermVar(sparql.Var(varPrefix + varr.s)),
+ None// !! vartargetmap(varr).nm
+ ))
+ full.trim(mappedTo)
})
}
- case class RuleIndex (trigger:sparql.TriplePattern, construct:sparql.Construct) {
- override def toString = "{ \"" + trigger + "\" } => {\"\n " + _shorten(construct.gp.toString).replace("\n", "\n ") + "\n\"}"
+ case class RuleIndex (trigger:sparql.TriplePattern, smap:SparqlMap) {
+ override def toString = "{ \"" + trigger + "\" } => {\"\n " + _shorten(smap.construct.gp.toString).replace("\n", "\n ") + "\n\"}"
def transform (tp:sparql.TriplePattern):sparql.GraphPattern = {
- substitute(substitute(construct.gp, trigger.s, tp.s), trigger.o, tp.o)
+ substitute(substitute(smap.construct.gp, trigger.s, smap.nodemap.var2maptarget(tp.s)),
+ trigger.o, smap.nodemap.var2maptarget(tp.o))
}
}
@@ -125,20 +182,20 @@
}
// val varsS:Option[Bindings] = vars.maybeRebind(construct, v, tos)
// b:Map[sparql.Construct, List[VarMap]]
- def mustBind (construct:sparql.Construct, vs:sparql.Term, tos:sparql.Term, vo:sparql.Term, too:sparql.Term):Bindings = {
+ def mustBind (construct:sparql.Construct, nodemap:NodePatternMap, vs:sparql.Term, tos:sparql.Term, vo:sparql.Term, too:sparql.Term):Bindings = {
/* ridiculous traversal for the first viably matching rule edition. */
var matched = false
val existing:List[VarMap] = b(construct).map((map:VarMap) => {
def _matches (l:sparql.Term, r:sparql.Term):(Boolean, VarMap) = {
- val empty:VarMap = Map[sparql.Var, sparql.Term]()
+ val empty:VarMap = Map[sparql.Var, MapTarget]()
(l, r) match {
case (v:sparql.TermVar, x) =>
// println("(v:sparql.TermVar, x)" + v.v + ":" + x)
if (map.contains(v.v)) {
- if (r == map(v.v)) (true, empty)
+ if (r == map(v.v).term) (true, empty)
else (false, empty)
} else {
- (true, Map[sparql.Var, sparql.Term](v.v -> r))
+ (true, Map[sparql.Var, MapTarget](v.v -> MapTarget(r, nodemap.m.get(v.v))))
}
case (x, v:sparql.TermVar) => {
// println("query variable " + v + " known equal to " + x + " at compile time")
@@ -166,21 +223,21 @@
val (oldConstr, l) = constructlist
if (oldConstr == construct) {
def _newBinding (l:sparql.Term, r:sparql.Term):VarMap = {
- val empty:VarMap = Map[sparql.Var, sparql.Term]()
+ val empty:VarMap = Map[sparql.Var, MapTarget]()
(l, r) match {
case (v:sparql.TermVar, _) =>
- Map[sparql.Var, sparql.Term](v.v -> r)
+ Map[sparql.Var, MapTarget](v.v -> MapTarget(r, nodemap.m.get(v.v)))
case (b:sparql.TermBNode, _) => {
println(".. synthetic query variable " + b + "")
- Map[sparql.Var, sparql.Term]()
+ Map[sparql.Var, MapTarget]()
// println("@@ mustBind:_newBinding(BNode) + " + b)
// Map(sparql.Var("bnode_" + b.b.s) -> r) // !!!
}
case (_, v:sparql.TermVar) => {
println(".. query variable " + v + " known equal to " + l + " at compile time")
- Map[sparql.Var, sparql.Term]()
+ Map[sparql.Var, MapTarget]()
}
- case (_, _) => Map[sparql.Var, sparql.Term]()
+ case (_, _) => Map[sparql.Var, MapTarget]()
}
}
val ent = _newBinding(vs, tos) ++ _newBinding(vo, too)
@@ -221,9 +278,9 @@
val _prefix = "rule:" + _ruleNo
_ruleNo = _ruleNo + 1
_deepPrint1(_prefix, "trying " + _shorten(hornRule.trigger.toString))
- val vars = varsP.ensureGraphPattern(hornRule.construct)
+ val vars = varsP.ensureGraphPattern(hornRule.smap.construct)
// try matching the subject
- val varss:Bindings = vars.mustBind(hornRule.construct, hornRule.trigger.s, car.s, hornRule.trigger.o, car.o)
+ val varss:Bindings = vars.mustBind(hornRule.smap.construct, hornRule.smap.nodemap, hornRule.trigger.s, car.s, hornRule.trigger.o, car.o)
val ret =
if (cdr.size > 0) {
transform(cdr, used + car, varss)
@@ -281,10 +338,11 @@
}
}
- def apply (query:sparql.Select, constructs:List[sparql.Construct]) : sparql.Select = {
+ def apply (query:sparql.Select, maps:List[SparqlMap]) : sparql.Select = {
var _ruleNo = 0
val ruleMap = RuleMap({
- constructs.foldLeft(Map[sparql.Uri, List[RuleIndex]]())((m, rule) => {
+ maps.foldLeft(Map[sparql.Uri, List[RuleIndex]]())((m, sm) => {
+ val SparqlMap(rule, nodemap) = sm
// Register abbreviations for debugging output.
RuleLabels.update(rule.head.toString, "head" + _ruleNo)
RuleLabels.update(rule.gp.toString, "body" + _ruleNo)
@@ -293,8 +351,8 @@
rule.head.triplepatterns.foldLeft(m)((m, tp) => m + ({
tp.p match {
case sparql.TermUri(u) => u -> {
- if (m.contains(u)) m(u) ++ List(RuleIndex(tp, rule))
- else List(RuleIndex(tp, rule))}
+ if (m.contains(u)) m(u) ++ List(RuleIndex(tp, sm))
+ else List(RuleIndex(tp, sm))}
case _ => error("not implemented: " + tp.p)
}
}))
--- a/src/main/scala/SparqlToSparqlToSql.scala Sun Jun 13 19:42:52 2010 -0400
+++ b/src/main/scala/SparqlToSparqlToSql.scala Tue Jun 15 16:11:39 2010 -0700
@@ -47,7 +47,8 @@
)
/* Convert to equivalent SQL SELECT. */
- val asStem = sparql2sparql.SparqlToSparql(select, List(rule))
+ val emptyPatternMap = sparql2sparql.NodePatternMap(Map[sparql.Var, sparql2sparql.NodePattern]())
+ val asStem = sparql2sparql.SparqlToSparql(select, List(sparql2sparql.SparqlMap(rule, emptyPatternMap)))
// println("triple: "+triple)
// println("asStem: "+asStem)
val sql.Select(distinct, sql.AttributeList(attributes), tablelist, expression, order, offset, limit) = sparql2sql.SparqlToSql(schema, asStem, stemUri, false, true)._1
--- a/src/test/scala/SparqlToSparqlTest.scala Sun Jun 13 19:42:52 2010 -0400
+++ b/src/test/scala/SparqlToSparqlTest.scala Tue Jun 15 16:11:39 2010 -0700
@@ -7,13 +7,15 @@
import org.scalatest.FunSuite
import java.net.URI
import w3c.sw.sparql.Sparql
-import w3c.sw.sparql2sparql.{SparqlToSparql}
+import w3c.sw.sparql2sparql.{SparqlToSparql,NodePatternMap,NodePattern,SparqlMap}
/* The SparqlToSparqlTest class transforms SPARQL queries to a relational data
* structure and compares them to a structure parsed from SQL.
*/
class SparqlToSparqlTest extends FunSuite {
+ val emptyPatternMap = NodePatternMap(Map[sparql.Var, NodePattern]())
+
test("foaf:last_name simple head") {
val sparqlParser = Sparql()
/* Query to be fired over view created by some transformation rules. */
@@ -41,7 +43,7 @@
CONSTRUCT { ?who foaf:first_name ?fname }
WHERE { ?who empP:firstName ?fname }
""").get
- val transformed = SparqlToSparql(query, List(fname, lname))
+ val transformed = SparqlToSparql(query, List(SparqlMap(fname, emptyPatternMap), SparqlMap(lname, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX empP : <http://hr.example/DB/Employee#>
PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
@@ -69,7 +71,7 @@
WHERE { ?who empP:firstName ?fname .
?who empP:lastName ?lname }
""").get
- val transformed = SparqlToSparql(query, List(flname))
+ val transformed = SparqlToSparql(query, List(SparqlMap(flname, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX empP : <http://hr.example/DB/Employee#>
PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
@@ -98,7 +100,7 @@
WHERE { ?who empP:firstName ?fname .
?who empP:lastName ?lname }
""").get
- val transformed = SparqlToSparql(query, List(flname))
+ val transformed = SparqlToSparql(query, List(SparqlMap(flname, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX empP : <http://hr.example/DB/Employee#>
PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
@@ -126,7 +128,7 @@
CONSTRUCT { ?who foaf:last_name ?lname }
WHERE { ?who empP:lastName ?lname }
""").get
- val transformed = SparqlToSparql(query, List(lname))
+ val transformed = SparqlToSparql(query, List(SparqlMap(lname, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX empP : <http://hr.example/DB/Employee#>
PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
@@ -170,7 +172,7 @@
?who foaf:knows ?whom .
?whom foaf:last_name "Smith"^^xsd:string }
""").get
- val transformed = SparqlToSparql(query, List(Emp_TaskToFoaf))
+ val transformed = SparqlToSparql(query, List(SparqlMap(Emp_TaskToFoaf, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX empP : <http://hr.example/DB/Employee#>
PREFIX task : <http://hr.example/DB/Task#>
@@ -197,7 +199,7 @@
""").get
SparqlToSparql.Abbreviations ++= Emp_TaskToFoaf_abbr
- val transformed = SparqlToSparql(query, List(Emp_TaskToFoaf))
+ val transformed = SparqlToSparql(query, List(SparqlMap(Emp_TaskToFoaf, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX empP : <http://hr.example/DB/Employee#>
PREFIX task : <http://hr.example/DB/Task#>
@@ -294,7 +296,7 @@
?indicCode NDCcodes:NDC ?indicNDC .
?indicCode NDCcodes:ingredient ?ingred }
""").get
- val transformed = SparqlToSparql(query, List(rule1))
+ val transformed = SparqlToSparql(query, List(SparqlMap(rule1, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX Person: <http://hospital.example/DB/Person#>
PREFIX Sex_DE: <http://hospital.example/DB/Sex_DE#>
@@ -347,7 +349,7 @@
?indicCode NDCcodes:NDC ?indicNDC .
?indicCode NDCcodes:ingredient ?ingredCode }
""").get
- val transformed = SparqlToSparql(query, List(rule1))
+ val transformed = SparqlToSparql(query, List(SparqlMap(rule1, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX Item_Medication: <http://hospital.example/DB/Item_Medication#>
PREFIX Medication: <http://hospital.example/DB/Medication#>
@@ -431,7 +433,7 @@
?indicCode NDCcodes:NDC ?indicNDC .
?indicCode NDCcodes:ingredient ?ingredCode }
""").get
- val transformed = SparqlToSparql(query, List(rule1))
+ val transformed = SparqlToSparql(query, List(SparqlMap(rule1, emptyPatternMap)))
val expected = sparqlParser.parseAll(sparqlParser.select, """
PREFIX Person: <http://hospital.example/DB/Person#>
PREFIX Sex_DE: <http://hospital.example/DB/Sex_DE#>
--- a/src/test/scala/SparqlToSparqlToSqlTest.scala Sun Jun 13 19:42:52 2010 -0400
+++ b/src/test/scala/SparqlToSparqlToSqlTest.scala Tue Jun 15 16:11:39 2010 -0700
@@ -8,7 +8,7 @@
import scala.util.matching.Regex
import java.net.URI
import w3c.sw.sparql.Sparql
-import w3c.sw.sparql2sparql.{SparqlToSparql}
+import w3c.sw.sparql2sparql.{SparqlToSparql,NodePatternMap,NodePattern,SparqlMap}
import w3c.sw.sql.{Sql,DatabaseDesc,Relation,RelationDesc,Attribute,Value,Datatype,ForeignKey,Name}
import w3c.sw.sparql2sql.{SparqlToSql,StemURI}
import w3c.sw.sparql2sparql2sql.SparqlToSparqlToSql.toView
@@ -45,7 +45,9 @@
WHERE { ?who empP:firstName ?fname .
?who empP:lastName ?lname }
""").get
- val asStem = SparqlToSparql(foafQuery, List(hr2foaf))
+ val hrPatternMap = NodePatternMap(Map[sparql.Var, NodePattern]())
+
+ val asStem = SparqlToSparql(foafQuery, List(SparqlMap(hr2foaf, hrPatternMap)))
val stemQuery = sparqlParser.parseAll(sparqlParser.select, """
PREFIX empP : <http://hr.example/DB/Employee#>
PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
@@ -157,6 +159,8 @@
?indicCode NDCcodes:ingredient ?ingredCode }
""").get
+ val hl7PatternMap = NodePatternMap(Map[sparql.Var, NodePattern]())
+
test("~/swobjects/tests/healthCare/lists-notBound/hl7.rq short") {
val sparqlParser = Sparql()
val hl7Query = sparqlParser.parseAll(sparqlParser.select, """
@@ -202,7 +206,7 @@
?_0_indicCode NDCcodes:ingredient 6809
}
""").get
- val asStem = SparqlToSparql(hl7Query, List(db2hl7))
+ val asStem = SparqlToSparql(hl7Query, List(SparqlMap(db2hl7, hl7PatternMap)))
assert(asStem === stemQuery)
val sqlParser = Sql()
val sqlQuery = sqlParser.parseAll(sqlParser.select, """
@@ -321,7 +325,7 @@
AND R_patient.MiddleName IS NOT NULL
AND R__0_0_sexEntry.EntryName IS NOT NULL
""").get
- val asStem = SparqlToSparql(hl7Query, List(db2hl7))
+ val asStem = SparqlToSparql(hl7Query, List(SparqlMap(db2hl7, hl7PatternMap)))
if (!(asStem == stemQuery)) {
println(asStem.toString())
println("---")
@@ -484,8 +488,8 @@
*/
val bsbmDb:DatabaseDesc = DDLParser.parseAll(DDLParser.ddl, bsbmDdl).get
- val delme = Sparql() // re-use ConstructParser ?
- val db2bsbm = delme.parseAll(delme.construct, """
+ val db2bsbmP = Sparql() // re-use ConstructParser ?
+ val db2bsbm = db2bsbmP.parseAll(db2bsbmP.construct, """
PREFIX map: <file:/E:/code/d2r-server-0.4/d2r-mapping.n3#>
PREFIX vocab: <vocab/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
@@ -524,6 +528,15 @@
?ptp producttypeproduct:product ?product .
}""" //"
).get
+ val bsbmPatternMap = NodePatternMap(Map(
+ sparql.Var("pfp") ->
+ NodePattern("http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductFeature([0-9]+)",
+ "http://bsbm.example/db/productfeatureproduct/productFeature.$1#record"),
+ sparql.Var("ptp") ->
+ NodePattern("http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductType([0-9]+)",
+ "http://bsbm.example/db/producttypeproduct/productType.$1#record")
+ ))
+
test("bsbm1") {
val sparqlParser = Sparql()
val queryStr = """
@@ -544,10 +557,6 @@
ORDER BY ?label
LIMIT 10
"""
- .replaceAll("<http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductFeature([0-9]+)>",
- "<http://bsbm.example/db/productfeatureproduct/productFeature.$1#record>")
- .replaceAll("<http://www4.wiwiss.fu-berlin.de/bizer/bsbm/v01/instances/ProductType([0-9]+)>",
- "<http://bsbm.example/db/producttypeproduct/productType.$1#record>")
val bsbmQuery = sparqlParser.parseAll(sparqlParser.select, queryStr).get
@@ -586,7 +595,8 @@
ORDER BY R_product.label
LIMIT 10
""").get
- val asStem = SparqlToSparql(bsbmQuery, List(db2bsbm))
+
+ val asStem = SparqlToSparql(bsbmQuery, List(SparqlMap(db2bsbm, bsbmPatternMap)))
assert(stemExpected === asStem)
val (asSql, _) = SparqlToSql(bsbmDb, asStem, StemURI("http://bsbm.example/db/"), false, false)
assert(sqlExpected === asSql)