--- a/src/main/scala/SPARQL.scala Sun Jan 31 12:06:15 2010 -0500
+++ b/src/main/scala/SPARQL.scala Sun Jan 31 20:30:34 2010 -0500
@@ -14,7 +14,7 @@
import MyParsers._
case class Select(attrs:SparqlAttributeList, gp:GraphPattern)
-case class Construct(pattern:TriplesBlock, gp:GraphPattern)
+case class Construct(head:TriplesBlock, gp:GraphPattern)
case class SparqlAttributeList(attributelist:List[Var])
sealed abstract class GraphPattern
--- a/src/main/scala/SparqlToSparql.scala Sun Jan 31 12:06:15 2010 -0500
+++ b/src/main/scala/SparqlToSparql.scala Sun Jan 31 20:30:34 2010 -0500
@@ -1,24 +1,105 @@
/* SparqlToSparql: convert SPARQL queries to sound SQL queries.
*
- * Please read from the bottom -- i.e. apply calls mapGraphPattern with the root
- * graph pattern. mapGraphPattern handles all the graph pattern types in SPARQL,
- * effectively peforming the Convert Graph Patterns step in SPARQL 1.0 12.2.1
- * <http://www.w3.org/TR/rdf-sparql-query/#convertGraphPattern>
- * with the target semantics in SQL instead of SPARQL.
+
+ *
*/
package w3c.sw.sparql2sparql
import scala.util.parsing.combinator._
-import java.net.URI
-import w3c.sw.sql
-import w3c.sw.sql.PrettySql.toPrettySql
import w3c.sw.sparql
-import w3c.sw.util
object SparqlToSparql {
+ def substituteTerm (changeMe:sparql.S, from:sparql.Term, to:sparql.Term):sparql.S = {
+ if (toTerm(changeMe) == from) to match {
+ case sparql.TermUri(u) => sparql.SUri(u)
+ case sparql.TermVar(v) => sparql.SVar(v)
+ case sparql.TermLit(l) => error("literal subject \"" + l + "\" not allowed in SPARQL")
+ }
+ else changeMe
+ }
+ def substituteTerm (changeMe:sparql.O, from:sparql.Term, to:sparql.Term):sparql.O = {
+ if (toTerm(changeMe) == from) to match {
+ case sparql.TermUri(u) => sparql.OUri(u)
+ case sparql.TermVar(v) => sparql.OVar(v)
+ case sparql.TermLit(l) => sparql.OLit(l)
+ }
+ else changeMe
+ }
+ def toTerm (term:sparql.S):sparql.Term = {
+ term match {
+ case sparql.SUri(u) => sparql.TermUri(u)
+ case sparql.SVar(v) => sparql.TermVar(v)
+ }
+ }
+ def toTerm (term:sparql.O):sparql.Term = {
+ term match {
+ case sparql.OUri(u) => sparql.TermUri(u)
+ case sparql.OVar(v) => sparql.TermVar(v)
+ case sparql.OLit(l) => sparql.TermLit(l)
+ }
+ }
+ def substitute (gp:sparql.GraphPattern, from:sparql.Term, to:sparql.Term) = {
+ 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),
+ tp.p,
+ substituteTerm(tp.o, from, to))
+ }
+ ))
+ case _ => error("not implemented" + gp)
+ }
+ }
+ case class HornRule (head:sparql.TriplePattern, gp:sparql.GraphPattern) {
+ override def toString = "{" + head + "} => {" + gp + "}"
+ def transform (tp:sparql.TriplePattern):sparql.GraphPattern = {
+ substitute(substitute(gp, toTerm(head.s), toTerm(tp.s)), toTerm(head.o), toTerm(tp.o))
+ }
+ }
+ case class RuleMap (rules:Map[sparql.Uri, HornRule]) {
+ def transform (tp:sparql.TriplePattern):sparql.GraphPattern = {
+ tp.p match {
+ case sparql.PUri(u) =>
+ try { rules(u).transform(tp) } catch {
+ case e:java.util.NoSuchElementException => sparql.TriplesBlock(List(tp))
+ }
+ case _ => error("not implemented: " + tp.p)
+ }
+ }
+ }
+
+ def mapGraphPattern (gp:sparql.GraphPattern, ruleMap:RuleMap):sparql.GraphPattern = {
+ gp match {
+ case sparql.TriplesBlock(tps) => {
+ val l = tps.foldLeft(List[sparql.GraphPattern]())((s, tp) => s ++ Set(ruleMap.transform(tp)))
+ if (l.size > 1)
+ sparql.TableConjunction(l)
+ else
+ l(0)
+ }
+ case _ => error("not implemented: " + gp);
+ }
+ }
+
def apply (query:sparql.Select, constructs:List[sparql.Construct]) : sparql.Select = {
- query
+ val ruleMap = RuleMap({
+ constructs.foldLeft(Map[sparql.Uri, HornRule]())((m, rule) => {
+ rule.head.triplepatterns.foldLeft(m)((m, tp) => m + ({
+ tp.p match {
+ case sparql.PUri(u) => u -> HornRule(tp, rule.gp)
+ case _ => error("not implemented: " + tp.p)
+ }
+ }))
+ })
+ })
+ // println("ruleMap: " + ruleMap)
+ sparql.Select(
+ query.attrs,
+ mapGraphPattern(query.gp, ruleMap)
+ )
}
}
--- a/src/test/scala/SparqlToSparqlTest.scala Sun Jan 31 12:06:15 2010 -0500
+++ b/src/test/scala/SparqlToSparqlTest.scala Sun Jan 31 20:30:34 2010 -0500
@@ -14,7 +14,6 @@
*/
class SparqlToSparqlTest extends FunSuite {
- /* Disable turtle string-izing (SparqlToSparql parm 5) and return native format: */
test("cat") {
val sparqlParser = Sparql()
val query = sparqlParser.parseAll(sparqlParser.select, """
@@ -33,4 +32,33 @@
assert(transformed === expected)
}
+ test("foaf:last_name") {
+ val sparqlParser = Sparql()
+ val query = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX foaf : <http://xmlns.com/foaf/0.1/>
+PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
+SELECT ?emp {
+?emp foaf:last_name "Smith"^^xsd:string
}
+""").get
+ val rule1 = sparqlParser.parseAll(sparqlParser.construct, """
+PREFIX foaf : <http://xmlns.com/foaf/0.1/>
+PREFIX empP : <http://hr.example/DB/Employee#>
+CONSTRUCT { ?who foaf:first_name ?fname .
+ ?who foaf:last_name ?lname }
+ WHERE { ?who empP:firstName ?fname .
+ ?who empP:lastName ?lname }
+""").get
+ val transformed = SparqlToSparql(query, List(rule1))
+ val expected = sparqlParser.parseAll(sparqlParser.select, """
+PREFIX empP : <http://hr.example/DB/Employee#>
+PREFIX xsd : <http://www.w3.org/2001/XMLSchema#>
+SELECT ?emp {
+?emp empP:firstName ?fname .
+?emp empP:lastName "Smith"^^xsd:string
+}
+""").get
+ assert(transformed === expected)
+ }
+
+}