Browse Source

Added support for non-string primitive constants...

Added support for non-string primitive constants, even though that’s
not part of the R2RML specification.
Christophe Debruyne 6 years ago
parent
commit
e35faf1ed6

+ 7 - 9
src/r2rml/model/ObjectMap.java

@@ -57,6 +57,8 @@ public class ObjectMap extends TermMap {
 			}
 
 			if(languages.size() == 1 && datatypes.size() == 1) {
+				System.out.println(languages);
+				System.out.println(datatypes);
 				logger.error("A TermMap cannot have both a rr:datatype and rr:language.");
 				logger.error(description);
 				return false;
@@ -89,18 +91,14 @@ public class ObjectMap extends TermMap {
 		return true;
 	}
 
-
-
 	@Override
 	protected RDFNode distillConstant(RDFNode node) {
 		// If the constant-valued term map is an object map, then its 
 		// constant value must be an IRI or literal.
-		if(isConstantValuedTermMap()) {
-			if(!node.isURIResource() && !node.isLiteral()) {
-				logger.error("Constant for ObjectMap must be an IRI or literal.");
-				logger.error(description);
-				return null;
-			}
+		if(!node.isURIResource() && !node.isLiteral()) {
+			logger.error("Constant for ObjectMap must be an IRI or literal.");
+			logger.error(description);
+			return null;
 		}
 
 		return node;
@@ -128,7 +126,7 @@ public class ObjectMap extends TermMap {
 
 		if(isColumnValuedTermMap() || datatypes.size() > 0 || languages.size() > 0) 
 			return R2RML.LITERAL;
-		
+
 		/* We assume that functions are also by default literals */
 		if(isFunctionValuedTermMap())
 			return R2RML.LITERAL;

+ 8 - 2
src/r2rml/model/R2RMLMappingFactory.java

@@ -34,18 +34,24 @@ public class R2RMLMappingFactory {
 	private static String CONSTRUCTPMAPS = "PREFIX rr: <http://www.w3.org/ns/r2rml#> CONSTRUCT { ?x rr:predicateMap [ rr:constant ?y ]. } WHERE { ?x rr:predicate ?y. }";
 	private static String CONSTRUCTGMAPS = "PREFIX rr: <http://www.w3.org/ns/r2rml#> CONSTRUCT { ?x rr:graphMap [ rr:constant ?y ]. } WHERE { ?x rr:graph ?y. }";
 
+	// MAKE CONSTANTS EXPLICITELY LITERALS TO DEAL WITH TYPED CONSTANTS
+	// EVEN THOUGH IT IS OUT OF THE SPEC
+	private static String CONSTRUCTLITERAL = "PREFIX rr: <http://www.w3.org/ns/r2rml#> CONSTRUCT { ?x rr:termType rr:Literal . } WHERE { ?x rr:constant ?y . FILTER (isLiteral(?y)) }" ;
+	
 	public static R2RMLMapping createR2RMLMapping(String mappingFile, String baseIRI) {
 		R2RMLMapping mapping = new R2RMLMapping();
 
 		// We reason over the mapping to facilitate retrieval of the mappings
 		Model data = FileManager.get().loadModel(mappingFile);
-
+		
 		// We construct triples to replace the shortcuts.
 		data.add(QueryExecutionFactory.create(CONSTRUCTSMAPS, data).execConstruct());
 		data.add(QueryExecutionFactory.create(CONSTRUCTOMAPS, data).execConstruct());
 		data.add(QueryExecutionFactory.create(CONSTRUCTPMAPS, data).execConstruct());
 		data.add(QueryExecutionFactory.create(CONSTRUCTGMAPS, data).execConstruct());
-
+		
+		data.add(QueryExecutionFactory.create(CONSTRUCTLITERAL, data).execConstruct());
+		
 		Model schema = ModelFactory.createDefaultModel();
 		schema.read(R2RMLMappingFactory.class.getResourceAsStream("/r2rml.rdf"), null);
 

+ 9 - 3
src/r2rml/model/TermMap.java

@@ -17,6 +17,7 @@ import org.apache.jena.datatypes.RDFDatatype;
 import org.apache.jena.enhanced.UnsupportedPolymorphismException;
 import org.apache.jena.iri.IRI;
 import org.apache.jena.iri.IRIFactory;
+import org.apache.jena.rdf.model.Literal;
 import org.apache.jena.rdf.model.RDFList;
 import org.apache.jena.rdf.model.RDFNode;
 import org.apache.jena.rdf.model.Resource;
@@ -58,7 +59,7 @@ public abstract class TermMap extends R2RMLResource {
 	private static Map<Object, Resource> blankNodeMap = new HashMap<Object, Resource>();
 
 	private String template;
-	private RDFNode constant;
+	protected RDFNode constant;
 	private String column;
 	private FunctionCall functionCall;
 
@@ -236,8 +237,8 @@ public abstract class TermMap extends R2RMLResource {
 	protected abstract boolean isChosenTermTypeValid();
 
 	/**
-	 * True if the conditions for constant values for one of the TermMap's subclasses
-	 * are met.
+	 * Returns RDF term if the conditions for constant values for one of the TermMap's 
+	 * subclasses are met. Only to be called if a TermMap has a constant.
 	 * @return 
 	 */
 	protected abstract RDFNode distillConstant(RDFNode node);
@@ -376,9 +377,13 @@ public abstract class TermMap extends R2RMLResource {
 				RDFDatatype d = R2RMLTypeMapper.getTypeByName(datatype);
 				return ResourceFactory.createTypedLiteral(value.toString(), d);
 			}
+			if(value instanceof Literal) {
+				return (Literal) value ;
+			}
 			return ResourceFactory.createTypedLiteral(value);
 		}
 		return null;
+		
 	}
 
 	/**
@@ -410,6 +415,7 @@ public abstract class TermMap extends R2RMLResource {
 	private Object getValueForRDFTerm(Row row) throws R2RMLException {
 		if(isConstantValuedTermMap()) {
 			return constant;
+//			return constant.isLiteral() ? constant.asLiteral().getValue() : constant ;
 		} else if(isColumnValuedTermMap()) {
 			return row.getObject(column);
 		} else if(isTemplateValuedTermMap()) {

+ 33 - 0
test/resources/15.mapping.ttl

@@ -0,0 +1,33 @@
+@prefix rr: <http://www.w3.org/ns/r2rml#> .
+@prefix ex: <http://example.com/ns#> .
+@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
+@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
+
+<#TriplesMap1>
+    rr:logicalTable [ rr:tableName "EMP" ];
+    rr:subjectMap [
+        rr:template "http://data.example.com/employee/{EMPNO}" ;
+    ];
+    
+    rr:predicateObjectMap [
+		rr:predicate rdfs:label ;
+		rr:object "test-1"^^xsd:string ;
+		rr:object "test-2"^^<http://www.w3.org/2001/XMLSchema#string> ;
+		rr:object "test-3" ;
+		rr:object "test-4"@en ;
+		rr:object 'test-5'@fr ;
+		rr:object "test-6"@fr-be ;
+    ] ;
+    
+    rr:predicateObjectMap [
+		rr:predicate ex:testNumeric ;
+		rr:object 2 ;			# xsd:integer                                                                      
+		rr:object 4.002602 ;	# xsd:decimal                                                                      
+		rr:object 1.663E-4 ;	# xsd:double  
+    ] ;
+    
+    rr:predicateObjectMap [
+		rr:predicate ex:testBoolean ;
+		rr:object false ;		# xsd:obolean                                                                      
+    ] ;
+    .

+ 108 - 0
test/test/TestR2RMLConstants.java

@@ -0,0 +1,108 @@
+package test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLNonTransientConnectionException;
+import java.sql.Statement;
+
+import org.apache.jena.rdf.model.Model;
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Logger;
+import org.junit.BeforeClass;
+
+import junit.framework.TestCase;
+import r2rml.engine.Configuration;
+import r2rml.engine.R2RMLException;
+import r2rml.engine.R2RMLProcessor;
+
+/**
+ * Unit test for testing the functionality of this implementation using an
+ * in memory database, focussing on constants.
+ * 
+ * @author Christophe Debruyne
+ *
+ */
+public class TestR2RMLConstants extends TestCase {
+
+	private static Logger logger = Logger.getLogger(TestR2RMLConstants.class.getName());
+	private static String connectionURL = "jdbc:derby:memory:testing";
+
+	public TestR2RMLConstants(String testName) {
+		super(testName);
+	}
+
+	@BeforeClass
+	public static void init() throws Exception {
+		// Log4J junit configuration.
+		BasicConfigurator.configure();
+	}
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+
+		try {
+			logger.info("Starting in-memory database for unit tests");
+			Class.forName("org.apache.derby.jdbc.EmbeddedDriver");
+			DriverManager.getConnection(connectionURL + ";create=true").close();
+		} catch (Exception ex) {
+			ex.printStackTrace();
+			fail("Exception during database startup.");
+		}
+		try {
+			Connection connection = DriverManager.getConnection(connectionURL);
+			Statement statement = connection.createStatement();
+			statement.execute("CREATE TABLE DEPT(DEPTNO INT PRIMARY KEY, DNAME VARCHAR(30), LOC VARCHAR(30))");
+			statement.execute("CREATE TABLE EMP(EMPNO INT PRIMARY KEY, ENAME VARCHAR(100), JOB VARCHAR(20), DEPTNO INT, FOREIGN KEY (DEPTNO) REFERENCES DEPT(DEPTNO))");
+			statement.execute("INSERT INTO DEPT VALUES (10, 'APPSERVER', 'NEW YORK')");
+			statement.execute("INSERT INTO EMP VALUES (7369, 'SMITH', 'CLERK', 10)");
+
+			statement.execute("CREATE TABLE DEPT2(DEPTNO INT, DNAME VARCHAR(30), LOC VARCHAR(30))");
+			statement.execute("CREATE TABLE EMP2(EMPNO INT, ENAME VARCHAR(100), JOB VARCHAR(20))");
+			statement.execute("CREATE TABLE EMP2DEPT(EMPNO INT, DEPTNO INT)");
+			statement.execute("INSERT INTO DEPT2 VALUES (10, 'APPSERVER', 'NEW YORK')");
+			statement.execute("INSERT INTO DEPT2 VALUES (20, 'RESEARCH', 'BOSTON')");
+			statement.execute("INSERT INTO EMP2 VALUES (7369, 'SMITH', 'CLERK')");
+			statement.execute("INSERT INTO EMP2 VALUES (7369, 'SMITH', 'NIGHTGUARD')");
+			statement.execute("INSERT INTO EMP2 VALUES (7400, 'JONES', 'ENGINEER')");
+			statement.execute("INSERT INTO EMP2DEPT VALUES (7369, 10)");
+			statement.execute("INSERT INTO EMP2DEPT VALUES (7369, 20)");
+			statement.execute("INSERT INTO EMP2DEPT VALUES (7400, 10)");
+			statement.close();
+			connection.close();
+
+		} catch (Exception ex) {
+			ex.printStackTrace();
+			fail("Failure setting up the database.");
+		}
+	}
+
+	@Override
+	protected void tearDown() throws Exception {
+		super.tearDown();
+		logger.info("Stopping in-memory database.");
+		try {
+			DriverManager.getConnection(connectionURL + ";drop=true").close();
+		} catch (SQLNonTransientConnectionException ex) {
+			if (ex.getErrorCode() != 45000) {
+				throw ex;
+			}
+			// Shutdown success
+		}
+	}
+	
+	/**
+	 * Testing adhoc datatypes...
+	 * @throws R2RMLException
+	 */
+	public void testConstants() throws R2RMLException {
+		Configuration configuration = new Configuration();
+		configuration.setMappingFile("./test/resources/15.mapping.ttl");
+		configuration.setConnectionURL(connectionURL);
+		R2RMLProcessor engine = new R2RMLProcessor(configuration);
+		engine.execute();
+		Model model = engine.getDataset().getDefaultModel();
+		model.write(System.out, "RDF/XML");	
+	}
+
+}