diff --git a/CHANGELOG.md b/CHANGELOG.md
index 148a5c8e..29ec3ee8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## Unreleased
+### Changed
+- RMLMapper crashes when parent Triples Map cannot be found (https://github.com/RMLio/rmlmapper-java/issues/270). This changes behaviour of RMLMapper (log error instead of stopping), but is still valid RML Processor behaviour.
+
## [8.1.0] - 2025-12-23
### Added
diff --git a/buildNumber.properties b/buildNumber.properties
index a30686cb..a2d8f523 100644
--- a/buildNumber.properties
+++ b/buildNumber.properties
@@ -1,3 +1,3 @@
#maven.buildNumber.plugin properties file
-#Thu Dec 11 14:28:34 CET 2025
-buildNumber0=379
+#Tue Dec 23 11:40:14 CET 2025
+buildNumber0=380
diff --git a/pom.xml b/pom.xml
index 3defbb85..da672038 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
be.ugent.rml
rmlmapper
RMLMapper
- 8.1.0
+ 8.1.1-SNAPSHOT
The RMLMapper executes RML rules to generate high quality Linked Data from multiple originally (semi-)structured data sources.
diff --git a/src/main/java/be/ugent/rml/MappingOptimizer.java b/src/main/java/be/ugent/rml/MappingOptimizer.java
index 70be3760..3b4b9ac2 100644
--- a/src/main/java/be/ugent/rml/MappingOptimizer.java
+++ b/src/main/java/be/ugent/rml/MappingOptimizer.java
@@ -64,88 +64,94 @@ private void eliminateSelfJoins() {
for (Quad refObjectMapQuad : refObjectMapsQuads) {
Term parentTriplesMap = refObjectMapQuad.getObject();
Term childObjectMap = refObjectMapQuad.getSubject();
- Term parentLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);
- Term childPredicateObjectMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "objectMap"), childObjectMap)).get(0);
- Term childTriplesMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "predicateObjectMap"), childPredicateObjectMap)).get(0);
- Term childLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(childTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);
- // check if the logical sources are the same
- if (childLogicalSource.equals(parentLogicalSource)) {
- List joinConditions = Utils.getObjectsFromQuads(rmlStore.getQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "joinCondition"), null));
+ try {
+ Term parentLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);
+ Term childPredicateObjectMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "objectMap"), childObjectMap)).get(0);
+ Term childTriplesMap = Utils.getSubjectsFromQuads(rmlStore.getQuads(null, new NamedNode(NAMESPACES.RML2 + "predicateObjectMap"), childPredicateObjectMap)).get(0);
+ Term childLogicalSource = Utils.getObjectsFromQuads(rmlStore.getQuads(childTriplesMap, new NamedNode(NAMESPACES.RML2 + "logicalSource"), null)).get(0);
- List parentSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
- Term parentSubjectMap = null;
- if (!parentSubjectMaps.isEmpty()) {
- parentSubjectMap = parentSubjectMaps.get(0);
- }
+ // check if the logical sources are the same
+ if (childLogicalSource.equals(parentLogicalSource)) {
- boolean safeSelfJoinElimination = true;
-
- // if no join condition, we can safely eliminate the self-join
- // else we need more checks
- if (parentSubjectMap != null && !joinConditions.isEmpty()) {
- // we can eliminate a self-join when all join conditions have equal references and all references for the parent subject or all reference for the related child triple come back in the join conditions
- // 1. check if all join references are equal
- List joinReferences = new ArrayList<>();
- for (Term joinCondition : joinConditions) {
- String parent = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "parent"), null)).get(0).getValue();
- String child = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "child"), null)).get(0).getValue();
- if (child.equals(parent)) {
- joinReferences.add(child);
- } else {
- safeSelfJoinElimination = false;
- }
+ List joinConditions = Utils.getObjectsFromQuads(rmlStore.getQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "joinCondition"), null));
+
+ List parentSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
+ Term parentSubjectMap = null;
+ if (!parentSubjectMaps.isEmpty()) {
+ parentSubjectMap = parentSubjectMaps.get(0);
}
- if (safeSelfJoinElimination) {
- // 2. check if all references for the parent subject come back in the join conditions
- boolean safeTerms = hasSafeReferences(parentSubjectMap, joinReferences);
- if(!safeTerms) {
- // if not all references for the parent subject come back in the join conditions,
- // 3. check if all references for the related child terms come back in the join conditions
- // 3.1 check child subject
- List childSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
- if(!childSubjectMaps.isEmpty()) {
- safeTerms = hasSafeReferences(childSubjectMaps.get(0), joinReferences);
+
+ boolean safeSelfJoinElimination = true;
+
+ // if no join condition, we can safely eliminate the self-join
+ // else we need more checks
+ if (parentSubjectMap != null && !joinConditions.isEmpty()) {
+ // we can eliminate a self-join when all join conditions have equal references and all references for the parent subject or all reference for the related child triple come back in the join conditions
+ // 1. check if all join references are equal
+ List joinReferences = new ArrayList<>();
+ for (Term joinCondition : joinConditions) {
+ String parent = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "parent"), null)).get(0).getValue();
+ String child = getObjectsFromQuads(rmlStore.getQuads(joinCondition, new NamedNode(NAMESPACES.RML2 + "child"), null)).get(0).getValue();
+ if (child.equals(parent)) {
+ joinReferences.add(child);
} else {
- safeTerms = true;
+ safeSelfJoinElimination = false;
}
- //3.2 check child predicate (only make sense if the child subject was safe, otherwise we cannot eliminate the-self join)
- if (safeTerms) {
- List childPredicateMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(childPredicateObjectMap, new NamedNode(NAMESPACES.RML2 + "predicateMap"), null));
- if(!childPredicateMaps.isEmpty()) {
- safeTerms = hasSafeReferences(childPredicateMaps.get(0), joinReferences);
+ }
+ if (safeSelfJoinElimination) {
+ // 2. check if all references for the parent subject come back in the join conditions
+ boolean safeTerms = hasSafeReferences(parentSubjectMap, joinReferences);
+ if (!safeTerms) {
+ // if not all references for the parent subject come back in the join conditions,
+ // 3. check if all references for the related child terms come back in the join conditions
+ // 3.1 check child subject
+ List childSubjectMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(parentTriplesMap, new NamedNode(NAMESPACES.RML2 + "subjectMap"), null));
+ if (!childSubjectMaps.isEmpty()) {
+ safeTerms = hasSafeReferences(childSubjectMaps.get(0), joinReferences);
+ } else {
+ safeTerms = true;
+ }
+ //3.2 check child predicate (only make sense if the child subject was safe, otherwise we cannot eliminate the-self join)
+ if (safeTerms) {
+ List childPredicateMaps = Utils.getObjectsFromQuads(rmlStore.getQuads(childPredicateObjectMap, new NamedNode(NAMESPACES.RML2 + "predicateMap"), null));
+ if (!childPredicateMaps.isEmpty()) {
+ safeTerms = hasSafeReferences(childPredicateMaps.get(0), joinReferences);
+ }
}
}
- }
- // 4. if parent subject or all child terms are safe, the self join can be eliminated, else not
- if (!safeTerms) {
- safeSelfJoinElimination = false;
+ // 4. if parent subject or all child terms are safe, the self join can be eliminated, else not
+ if (!safeTerms) {
+ safeSelfJoinElimination = false;
+ }
}
}
- }
- if (safeSelfJoinElimination) {
- // now we rewrite the mapping file to eliminate the self-join
- boolean termTypeAdded = false;
- List parentSubjectMapQuads = rmlStore.getQuads(parentSubjectMap, null, null);
- for (Quad parentSubjectMapQuad : parentSubjectMapQuads) {
- Term predicate = parentSubjectMapQuad.getPredicate();
- if (predicate.equals(new NamedNode(NAMESPACES.FNML + "functionValue"))
- || predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))
- || predicate.equals(new NamedNode(NAMESPACES.RML2 + "reference"))
- || predicate.equals(new NamedNode(NAMESPACES.RML2 + "template"))
- || predicate.equals(new NamedNode(NAMESPACES.RML2 + "constant"))) {
- rmlStore.addQuad(childObjectMap, predicate, parentSubjectMapQuad.getObject());
+ if (safeSelfJoinElimination) {
+ // now we rewrite the mapping file to eliminate the self-join
+ boolean termTypeAdded = false;
+ List parentSubjectMapQuads = rmlStore.getQuads(parentSubjectMap, null, null);
+ for (Quad parentSubjectMapQuad : parentSubjectMapQuads) {
+ Term predicate = parentSubjectMapQuad.getPredicate();
+ if (predicate.equals(new NamedNode(NAMESPACES.FNML + "functionValue"))
+ || predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))
+ || predicate.equals(new NamedNode(NAMESPACES.RML2 + "reference"))
+ || predicate.equals(new NamedNode(NAMESPACES.RML2 + "template"))
+ || predicate.equals(new NamedNode(NAMESPACES.RML2 + "constant"))) {
+ rmlStore.addQuad(childObjectMap, predicate, parentSubjectMapQuad.getObject());
+ }
+ if (predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))) {
+ termTypeAdded = true;
+ }
}
- if (predicate.equals(new NamedNode(NAMESPACES.RML2 + "termType"))) {
- termTypeAdded = true;
+ rmlStore.removeQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "parentTriplesMap"), parentTriplesMap);
+ if (!termTypeAdded) {
+ rmlStore.addQuad(childObjectMap, new NamedNode(NAMESPACES.RML2 + "termType"), new NamedNode(NAMESPACES.RML2 + "IRI"));
}
}
- rmlStore.removeQuads(childObjectMap, new NamedNode(NAMESPACES.RML2 + "parentTriplesMap"), parentTriplesMap);
- if (!termTypeAdded) {
- rmlStore.addQuad(childObjectMap, new NamedNode(NAMESPACES.RML2 + "termType"), new NamedNode(NAMESPACES.RML2 + "IRI"));
- }
}
+ } catch (java.lang.IndexOutOfBoundsException e) {
+ continue;
}
}
}
diff --git a/src/main/java/be/ugent/rml/records/RecordsFactory.java b/src/main/java/be/ugent/rml/records/RecordsFactory.java
index 69480fb1..a61bb6d2 100644
--- a/src/main/java/be/ugent/rml/records/RecordsFactory.java
+++ b/src/main/java/be/ugent/rml/records/RecordsFactory.java
@@ -73,7 +73,8 @@ public List createRecords(Term triplesMap, QuadStore rmlStore) throws Ex
return getRecords(access, logicalSource, referenceFormulation, rmlStore);
} else {
- throw new Error("No Logical Source is found for " + triplesMap + ". Exactly one Logical Source is required per Triples Map.");
+ logger.error("No Logical Source is found for " + triplesMap + ". Exactly one Logical Source is required per Triples Map.");
+ return new ArrayList<>();
}
}