Skip to content

Commit f0a5bb5

Browse files
author
Marco Grassi
committed
Merge branch 'ref-RML-to-MTL'
2 parents 260d584 + 60d2634 commit f0a5bb5

4 files changed

Lines changed: 105 additions & 59 deletions

File tree

src/main/java/com/cefriel/template/Main.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import javax.tools.ToolProvider;
3030
import java.io.File;
3131
import java.io.FileWriter;
32+
import java.io.InputStream;
3233
import java.net.URL;
3334
import java.net.URLClassLoader;
3435
import java.nio.file.Files;
@@ -181,7 +182,10 @@ public void exec() throws Exception {
181182
}
182183
}
183184
if(compileRML) {
184-
Util.validateRML(templatePath, verbose);
185+
try (InputStream rmlMappingStream = Files.newInputStream(templatePath))
186+
{
187+
Util.validateRML(rmlMappingStream, verbose);
188+
}
185189

186190
Reader compilerReader = TemplateFunctions.getRDFReaderFromFile(templatePath.toString());
187191
Map<String, Reader> compilerReaderMap = new HashMap<>();

src/main/java/com/cefriel/template/utils/RMLCompilerUtils.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,17 @@ public boolean checkReference(String s){
209209
return false;
210210
}
211211

212+
public String getBaseIRI(String turtle) {
213+
Pattern p = Pattern.compile("@base <([^<>]*)>");
214+
Matcher m = p.matcher(turtle);
215+
216+
if (m.find()) {
217+
return m.group(1);
218+
} else {
219+
return null;
220+
}
221+
}
222+
212223
/**
213224
* From rmlmapper <a href="https://github.com/RMLio/rmlmapper-java/blob/6492743f9c81523b6e9142c929d3aaecc78d67eb/src/main/java/be/ugent/rml/Utils.java#L634">...</a>
214225
*
@@ -223,15 +234,7 @@ public String getBaseIRI(Path rmlPath) {
223234
} catch (IOException e) {
224235
turtle = "";
225236
}
226-
227-
Pattern p = Pattern.compile("@base <([^<>]*)>");
228-
Matcher m = p.matcher(turtle);
229-
230-
if (m.find()) {
231-
return m.group(1);
232-
} else {
233-
return null;
234-
}
237+
return getBaseIRI(turtle);
235238
}
236239

237240
}

src/main/java/com/cefriel/template/utils/Util.java

Lines changed: 65 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package com.cefriel.template.utils;
1818

19+
import com.cefriel.template.TemplateExecutor;
1920
import com.cefriel.template.TemplateMap;
2021
import com.cefriel.template.io.Formatter;
2122
import com.cefriel.template.io.Reader;
@@ -30,9 +31,11 @@
3031
import org.apache.velocity.VelocityContext;
3132
import org.apache.velocity.app.VelocityEngine;
3233
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
34+
import org.apache.velocity.runtime.resource.loader.FileResourceLoader;
3335
import org.apache.velocity.tools.generic.*;
3436
import org.eclipse.rdf4j.common.exception.ValidationException;
3537
import org.eclipse.rdf4j.model.Model;
38+
import org.eclipse.rdf4j.model.base.CoreDatatype;
3639
import org.eclipse.rdf4j.model.vocabulary.RDF4J;
3740
import org.eclipse.rdf4j.model.vocabulary.SHACL;
3841
import org.eclipse.rdf4j.repository.RepositoryConnection;
@@ -45,6 +48,7 @@
4548
import org.slf4j.Logger;
4649
import org.slf4j.LoggerFactory;
4750

51+
import java.io.ByteArrayInputStream;
4852
import java.io.IOException;
4953
import java.io.InputStream;
5054
import java.nio.charset.StandardCharsets;
@@ -195,11 +199,16 @@ public static VelocityEngine createVelocityEngine(boolean templateInResources, b
195199
velocityEngine.setProperty("resource.loaders", "class");
196200
velocityEngine.setProperty("resource.loader.class.class",
197201
ClasspathResourceLoader.class.getName());
202+
} else{
203+
velocityEngine.setProperty("resource.loaders", "file");
204+
velocityEngine.setProperty("resource.loader.file.class", FileResourceLoader.class.getName());
205+
velocityEngine.setProperty("resource.loader.file.path", "");
198206
}
199207
velocityEngine.init();
200208
return velocityEngine;
201209
}
202-
public static void validateRML(Path templatePath, boolean verbose) {
210+
211+
public static void validateRML(InputStream rmlMapping, boolean verbose) {
203212

204213
ShaclSail shaclSail = new ShaclSail(new MemoryStore());
205214
SailRepository repository = new SailRepository(shaclSail);
@@ -208,33 +217,25 @@ public static void validateRML(Path templatePath, boolean verbose) {
208217
try (RepositoryConnection connection = repository.getConnection()) {
209218
try (InputStream shapesStream = Util.class.getResourceAsStream("/rml/core.ttl")) {
210219
Model rules = Rio.parse(shapesStream, RDFFormat.TURTLE);
211-
// cf. https://github.com/eclipse-rdf4j/rdf4j/discussions/4287
212220
rules.remove(null, SHACL.NAME, null);
213221
rules.remove(null, SHACL.DESCRIPTION, null);
214-
215222
connection.begin();
216223
connection.add(rules, RDF4J.SHACL_SHAPE_GRAPH);
217224
connection.commit();
218225
}
219-
220-
// Load RML
221-
try (InputStream dataStream = Files.newInputStream(templatePath)) {
222-
connection.begin();
223-
connection.add(dataStream, "", org.eclipse.rdf4j.rio.RDFFormat.TURTLE);
224-
225-
try {
226-
connection.commit();
227-
log.info("RML validated correctly");
228-
} catch (RepositoryException exception) {
229-
Throwable cause = exception.getCause();
230-
log.error("RML not valid");
231-
if (verbose)
232-
if (cause instanceof ValidationException) {
233-
Model validationReportModel = ((ValidationException) cause).validationReportAsModel();
234-
Rio.write(validationReportModel, System.out, RDFFormat.TURTLE);
235-
}
236-
throw exception;
226+
connection.begin();
227+
connection.add(rmlMapping, "", RDFFormat.TURTLE);
228+
try {
229+
connection.commit();
230+
log.info("RML validated correctly");
231+
} catch (RepositoryException exception) {
232+
Throwable cause = exception.getCause();
233+
log.error("RML not valid");
234+
if (verbose && cause instanceof ValidationException) {
235+
Model validationReportModel = ((ValidationException) cause).validationReportAsModel();
236+
Rio.write(validationReportModel, System.out, RDFFormat.TURTLE);
237237
}
238+
throw exception;
238239
}
239240
} catch (Exception e) {
240241
throw new RuntimeException(e);
@@ -243,6 +244,7 @@ public static void validateRML(Path templatePath, boolean verbose) {
243244
}
244245
}
245246

247+
246248
/**
247249
* Creates a new {@link VelocityContext} and populates it with the provided readers, template map, and template functions.
248250
* Additionally, it adds a set of common tools for mathematical operations, number formatting, date manipulation,
@@ -331,4 +333,46 @@ public static VelocityContext createVelocityContext(Reader reader, TemplateMap t
331333
public static VelocityContext createVelocityContext(Map<String, Reader> readers, TemplateMap templateMap) {
332334
return createVelocityContext(readers, templateMap, new TemplateFunctions());
333335
}
336+
337+
/**
338+
* Compiles an MTL mapping from the given RML file.
339+
*
340+
* @param mappingRML Path to the RML mapping file.
341+
* @param baseIri Base IRI to use if not found in the mapping.
342+
* @param basePath Base path for output files.
343+
* @param trimTemplate Whether to use the trimmed template.
344+
* @param verbose Enable verbose validation output.
345+
* @return Path to the compiled template.
346+
* @throws Exception if validation or compilation fails.
347+
*/
348+
public static Path compiledMTLMapping(InputStream mappingRML, String baseIri, Path basePath, boolean trimTemplate, boolean verbose) throws Exception {
349+
String mappingRMLString = inputStreamToString(mappingRML);
350+
Util.validateRML(new ByteArrayInputStream(mappingRMLString.getBytes(StandardCharsets.UTF_8)), verbose);
351+
Reader compilerReader = TemplateFunctions.getRDFReaderFromString(mappingRMLString, RDFFormat.TURTLE.toString());
352+
Map<String, Reader> compilerReaderMap = new HashMap<>();
353+
compilerReaderMap.put("reader", compilerReader);
354+
355+
try (InputStream rmlCompiler = trimTemplate
356+
? Util.class.getResourceAsStream("/rml/rml-compiler.vm.tmp.vm")
357+
: Util.class.getResourceAsStream("/rml/rml-compiler.vm")) {
358+
359+
RMLCompilerUtils rmlCompilerUtils = new RMLCompilerUtils();
360+
361+
Map<String, String> rmlMap = new HashMap<>();
362+
String baseIriRML = rmlCompilerUtils.getBaseIRI(mappingRMLString);
363+
baseIriRML = baseIriRML != null ? baseIriRML : baseIri;
364+
rmlMap.put("baseIRI", baseIriRML);
365+
rmlMap.put("basePath", basePath.toString() + "/");
366+
367+
Path compiledTemplatePath = Paths.get(basePath.toString(), "template.rml.vm");
368+
TemplateExecutor templateExecutor = new TemplateExecutor(false, false, true, null);
369+
return templateExecutor.executeMapping(
370+
compilerReaderMap,
371+
rmlCompiler,
372+
compiledTemplatePath,
373+
rmlCompilerUtils,
374+
new TemplateMap(rmlMap)
375+
);
376+
}
377+
}
334378
}

