[Mulgara-svn] r1853 - in projects/SparqlTester/trunk/src/org/duraspace/rdf: . parser ttl vocab

pag at mulgara.org pag at mulgara.org
Tue Nov 24 19:56:20 UTC 2009


Author: pag
Date: 2009-11-24 11:56:19 -0800 (Tue, 24 Nov 2009)
New Revision: 1853

Added:
   projects/SparqlTester/trunk/src/org/duraspace/rdf/SparqlResult.scala
   projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/N3GraphReader.scala
   projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/RDFGraphReader.scala
   projects/SparqlTester/trunk/src/org/duraspace/rdf/ttl/
   projects/SparqlTester/trunk/src/org/duraspace/rdf/ttl/SparqlResult.scala
   projects/SparqlTester/trunk/src/org/duraspace/rdf/vocab/RS.scala
Log:
Now handling various result files: RDF, TTL, SRX, boolean, sorted and unsorted

Added: projects/SparqlTester/trunk/src/org/duraspace/rdf/SparqlResult.scala
===================================================================
--- projects/SparqlTester/trunk/src/org/duraspace/rdf/SparqlResult.scala	                        (rev 0)
+++ projects/SparqlTester/trunk/src/org/duraspace/rdf/SparqlResult.scala	2009-11-24 19:56:19 UTC (rev 1853)
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.duraspace.rdf
+
+import java.io.File
+import java.io.InputStream
+import scala.xml.XML
+
+abstract class SparqlResult {
+
+  def isSorted = false
+
+  def isBoolean = false
+
+  def variables: Seq[String]
+
+  def results: Collection[Map[String,Node]]
+
+  def booleanResult = false
+
+  def equivalentTo(other: SparqlResult) = {
+    if (isBoolean) booleanResult == other.booleanResult
+    else if (isSorted) other.isSorted && results == other.results
+    else results == other.results.toList
+  }
+
+  /** Compares this result set to another for equality */
+  override def equals(that: Any) = that match {
+    case r: SparqlResult => isSorted == r.isSorted && results == r.results
+    case _ => false
+  }
+
+  /** String representation of the entire result set */
+  override def toString = {
+    if (isBoolean) booleanResult.toString
+    else variables + "\n" + results.toString
+  }
+}
+
+
+object SparqlResult {
+
+  def apply(file: File) =
+    if (file.getName.endsWith(".srx")) new org.duraspace.rdf.xml.SparqlResult(file)
+    else new org.duraspace.rdf.ttl.SparqlResult(file)
+
+  def apply(xml: scala.xml.Node) = new org.duraspace.rdf.xml.SparqlResult(xml)
+
+  def apply(content: InputStream) = new org.duraspace.rdf.xml.SparqlResult(XML.load(content))
+}

