Browse Source

Support for basic column case

Christophe Debruyne 8 years ago
parent
commit
4804ab8044

+ 1 - 0
src/r2rml/engine/RRF.java

@@ -25,5 +25,6 @@ public final class RRF {
 	
 	// Properties for Containers and Collections
 	public static final Property gather = ResourceFactory.createProperty(NS + "gather");
+	public static final Property collectAs = ResourceFactory.createProperty(NS + "collectAs");
 	
 }

+ 102 - 0
src/r2rml/model/CollectUtil.java

@@ -0,0 +1,102 @@
+package r2rml.model;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jena.rdf.model.Container;
+import org.apache.jena.rdf.model.ModelFactory;
+import org.apache.jena.rdf.model.Property;
+import org.apache.jena.rdf.model.RDFNode;
+import org.apache.jena.rdf.model.Resource;
+import org.apache.jena.vocabulary.RDF;
+
+public class CollectUtil {
+
+	private static Map<String, ObjectSet> object_set_map = new HashMap<String, ObjectSet>();
+	private static Map<String, PropertySet> property_set_map = new HashMap<String, PropertySet>();
+	private static Map<String, GraphSet> graph_set_map = new HashMap<String, GraphSet>();
+	private static Map<String, Collectable> objectMap_map = new HashMap<String, Collectable>();
+	private static Map<String, Resource> subject_map = new HashMap<String, Resource>();
+	
+	public static void collect(PredicateObjectMap opm, Collectable om, Resource subject, RDFNode o, List<Property> predicates, Set<String> pogs) {
+		String pom_om_sub = opm.toString() + om.toString() + subject;
+		
+		if(!object_set_map.containsKey(pom_om_sub)) {
+			object_set_map.put(pom_om_sub, new ObjectSet());
+			property_set_map.put(pom_om_sub, new PropertySet());
+			graph_set_map.put(pom_om_sub, new GraphSet());
+			objectMap_map.put(pom_om_sub, om);
+			subject_map.put(pom_om_sub, subject);
+		}
+		
+		object_set_map.get(pom_om_sub).add(o);
+		property_set_map.get(pom_om_sub).addAll(predicates);
+		graph_set_map.get(pom_om_sub).addAll(pogs);
+	}
+
+	public static Set<String> getCollectedKeys() {
+		return object_set_map.keySet();
+	}
+
+	public static RDFNode getObject(String key) {
+		Collectable om = objectMap_map.get(key);
+		ObjectSet os = object_set_map.get(key);
+		
+		if(om.getCollectAsTermType().equals(RDF.List)) {
+			return ModelFactory.createDefaultModel().createList(os.toArray(new RDFNode[] {}));
+		}
+		
+		Container c = null;
+		
+		if(om.getCollectAsTermType().equals(RDF.Bag))
+			c = ModelFactory.createDefaultModel().createBag();
+		else if(om.getCollectAsTermType().equals(RDF.Seq))
+			c = ModelFactory.createDefaultModel().createSeq();
+		else if(om.getCollectAsTermType().equals(RDF.Alt))
+			c = ModelFactory.createDefaultModel().createAlt();
+		else
+			return null;
+		
+		for(RDFNode o : os)
+			c.add(o);
+		
+		return c;
+	}
+
+	public static Resource getSubject(String key) {
+		return subject_map.get(key);
+	}
+
+	public static Set<String> getPredicateObjectGraphs(String key) {
+		return graph_set_map.get(key);
+	}
+
+	public static Set<Property> getPredicates(String key) {
+		return property_set_map.get(key);
+	}
+
+	public static void reset() {
+		object_set_map.clear();
+		property_set_map.clear();
+		graph_set_map.clear();
+		objectMap_map.clear();
+		subject_map.clear();
+	}
+
+}
+
+class ObjectSet extends LinkedHashSet<RDFNode> {
+	private static final long serialVersionUID = 1L;
+}
+
+class PropertySet extends HashSet<Property> {
+	private static final long serialVersionUID = 1L;
+}
+
+class GraphSet extends HashSet<String> {
+	private static final long serialVersionUID = 1L;
+}