src/test/java/com/cefriel/template/RMLTests.java

Lines changed: 23 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.eclipse.rdf4j.rio.helpers.StatementCollector;
3030
import org.junit.jupiter.api.Test;
3131

32+
import java.io.InputStream;
3233
import java.io.StringReader;
3334
import java.nio.file.Files;
3435
import java.nio.file.Path;
@@ -40,54 +41,48 @@
4041

4142
public class RMLTests {
4243

43-
final static String FOLDER = "src/test/resources/rml/";
44-
private String resolvePath(String folder, String file) {
45-
return FOLDER + file;
46-
}
44+
final static Path FOLDER = Path.of("src/test/resources/rml/");
4745

4846
@Test
4947
public void invalidRMLTest() throws Exception {
50-
String folder = "rml";
51-
Path rmlMappings = Paths.get(resolvePath(folder, "invalid-mapping.ttl"));
52-
assertThrows(RuntimeException.class, () -> Util.validateRML(rmlMappings, false));
48+
Path rmlMappings = FOLDER.resolve(Path.of("invalid-mapping.ttl"));
49+
try (InputStream rmlMapping = Files.newInputStream(rmlMappings)) {
50+
assertThrows(RuntimeException.class,
51+
() -> Util.validateRML(rmlMapping, false));
52+
}
5353
}
5454

5555
@Test
5656
public void validRMLTest() throws Exception {
57+
Path rmlMapping = FOLDER.resolve(Path.of("mapping.ttl"));
58+
String expectedOutput = Files.readString(FOLDER.resolve("output.nq"));
5759

58-
String folder = "rml";
59-
String rmlMappings = resolvePath(folder, "mapping.ttl");
60-
61-
String expectedOutput = Files.readString(Paths.get(resolvePath(folder, "output.nq")));
60+
try (InputStream rmlMappingStream = Files.newInputStream(rmlMapping)) {
61+
Util.validateRML(rmlMappingStream, false);
62+
}
6263

63-
Util.validateRML(Paths.get(rmlMappings), false);
64-
65-
Reader compilerReader = TemplateFunctions.getRDFReaderFromFile(rmlMappings);
66-
Path rmlCompiler = Paths.get("rml/rml-compiler.vm");
67-
Path compiledTemplatePath = Paths.get(resolvePath(folder,"template.rml.vm"));
64+
Reader compilerReader = TemplateFunctions.getRDFReaderFromFile(rmlMapping.toString());
6865

6966
Map<String,String> rmlMap = new HashMap<>();
70-
rmlMap.put("basePath", FOLDER);
67+
rmlMap.put("basePath", null);
7168

72-
TemplateExecutor rmlTemplateExecutor = new TemplateExecutor(false, false, true, null);
7369
TemplateExecutor templateExecutor = new TemplateExecutor(false, false, false, null);
74-
rmlTemplateExecutor.executeMapping(Map.of("reader", compilerReader), rmlCompiler, compiledTemplatePath, new RMLCompilerUtils(), new TemplateMap(rmlMap));
75-
String result = templateExecutor.executeMapping(Map.of("reader", compilerReader), compiledTemplatePath);
76-
Files.delete(compiledTemplatePath);
77-
78-
Model resultModel = parseRDFString(result);
79-
Model expectedOutputModel = parseRDFString(expectedOutput);
80-
81-
assert(Models.isomorphic(resultModel, expectedOutputModel));
70+
try (InputStream rmlMappingStream = Files.newInputStream(rmlMapping)) {
71+
Path mappingMTL = Util.compiledMTLMapping(rmlMappingStream, null, FOLDER, false, false);
72+
String result = templateExecutor.executeMapping(Map.of("reader", compilerReader), FOLDER.resolve(mappingMTL.getFileName()));
73+
Files.delete(mappingMTL);
74+
75+
Model resultModel = parseRDFString(result);
76+
Model expectedOutputModel = parseRDFString(expectedOutput);
77+
assert(Models.isomorphic(resultModel, expectedOutputModel));
78+
}
8279
}
8380

8481
private static Model parseRDFString(String rdfString) throws Exception {
8582
RDFParser rdfParser = Rio.createParser(RDFFormat.NQUADS);
86-
8783
Model model = new TreeModel();
8884
rdfParser.setRDFHandler(new StatementCollector(model));
8985
rdfParser.parse(new StringReader(rdfString), "http://example.com/base/");
9086
return model;
9187
}
92-
9388
}

0 commit comments

Comments
 (0)