Added: projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/N3GraphReader.scala
===================================================================
--- projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/N3GraphReader.scala	                        (rev 0)
+++ projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/N3GraphReader.scala	2009-11-24 19:56:19 UTC (rev 1853)
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.duraspace.rdf.parser
+
+import java.io.File
+import java.io.FileInputStream
+import java.util.logging.Logger
+import java.util.logging.Level
+import java.net.URI
+import java.net.URISyntaxException
+
+import com.hp.hpl.jena.n3.N3Parser
+import com.hp.hpl.jena.n3.N3AntlrParserTokenTypes._
+import com.hp.hpl.jena.n3.N3ParserEventHandler
+import antlr.collections.AST
+
+import org.duraspace.rdf.impl._
+import org.duraspace.rdf.vocab.XSD
+import org.duraspace.rdf.vocab.RDF
+import org.duraspace.rdf.vocab.OWL
+
+
+class N3GraphReader(val graphFile: File) extends N3ParserEventHandler with GraphReader {
+
+  /** The first identifier for anonymous nodes. */
+  val AnonTag1 = "_:"
+
+  /** The second identifier for anonymous nodes. */
+  val AnonTag2 = "=:"
+
+  def parse {
+    try {
+      val inputStream = new FileInputStream(graphFile)
+      (new N3Parser(inputStream, this)).parse()
+    } catch {
+      case e => throw new ParseException("Error reading from file: " + graphFile, e)
+    }
+  }
+
+  def endDocument { debug("Finishing N3 document") }
+
+  def endFormula(line: Int, arg1: String) { debug("End of formula. " + line + ": " + arg1) }
+
+  def error(arg0: Exception, arg1: String) { error("Error in data. " + arg0 + ": " + arg1) }
+
+  def startDocument() { debug("Starting N3 document") }
+
+  def startFormula(line: Int, arg1: String) { error("Unexpected formula. " + line + ": " + arg1) }
+
+  def directive(line: Int, directive: AST, args: Array[AST], context: String) {
+    directive.getType match {
+      case AT_PREFIX => {
+        debug("Adding prefix: " + args(0) + args(1))
+        prefixMap += (args(0).toString -> args(1).toString)
+      }
+      case _ => error("Ignoring directive. " + line + ": " + directive + " {" + context + "}")
+    }
+  }
+
+  def quad(line: Int, subj: AST, pred: AST, obj: AST, context: String) {
+    debug("line: " + line + ". " + List(subj.getText(), pred.getText(), obj.getText()).mkString(" ") + " :- " + context)
+    try {
+      graph.add(toNode(subj).asInstanceOf[SubjectNode], toNode(pred).asInstanceOf[PredicateNode], toNode(obj).asInstanceOf[ObjectNode])
+    } catch {
+      case e: Throwable => {
+        error("Error parsing node: " + e.getMessage() + " at line: " + line + " [" + subj + ", " + pred + ", " + obj + "]")
+      }
+    }
+  }
+
+  def toNode(ast: AST) = {
+    ast.getType() match {
+      case LITERAL => {
+        val a1 = ast.getNextSibling
+        val a2 = if (a1 == null) null else a1.getNextSibling
+        val lang = getLang(a1, a2)
+        val datatype = getDatatype(a1, a2)
+        new LiteralImpl(ast.toString, lang, datatype)
+      }
+      case NUMBER => new LiteralImpl(ast.toString, getNumberType(ast.toString))
+      case ANON => new BlankNodeImpl(ast.toString())
+      case QNAME => {
+        val s = ast.toString()
+        if (isAnonymous(ast)) new BlankNodeImpl(s)
+        else {
+          val colonIndex = s.indexOf(':')
+          val qnamePrefix = s.substring(0, colonIndex + 1)
+          val uriPrefix = prefixMap(qnamePrefix)
+          require (uriPrefix != null, "No @prefix for " + s)
+          new Uri(uriPrefix + s.substring(colonIndex + 1))
+        }
+      }
+      case URIREF => new Uri(ast.toString())
+      case KW_A => new Uri(RDF.Type)
+      case TK_LIST_FIRST => new Uri(RDF.First)
+      case TK_LIST_REST => new Uri(RDF.Rest)
+      case TK_LIST_NIL => new Uri(RDF.Nil)
+      case TK_LIST => new Uri(RDF.List)
+      case EQUAL => new Uri(OWL.SameAs)
+      case FORMULA => throw new ParseException("Formulas are not supported. file=[" + graphFile + "]")
+      case _ => throw new ParseException("Unsupported N3 parser token type: " + ast.getType() + " '" + ast + "' file=[" + graphFile + "]");
+    }
+  }
+
+  private def getLang(a1: AST, a2: AST): Option[String] = {
+    if (a1 != null) {
+      val lang = getLang(a1)
+      if (lang == None) getLang(a2) else lang
+    } else getLang(a2)
+  }
+
+  private def getLang(a: AST): Option[String] =
+    if (a == null || a.getType != AT_LANG) None else Some(a.getText.substring(1))
+
+  private def getDatatype(a1: AST, a2: AST): Option[URI] = {
+    val datatype = getDatatype(a1)
+    if (datatype == None) getDatatype(a2) else datatype
+  }
+
+  private def getDatatype(a: AST): Option[URI] = {
+    if (a == null || a.getType() != DATATYPE) None
+    else {
+      val dt = a.getFirstChild
+      try {
+        if (dt == null) None else Some(new URI(dt.toString()))
+      } catch {
+        case e: URISyntaxException => error("Error parsing N3 datatype: " + dt.toString())
+                                      None
+      }
+    }
+  }
+
+  private def getNumberType(n: String) = {
+    if (n.indexOf('.') >= 0) XSD.Double
+    else {
+      try {
+        val l = n.toLong
+        if (l <= Math.MAX_INT && l >= Math.MIN_INT) XSD.Int else XSD.Long
+      } catch {
+        case _ => XSD.Integer
+      }
+    }
+  }
+
+  def isAnonymous(node: AST) = {
+    val s = node.toString()
+    s.startsWith(AnonTag1) || s.startsWith(AnonTag2)
+  }
+
+}