+ 11 - 0
src/r2rml/model/Collectable.java

@@ -0,0 +1,11 @@
+package r2rml.model;
+
+import org.apache.jena.rdf.model.Resource;
+
+public interface Collectable {
+
+	public boolean hasCollactAs();
+
+	public Resource getCollectAsTermType();
+	
+}

+ 29 - 1
src/r2rml/model/ObjectMap.java

@@ -9,6 +9,7 @@ import org.apache.jena.vocabulary.RDF;
 import org.apache.log4j.Logger;
 
 import r2rml.engine.R2RML;
+import r2rml.engine.RRF;
 
 /**
  * ObjectMap Class.
@@ -19,16 +20,18 @@ import r2rml.engine.R2RML;
  * @version 0.2
  *
  */
-public class ObjectMap extends TermMap {
+public class ObjectMap extends TermMap implements Collectable {
 
 	private static Logger logger = Logger.getLogger(ObjectMap.class.getName());
 	private List<Statement> datatypes = null;
 	private List<Statement> languages = null;
+	private List<Statement> collectasslist = null;
 
 	public ObjectMap(Resource description, String baseIRI) {
 		super(description, baseIRI);
 		datatypes = description.listProperties(R2RML.datatype).toList();
 		languages = description.listProperties(R2RML.language).toList();
+		collectasslist = description.listProperties(RRF.collectAs).toList();
 	}
 
 	@Override
@@ -43,6 +46,23 @@ public class ObjectMap extends TermMap {
 			logger.error(description);
 			return false;
 		}
+		
+		if(collectasslist.size() > 1) {
+			logger.error("ObjectMap can only have at most one rrf:collectAs.");
+			logger.error(description);
+			return false;
+		} else if(collectasslist.size() == 1) {
+			RDFNode n = collectasslist.get(0).getObject();
+			if(!(n.isResource() && (
+					RDF.List.equals(n.asResource()) ||
+					RDF.Bag.equals(n.asResource()) ||
+					RDF.Seq.equals(n.asResource()) ||
+					RDF.Alt.equals(n.asResource())))) {
+				logger.error("rrf:collectAs must refer to RDF container or collection.");
+				logger.error(description);
+				return false;
+			}
+		}
 
 		if(isTermTypeLiteral()) {
 			if(datatypes.size() > 1) {
@@ -138,4 +158,12 @@ public class ObjectMap extends TermMap {
 
 		return R2RML.IRI;
 	}
+
+	public boolean hasCollactAs() {
+		return collectasslist.size() == 1;
+	}
+
+	public Resource getCollectAsTermType() {
+		return collectasslist.get(0).getResource();
+	}
 }

+ 33 - 1
src/r2rml/model/RefObjectMap.java

@@ -6,9 +6,11 @@ import java.util.List;
 import org.apache.jena.rdf.model.RDFNode;
 import org.apache.jena.rdf.model.Resource;
 import org.apache.jena.rdf.model.Statement;
+import org.apache.jena.vocabulary.RDF;
 import org.apache.log4j.Logger;
 
 import r2rml.engine.R2RML;
+import r2rml.engine.RRF;
 
 /**
  * RefObjectMap Class.
@@ -17,18 +19,21 @@ import r2rml.engine.R2RML;
  * @version 0.1
  *
  */
-public class RefObjectMap extends R2RMLResource {
+public class RefObjectMap extends R2RMLResource implements Collectable {
 	
 	private static Logger logger = Logger.getLogger(RefObjectMap.class.getName());
 
 	private List<Join> joins = new ArrayList<Join>();
 	
+	private List<Statement> collectasslist = null;
+	
 	// We keep track of the parent via a resource, as it will be processed
 	// by the engine.
 	private Resource parentTriplesMap = null;
 	
 	public RefObjectMap(Resource description) {
 		super(description);
+		collectasslist = description.listProperties(RRF.collectAs).toList();
 	}
 	
 	public List<Join> getJoins() {
@@ -75,7 +80,34 @@ public class RefObjectMap extends R2RMLResource {
 			joins.add(join);
 		}
 		
+		if(collectasslist.size() > 1) {
+			logger.error("ObjectMap can only have at most one rrf:collectAs.");
+			logger.error(description);
+			return false;
+		} else if(collectasslist.size() == 1) {
+			RDFNode n = collectasslist.get(0).getObject();
+			if(!(n.isResource() && (
+					RDF.List.equals(n.asResource()) ||
+					RDF.Bag.equals(n.asResource()) ||
+					RDF.Seq.equals(n.asResource()) ||
+					RDF.Alt.equals(n.asResource())))) {
+				logger.error("rrf:collectAs must refer to RDF container or collection.");
+				logger.error(description);
+				return false;
+			}
+		}
+		
 		return true;
 	}
+
+	@Override
+	public boolean hasCollactAs() {
+		return collectasslist.size() == 1;
+	}
+
+	@Override
+	public Resource getCollectAsTermType() {
+		return collectasslist.get(0).getResource();
+	}
 	
 }

+ 88 - 51
src/r2rml/model/TriplesMap.java

@@ -7,13 +7,10 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.jena.query.Dataset;
-import org.apache.jena.rdf.model.Alt;
-import org.apache.jena.rdf.model.Bag;
 import org.apache.jena.rdf.model.Property;
 import org.apache.jena.rdf.model.RDFList;
 import org.apache.jena.rdf.model.RDFNode;
 import org.apache.jena.rdf.model.Resource;
-import org.apache.jena.rdf.model.Seq;
 import org.apache.jena.rdf.model.Statement;
 import org.apache.jena.vocabulary.RDF;
 import org.apache.log4j.Logger;
@@ -185,16 +182,6 @@ public class TriplesMap extends R2RMLResource {
 								predicates.add(p);
 						}
 
-						// Let objects be the set of generated RDF terms that result 
-						// from applying each of the predicate-object map's object 
-						// maps (but not referencing object maps) to row
-						List<RDFNode> objects = new ArrayList<RDFNode>();
-						for(ObjectMap om : opm.getObjectMaps()) {
-							RDFNode o = om.generateRDFTerm(row); 
-							if(o != null)
-								objects.add(o);
-						}
-
 						// Let pogm be the set of graph maps of the predicate-object 
 						// map. Let predicate-object_graphs be the set of generated 
 						// RDF terms that result from applying each graph map in pogm 
@@ -209,16 +196,45 @@ public class TriplesMap extends R2RMLResource {
 						// Target graphs: If sgm and pogm are empty: rr:defaultGraph; 
 						// otherwise: union of subject_graphs and predicate-object_graphs
 						pogs.addAll(subjectGraphs);
+						
+						// Let objects be the set of generated RDF terms that result 
+						// from applying each of the predicate-object map's object 
+						// maps (but not referencing object maps) to row
+						List<RDFNode> objects = new ArrayList<RDFNode>();
+						for(ObjectMap om : opm.getObjectMaps()) {
+							RDFNode o = om.generateRDFTerm(row); 
+							if(o != null) {
+								if(om.hasCollactAs()) {
+									CollectUtil.collect(opm, om, subject, o, predicates, pogs);
+								} else {									
+									objects.add(o);
+								}
+							}
+						}
+
 						for(Property p : predicates) {
 							for(RDFNode o : objects) {
 								addTriplesToDataset(dataset, subject, p, o, pogs);
 							}
 						}
 
-
 					}
 				}
 			} // end while
+			
+			// BEGIN SUPPORT FOR THE COLUMN CASE -- OBJECT MAP
+			for(String key : CollectUtil.getCollectedKeys()) {
+				RDFNode o = CollectUtil.getObject(key);
+				Resource subject = CollectUtil.getSubject(key);
+				Set<String> pogs = CollectUtil.getPredicateObjectGraphs(key);
+				Set<Property> predicates = CollectUtil.getPredicates(key);
+				
+				for(Property p : predicates) {
+					addTriplesToDataset(dataset, subject, p, o, pogs);
+				}
+			}
+			CollectUtil.reset();
+			// END SUPPORT FOR THE COLUMN CASE -- OBJECT MAP
 
 			// For each referencing object map of a predicate-object map of 
 			// the triples map, apply the following steps:
@@ -247,49 +263,67 @@ public class TriplesMap extends R2RMLResource {
 						// from applying psm to parent_row
 						Resource object = psm.generateRDFTerm(parent_row);
 						
-						// if subject or object is NULL, don't generate triples
-						if(subject != null || object != null) {
-
-							// Let predicates be the set of generated RDF terms that result 
-							// from applying each of the predicate-object map's predicate 
-							// maps to child_row
-							List<Property> predicates = new ArrayList<Property>();
-							for(PredicateMap pm : opm.getPredicateMaps()) {
-								Property p = pm.generateRDFTerm(child_row);
-								if(p != null)
-									predicates.add(p);
-							}
+						// Let predicates be the set of generated RDF terms that result 
+						// from applying each of the predicate-object map's predicate 
+						// maps to child_row
+						List<Property> predicates = new ArrayList<Property>();
+						for(PredicateMap pm : opm.getPredicateMaps()) {
+							Property p = pm.generateRDFTerm(child_row);
+							if(p != null)
+								predicates.add(p);
+						}
 
-							// Let subject_graphs be the set of generated RDF terms 
-							// that result from applying each graph map of sgm to 
-							// child_row
-							Set<String> subjectGraphs = new HashSet<String>();
-							for(GraphMap gm : sgm) {
-								Resource gmiri = gm.generateRDFTerm(child_row);
-								if(gmiri != null)
-									subjectGraphs.add(gmiri.getURI());
-							}
+						// Let subject_graphs be the set of generated RDF terms 
+						// that result from applying each graph map of sgm to 
+						// child_row
+						Set<String> subjectGraphs = new HashSet<String>();
+						for(GraphMap gm : sgm) {
+							Resource gmiri = gm.generateRDFTerm(child_row);
+							if(gmiri != null)
+								subjectGraphs.add(gmiri.getURI());
+						}
 
-							// Let predicate-object_graphs be the set of generated 
-							// RDF terms that result from applying each graph map in 
-							// pogm to child_row
-							Set<String> pogs = new HashSet<String>();
-							for(GraphMap gm : pogm) {
-								Resource gmiri = gm.generateRDFTerm(child_row);
-								if(gmiri != null)
-									pogs.add(gmiri.getURI());
-							}
+						// Let predicate-object_graphs be the set of generated 
+						// RDF terms that result from applying each graph map in 
+						// pogm to child_row
+						Set<String> pogs = new HashSet<String>();
+						for(GraphMap gm : pogm) {
+							Resource gmiri = gm.generateRDFTerm(child_row);
+							if(gmiri != null)
+								pogs.add(gmiri.getURI());
+						}
 
-							// Target graphs: If sgm and pogm are empty: rr:defaultGraph; 
-							// otherwise: union of subject_graphs and predicate-object_graphs
-							pogs.addAll(subjectGraphs);
-							for(Property p : predicates) {
-								addTriplesToDataset(dataset, subject, p, object, pogs);
+						// Target graphs: If sgm and pogm are empty: rr:defaultGraph; 
+						// otherwise: union of subject_graphs and predicate-object_graphs
+						pogs.addAll(subjectGraphs);
+						
+						// if subject or object is NULL, don't generate triples
+						if(subject != null || object != null) {
+							if(rof.hasCollactAs()) {
+								CollectUtil.collect(opm, rof, subject, object, predicates, pogs);
+							} else {
+								for(Property p : predicates) {
+									addTriplesToDataset(dataset, subject, p, object, pogs);
+								}
 							}
 						}
 					}
 				}
 			}
+			
+			// BEGIN SUPPORT FOR THE COLUMN CASE -- REF OBJECT MAP
+			for(String key : CollectUtil.getCollectedKeys()) {
+				RDFNode o = CollectUtil.getObject(key);
+				Resource subject = CollectUtil.getSubject(key);
+				Set<String> pogs = CollectUtil.getPredicateObjectGraphs(key);
+				Set<Property> predicates = CollectUtil.getPredicates(key);
+				
+				for(Property p : predicates) {
+					addTriplesToDataset(dataset, subject, p, o, pogs);
+				}
+			}
+			CollectUtil.reset();
+			// END SUPPORT FOR THE COLUMN CASE -- REF OBJECT MAP
 
 			logger.info("TriplesMap " + description + ": generated triples = " + count);
 
@@ -350,9 +384,12 @@ public class TriplesMap extends R2RMLResource {
 	}
 
 	private boolean isListOrContainer(RDFNode o) {
-		if(o.isResource()) {
+		if(o.isResource() && o.getModel() != null) {
 			Resource r = o.asResource();
-			if(r.canAs(RDFList.class) || r.canAs(Bag.class) || r.canAs(Seq.class) || r.canAs(Alt.class)) {
+			if(r.canAs(RDFList.class) || 
+				r.hasProperty(RDF.type, RDF.Bag) || 
+				r.hasProperty(RDF.type, RDF.Seq) || 
+				r.hasProperty(RDF.type, RDF.Alt)) {	
 				return true;
 			}
 		}

+ 51 - 1
test/resources/COL01.mapping.ttl

@@ -18,8 +18,58 @@
         		[ rr:column "FNAME" ] 
         		[ rr:column "LNAME" ]  
         	) ;
-        	rr:termType rdf:List ;
+        	rr:termType rdf:Bag ;
         ];
     ]
     
+    .
+    
+ <#TriplesMap2>
+    rr:logicalTable [ rr:tableName "PET" ];
+
+    rr:subjectMap [
+        rr:template "http://data.example.com/person/{OWNER}";
+    ];
+    
+    rr:predicateObjectMap [
+        rr:predicate ex:owns;
+        rr:objectMap [ 
+        	rr:template "http://data.example.com/pet/{ID}";
+        ];
+		rr:objectMap [ 
+        	rr:column "ID";
+        	rrf:collectAs rdf:List ;
+        ];
+    ];
+    
+    rr:predicateObjectMap [
+        rr:predicate ex:ownsSeqSeperate;
+        rr:objectMap [ 
+        	rr:template "http://data.example.com/pet/{ID}";
+        	rrf:collectAs rdf:Seq ;
+        ];
+    ] ;
+    
+	rr:predicateObjectMap [
+        rr:predicate ex:ownsBagRefObjectMap;
+        rr:objectMap [ 
+        	rr:parentTriplesMap <#PET>;
+            rr:joinCondition [
+                rr:child "ID";
+                rr:parent "ID";
+            ];
+        	rrf:collectAs rdf:Bag ;
+        ];
+    ]
+    
+    .
+    
+ <#PET>
+    rr:logicalTable [ rr:tableName "PET" ];
+
+    rr:subjectMap [
+        rr:template "http://data.example.com/pet-test/{ID}";
+        rr:class ex:Pet ;
+    ];
+    
     .

+ 1 - 0
test/test/TestR2RML.java

@@ -106,6 +106,7 @@ public class TestR2RML extends TestCase {
 		Model model = engine.getDataset().getDefaultModel();
 		Model target = ModelFactory.createDefaultModel();
 		target.read("./test/resources/01.output.ttl");
+		model.write(System.out, "TURTLE");
 		assertEquals(true, model.difference(target).isEmpty());
 		assertEquals(true, target.difference(model).isEmpty());	
 	}

+ 0 - 3
test/test/TestR2RMLCOL.java

@@ -17,9 +17,6 @@ import r2rml.engine.R2RMLProcessor;
  */
 public class TestR2RMLCOL extends TestCase {
 
-	//private static Logger logger = Logger.getLogger(TestR2RMLCSV.class.getName());
-	//private static String connectionURL = "jdbc:derby:memory:testing";
-
 	public TestR2RMLCOL(String testName) {
 		super(testName);
 	}