[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