Added: projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/RDFGraphReader.scala
===================================================================
--- projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/RDFGraphReader.scala	                        (rev 0)
+++ projects/SparqlTester/trunk/src/org/duraspace/rdf/parser/RDFGraphReader.scala	2009-11-24 19:56:19 UTC (rev 1853)
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.duraspace.rdf.parser
+
+import java.io.File
+import java.io.FileInputStream
+import java.util.logging.Logger
+import java.util.logging.Level
+import java.net.URI
+import java.net.URISyntaxException
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXParseException;
+import com.hp.hpl.jena.rdf.arp.ALiteral;
+import com.hp.hpl.jena.rdf.arp.ARP;
+import com.hp.hpl.jena.rdf.arp.AResource;
+import com.hp.hpl.jena.rdf.arp.StatementHandler;
+
+import org.duraspace.rdf.impl._
+import org.duraspace.rdf.vocab.XSD
+import org.duraspace.rdf.vocab.RDF
+import org.duraspace.rdf.vocab.OWL
+
+
+class RDFGraphReader(val graphFile: File) extends GraphReader with StatementHandler with ErrorHandler {
+
+  def parse {
+    try {
+      val arp = new ARP
+      val options = arp.getOptions
+      options.setEmbedding(true)
+      options.setLaxErrorMode()
+      val handlers = arp.getHandlers
+      handlers.setErrorHandler(this)
+      handlers.setStatementHandler(this)
+
+      val inputStream = new FileInputStream(graphFile)
+      arp.load(inputStream, graphFile.toURI.toString)
+    } catch {
+      case e: ParseException => throw e
+      case e => throw new ParseException("Error reading from file: " + graphFile, e)
+    }
+  }
+
+  def error(arg0: Exception, arg1: String) { error("Error in data. " + arg0 + ": " + arg1) }
+
+  def statement(subject: AResource, predicate: AResource, obj: ALiteral) {
+    addTriple(toNode(subject), toNode(predicate), toNode(obj))
+  }
+
+  def statement(subject: AResource, predicate: AResource, obj: AResource) {
+    addTriple(toNode(subject), toNode(predicate), toNode(obj))
+  }
+
+  def error(e: SAXParseException) {
+    error("Error: " + graphFile + ", line " + e.getLineNumber() + ", column " + e.getColumnNumber() + ": " + e.getMessage());
+  }
+
+  def fatalError(e: SAXParseException) {
+    throw new ParseException("Unrecoverable error in " + graphFile + ", line " + e.getLineNumber() + ", column " + e.getColumnNumber() + ": " + e.getMessage(), e)
+  }
+
+  def warning(e: SAXParseException) {
+    error("Warning: " + graphFile + ", line " + e.getLineNumber() + ", column " + e.getColumnNumber() + ": " + e.getMessage());
+  }
+
+  private def addTriple(s: Node, p: Node, o: Node) {
+    graph.add(s.asInstanceOf[SubjectNode], p.asInstanceOf[PredicateNode], o.asInstanceOf[ObjectNode])
+  }
+
+  private def toNode(l: ALiteral) = {
+    val datatype = if (l.getDatatypeURI != null) Some(new URI(l.getDatatypeURI)) else None
+
+    val lang = if (datatype != None) None
+               else if (l.getLang == "") None
+               else Some(l.getLang)
+
+    new LiteralImpl(l.toString, lang, datatype)
+  }
+
+  private def toNode(r: AResource) = {
+    if (r.isAnonymous) new BlankNodeImpl(r.getAnonymousID)
+    else new Uri(r.getURI())
+  }
+
+}

Added: projects/SparqlTester/trunk/src/org/duraspace/rdf/ttl/SparqlResult.scala
===================================================================
--- projects/SparqlTester/trunk/src/org/duraspace/rdf/ttl/SparqlResult.scala	                        (rev 0)
+++ projects/SparqlTester/trunk/src/org/duraspace/rdf/ttl/SparqlResult.scala	2009-11-24 19:56:19 UTC (rev 1853)
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.duraspace.rdf.ttl
+
+import scala.collection.mutable.ArrayBuffer
+import java.io.File
+import org.duraspace.rdf.impl.LiteralImpl
+import org.duraspace.rdf.impl.Uri._
+import org.duraspace.rdf.parser.GraphReader
+import org.duraspace.rdf.vocab.RDF
+import org.duraspace.rdf.vocab.RS
+
+/**
+ * A class for representing SPARQL results expressed in a TTL document
+ */
+class SparqlResult(file: File) extends org.duraspace.rdf.SparqlResult {
+
+  /** The TTL document containing the results */
+  val readResults = GraphReader(file)
+
+  /** The TTL file parsed as an RDF Graph */
+  val graph = readResults.graph
+
+  /** The result set object, as defined in the SPARQL result document */
+  private val resultSet = {
+    val rs = graph.getSubjects(RDF.Type, RS.ResultSet)
+    require(rs.size == 1)
+    rs.head
+  }
+
+  /** The list of all solutions defined in the result set */
+  val solutionList = graph.getValues(resultSet, RS.Solution)
+
+  /** A flag to indicate if order is important in this result set */
+  override val isSorted = if (solutionList.isEmpty) false
+                          else solutionList.head match {
+                            case n: SubjectNode => !graph.getValues(n, RS.Index).isEmpty
+                            case _ => false
+                          }
+
+  /** A flag to indicate if the results are a boolean */
+  override val isBoolean = !graph.getValues(resultSet, RS.Boolean).isEmpty
+
+  /** The list of variables in this result set */
+  val variables = {
+    for (LiteralImpl(v) <- graph.getValues(resultSet, RS.ResultVariable)) yield v.text
+  }
+
+  /**
+   * All the bindings in this result set.
+   * If sorted, then the bindings appear in a List, otherwise, a Set.
+   * Each binding is a Map of variable names to ObjectNodes containing the value.
+   */
+  def results = if (isSorted) sortedResults else unsortedResults
+
+  /** The single boolean result of these results */
+  override def booleanResult = graph.getValue(resultSet, RS.Boolean) match {
+    case l: Literal => l.text.toBoolean
+    case _ => false
+  }
+
+  /** Gets the list of bindings, in defined order */
+  private def sortedResults = {
+    val (indexed, arrSize) = indexMapped
+    val res = new Array[Map[String,ObjectNode]](arrSize)
+    indexed.foreach(t => res.update(t._1 - 1, t._2))
+    res.toList
+  }
+
+  /**
+   * Returns a tuple containing:
+   * first: A Map of index location to the binding that belongs at that location.
+   * second: The size of the required array for holding results.
+   * We expect that the size of the required array will be the same as the size of
+   * the Map, but this can be violated if there are spaces in the array.
+   */
+  private def indexMapped = {
+    var maxIndex = 0
+    (Map() ++ (for (SubjectNode(soln) <- solutionList) yield {
+      val i = graph.getValue(soln, RS.Index).asInstanceOf[Literal].text.toInt
+      if (i > maxIndex) maxIndex = i
+      (i, Map() ++ (
+        for (SubjectNode(bindingNode) <- graph.getValues(soln, RS.Binding); LiteralImpl(v) <- graph.getValues(bindingNode, RS.Variable)) yield {
+          val value = graph.getValue(bindingNode, RS.Value)
+          (v.text, value)
+        }
+      ))
+    }), maxIndex)
+  }
+
+  private def unsortedResults = {
+    Set() ++ (for (SubjectNode(soln) <- solutionList) yield {
+      Map() ++ (
+        for (SubjectNode(bindingNode) <- graph.getValues(soln, RS.Binding); LiteralImpl(v) <- graph.getValues(bindingNode, RS.Variable)) yield {
+          val value = graph.getValue(bindingNode, RS.Value)
+          (v.text, value)
+        }
+      )
+    })
+  }
+}

Added: projects/SparqlTester/trunk/src/org/duraspace/rdf/vocab/RS.scala
===================================================================
--- projects/SparqlTester/trunk/src/org/duraspace/rdf/vocab/RS.scala	                        (rev 0)
+++ projects/SparqlTester/trunk/src/org/duraspace/rdf/vocab/RS.scala	2009-11-24 19:56:19 UTC (rev 1853)
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2009 DuraSpace.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.duraspace.rdf.vocab
+
+import java.net.URI;
+
+object RS {
+
+  /** The QName prefix for ResultSet */
+  val Prefix = "rs"
+
+  /** The ResultSet namespace. */
+  val Base = "http://www.w3.org/2001/sw/DataAccess/tests/result-set#"
+
+  /** The type for result sets */
+  val ResultSet = URI.create(Base + "ResultSet")
+
+  /** The property for refering to result variables */
+  val ResultVariable = URI.create(Base + "resultVariable")
+
+  /** The property for identifying solutions */
+  val Solution = URI.create(Base + "solution")
+
+  /** The property for identifying bindings for a solution */
+  val Binding = URI.create(Base + "binding")
+
+  /** The property for linking a binding to its variable name */
+  val Variable = URI.create(Base + "variable")
+
+  /** The property for linking a binding to its value */
+  val Value = URI.create(Base + "value")
+
+  /** The property for indexing a binding in order */
+  val Index = URI.create(Base + "index")
+
+  /** The property for linking a boolean result to results */
+  val Boolean = URI.create(Base + "boolean")
+
+}




More information about the Mulgara-svn mailing list