From ba06b724beeda56d0b05b18f079e73d1af79b35a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Tue, 21 Jan 2025 12:50:46 +0200 Subject: [PATCH 01/12] Update README.md --- README.md | 55 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index beab4b6..e162c99 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,8 @@ ## Preconditions 1. Iterator mappings must be one-to-one mappings i.e. only only one property is mapped for source and target. (Is this true?) - + 2. Subject source mapping must have only one target property (i.e. the generated subject source property) + ## Pseudocode @@ -18,47 +19,71 @@ def getReferenceFormulationResource(sourceSchemaURI, inputGraph) JSON return new Resource(ql:JSONPath) -def getLogicalSourceData(g) +# Returns a list of source propertyURIs that are used to reference of generate subject URIs for the given target shape +def getSubjectSourceProperties(inputGraph, targetShapeURI) + return queryResults(inputGraph, + select ?sourcePropertyURI + where + ?mapping a :Mapping + ?mapping :target/rdf:_1 ?target + ?mapping :source/*/:id ?sourcePropertyURI # can have multiple sources + ?target :id targetShapeURI + ?target :mscrType ?targetType . + filter(?targetType == "subject") + ) + +# Returns a list of values that represent all the iterator mappings in the crosswalk +def getIteratorData(g) return queryResults(g, - select ?targetProperty ?sourceProperty + select ?targetShapeURI ?sourcePropertyURI where ?mapping a :Mapping . ?mapping :target/rdf:_1 ?target # see precondition 1 - ?mapping :source/rdf:_1 ?source - ?target :id ?targetShape . - ?source :id ?sourceProperty . - + ?mapping :source/rdf:_1/:id ?sourcePropertyURI + ?target :id ?targetShapeURI . ?target :mscrType ?targetType . filter(?targetType == "iterator") ) -def getLogicalSource(subjectURI, inputGraph, sourceSchemaURI) +def getLogicalSource(subjectURI, inputGraph, sourceSchemaURI, sourcePropertyURI) logicalSource = new Graph() referenceFormulation = getReferenceFormulationResource(sourceSchemaURI, inputGraph) # create triples for RML LogicalSource - # What to add for rml:source? + iteratorPath = inputGraph.getPropertyValue(sourcePropertyURI, :instancePath) + + logicalSource.add(rml:referenceFormulation, referenceFormulation) + logicalSource.add(rml:iterator, iteratorPath) + # What to add for rml:source? + logicalSource.add(rml:source, ?????) return logicalSource -def getSubjectMap(subjectURI): +def getSubjectMap(subjectURI, sourcePropertyURIs, inputGraph): + subjectMap = new Graph() def getPredicateObjectMap(subjectURI): def generateRMLFromMSCRGraph(inputGraph) sourceSchemaURI = getSourceSchemaURI(inputGraph) outputGraph = new Graph() - foreach(logicalSourceData in getLogicalSourceData(inputGraph)) + foreach(iteratorData in getIteratorData(inputGraph)) triplesMapURI = new Resource(getTriplesMapURI()) # blank node logicalSourceURI = new Resource(getLogicalSourceURI()) subjectMapURI = new Resource(getSubjectMapURI()) predicateObjecMapURI = new Resource(getPredicateObjectMapURI()) - targetShape = logicalSourceData.targetShape - sourceProperty = logicalSourceData.sourceProperty + targetShapeURI = iteratorData.targetShapeURI + sourcePropertyURI = iteratorData.sourcePropertyURI - outputGraph.add(getLogicalSource(logicalSourceResource, inputGraph, sourceSchemaURI)) + outputGraph.add(getLogicalSource(logicalSourceResource, inputGraph, sourceSchemaURI, sourcePropertyURI)) outputGraph.add(rml:logicalSource, new Resource(logicalSourceURI)) - outputGraph.add(getSubjectMap(subjectMapURI)) + outputGraph.add( + getSubjectMap( + subjectMapURI, + getSubjectSourceProperties(inputGraph, targetShapeURI) + inputGraph + ) + ) outputGraph.add(rr:subjectMap, new Resource(subjectMapURI)) outputGraph.add(getPredicateObjectMap(predicateObjectMapURI)) From 21986c15c9b12319dd63344adaa0067ff3a84418 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Tue, 21 Jan 2025 15:54:21 +0200 Subject: [PATCH 02/12] Update README.md --- README.md | 104 ++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index e162c99..3b1f00d 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,8 @@ ## Preconditions 1. Iterator mappings must be one-to-one mappings i.e. only only one property is mapped for source and target. (Is this true?) 2. Subject source mapping must have only one target property (i.e. the generated subject source property) - - + 3. There can only be one pair of iterator/subject source mappings per SHACL shape. How significant restriction is this? + ## Pseudocode ``` @@ -19,33 +19,32 @@ def getReferenceFormulationResource(sourceSchemaURI, inputGraph) JSON return new Resource(ql:JSONPath) -# Returns a list of source propertyURIs that are used to reference of generate subject URIs for the given target shape -def getSubjectSourceProperties(inputGraph, targetShapeURI) +# Returns an ordered list of source propertyURIs that are used to reference of generate subject URIs for the given target shape +def getSubjectSourceMapping(inputGraph, targetShapeURI) return queryResults(inputGraph, - select ?sourcePropertyURI + select ?mappingURI where - ?mapping a :Mapping - ?mapping :target/rdf:_1 ?target - ?mapping :source/*/:id ?sourcePropertyURI # can have multiple sources + ?mappingURI a :Mapping + ?mappingURI :target/rdf:_1 ?target ?target :id targetShapeURI ?target :mscrType ?targetType . filter(?targetType == "subject") - ) + ) # Returns a list of values that represent all the iterator mappings in the crosswalk def getIteratorData(g) return queryResults(g, - select ?targetShapeURI ?sourcePropertyURI + select ?targetShapeURI ?sourcePropertyURI ?mappingURI where - ?mapping a :Mapping . - ?mapping :target/rdf:_1 ?target # see precondition 1 - ?mapping :source/rdf:_1/:id ?sourcePropertyURI + ?mappingURI a :Mapping . + ?mappingURI :target/rdf:_1 ?target # see precondition 1 + ?mappingURI :source/rdf:_1/:id ?sourcePropertyURI ?target :id ?targetShapeURI . ?target :mscrType ?targetType . filter(?targetType == "iterator") ) -def getLogicalSource(subjectURI, inputGraph, sourceSchemaURI, sourcePropertyURI) +def getLogicalSourceModel(subjectURI, inputGraph, sourceSchemaURI, sourcePropertyURI) logicalSource = new Graph() referenceFormulation = getReferenceFormulationResource(sourceSchemaURI, inputGraph) # create triples for RML LogicalSource @@ -56,38 +55,83 @@ def getLogicalSource(subjectURI, inputGraph, sourceSchemaURI, sourcePropertyURI) # What to add for rml:source? logicalSource.add(rml:source, ?????) return logicalSource + +def createFunctionCallModel() + +def getProcessingModel(uri, inputGraph, mappingURI) + mappingInfo = getMappingInfo(mappingURI) + m = new Graph() + + function = m.createResource() + functionValue = m.createResource() + m.addTriple(function, fnml:functionValue, functionValue) -def getSubjectMap(subjectURI, sourcePropertyURIs, inputGraph): + + +def getSourcePropertyURIs(mappingURI, inputGraph) + return queryResults(inputGraph, + select ?sourcePropertyID + where + mappingURI :source/* ?sourceProperty + ?sourceProperty :id ?sourcePropertyID + ?sourceProperty :index ?index + order by ASC(?index) + ) + +def getSubjectMapModel(uri, targetShapeURI, inputGraph): + mappingURI = getSubjectSourceMapping(targetShapeURI, inputGraph) subjectMap = new Graph() -def getPredicateObjectMap(subjectURI): + sourcePropertyURIs = getSourcePropertyURIs(mappingURI, inputGraph) + if(sourcePropertyURIs.isEmptyUI) + # case: blank node + else + subjectMap.addTriple(uri, rdf.type, rr:SubjectMap) + processingURI = getProcessingURI(...) + + processingModel = getProsessingModel(processingURI, inputGraph, mappingURI) + if(processingModel != null) + subjectMap.addModel(processingModel) + subjectMap.addTriple(uri, fnml:functionValue, processingURI) + else + if(sourcePropertyURIs.size() > 1) + throw new Exception("Subject source mapping without processing functions must have only one source") + sourcePath = inputGraph.getString(sourceProeprtyURIs.get(0) :instancePath) + subjectMap.addTriple(uri, rml:reference, sourcePath) + # add also rr:class ? + subjectMap.addTriple(uri, rr:tempType, rr:IRI) + return subjectMap + +def getPredicateObjectMapModel(subjectURI): def generateRMLFromMSCRGraph(inputGraph) + validate(inputGraph) # check if the preconditions hold sourceSchemaURI = getSourceSchemaURI(inputGraph) outputGraph = new Graph() - foreach(iteratorData in getIteratorData(inputGraph)) - triplesMapURI = new Resource(getTriplesMapURI()) # blank node - logicalSourceURI = new Resource(getLogicalSourceURI()) - subjectMapURI = new Resource(getSubjectMapURI()) - predicateObjecMapURI = new Resource(getPredicateObjectMapURI()) + foreach(iteratorData in getIteratorData(inputGraph)) + triplesMapURI = getTriplesMapURI() + logicalSourceURI = getLogicalSourceURI() + subjectMapURI = getSubjectMapURI() + predicateObjecMapURI = getPredicateObjectMapURI() + + mappingURI = iteratorData.mappingURI targetShapeURI = iteratorData.targetShapeURI sourcePropertyURI = iteratorData.sourcePropertyURI - outputGraph.add(getLogicalSource(logicalSourceResource, inputGraph, sourceSchemaURI, sourcePropertyURI)) - outputGraph.add(rml:logicalSource, new Resource(logicalSourceURI)) + outputGraph.addModel(getLogicalSourceModel(logicalSourceURI, inputGraph, sourceSchemaURI, sourcePropertyURI)) + outputGraph.addTriple(triplesMapURI, rml:logicalSource, logicalSourceURI) - outputGraph.add( - getSubjectMap( - subjectMapURI, - getSubjectSourceProperties(inputGraph, targetShapeURI) + outputGraph.addModel( + getSubjectMapModel( + subjectMapURI inputGraph ) ) - outputGraph.add(rr:subjectMap, new Resource(subjectMapURI)) + outputGraph.addTriple(triplesMapURI, rr:subjectMap, subjectMapURI) - outputGraph.add(getPredicateObjectMap(predicateObjectMapURI)) - outputGraph.add(rr:predicateObjectMap, new Resource(predicateObjectMapURI)) + outputGraph.addModel(getPredicateObjectMapModel(predicateObjectMapURI)) + outputGraph.addTriple(triplesMapURI, rr:predicateObjectMap, predicateObjectMapURI) return outputGraph ``` From 203878cac5976a8f3b248506b8202d3fbef9631f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Wed, 22 Jan 2025 11:33:35 +0200 Subject: [PATCH 03/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3b1f00d..b0b0fd7 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mscr-rmlgenerator ## Preconditions - 1. Iterator mappings must be one-to-one mappings i.e. only only one property is mapped for source and target. (Is this true?) + 1. Iterator mappings must be one-to-one mappings i.e. only only one property is mapped for source and target AND there can be only one iterator mapping per NodeShape. The reason fro this is that there is currently no way of grouping other mappings under specific iterator mapping. TODO: Add examples (screenshots from MSCR). 2. Subject source mapping must have only one target property (i.e. the generated subject source property) 3. There can only be one pair of iterator/subject source mappings per SHACL shape. How significant restriction is this? From 6fa2ff5fba12b2273febbf4f565183537b0ed03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Wed, 22 Jan 2025 16:05:19 +0200 Subject: [PATCH 04/12] Update README.md --- README.md | 146 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 139 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b0b0fd7..0debdde 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,49 @@ 1. Iterator mappings must be one-to-one mappings i.e. only only one property is mapped for source and target AND there can be only one iterator mapping per NodeShape. The reason fro this is that there is currently no way of grouping other mappings under specific iterator mapping. TODO: Add examples (screenshots from MSCR). 2. Subject source mapping must have only one target property (i.e. the generated subject source property) 3. There can only be one pair of iterator/subject source mappings per SHACL shape. How significant restriction is this? - + +## Function calls + +sourceFunc +- default -> passThrough +- input: field to reference +- output: array of values in the order of source properties + +mappingFunc +- default -> passThrough +- input: array of values extracted from the source properties +- output: array of values. Exact output depends on the function. +targetFunc +- default -> passThrough +- input: array of values +- output: ? + +createArray +- create new array and add the value param +- return array + +addToArray +- add value param to the list provides through list param +- return array + +Example with two source properties. +``` +targetFunc( + mappingFunc( + addToArray( + value: + sourceFunc(valueParam: ) + ) + ) + ) +) +``` + + ## Pseudocode ``` @@ -56,16 +98,105 @@ def getLogicalSourceModel(subjectURI, inputGraph, sourceSchemaURI, sourcePropert logicalSource.add(rml:source, ?????) return logicalSource -def createFunctionCallModel() + +def createFunctionModel(functionValueTargetURI, functionToCallURI, paramDataList) + m = new Graph() + m.addRDF( + functionValueTargetURI, + fnml:functionValue, + [ + rr:predicateObjectMap [ + rr:predicate fno:executes; + rr:objectMap [ + rr:constant {functionToCallURI} + ]; + ]; + {for each paramData in paramDataList + rr:predicateObjectMap [ + rr:predicate {paramData.paramName}; + rr:objectMap {paramData.paramValueModel} + + ]; + } + ] + ) + return m +def createOuterFunctionModel(functionValueTargetURI, functionToCallURI, valueURI) + m = new Graph() + m.addRDF( + functionValueTargetURI, + fnml:functionValue, + [ + rr:predicateObjectMap [ + rr:predicate fno:executes; + rr:objectMap [ + rr:constant {functionToCallURI} + ]; + ]; + {for each paramData in paramDataList + rr:predicateObjectMap [ + rr:predicate :valueParameter + rr:objectMap {valueURI} + + ]; + } + ] + ) + return m + +def addSourceFuncModel(sourcePropertyInfoList, m) + latestFunctionURI = null + for(sourcePropertyInfo in sourcePropertyInfoList) + # create function call pair: source function + outer function + sourceFunctionURI = "mscr:func:passthrough" + if(sourcePropertyInfo.processing != null) + sourceFunctionURI = sourcePropertyInfo.processing.functionURI + params = sourcePropertyInfo.processing.params + + if(is first element in the sourcePropertyInfoList) { + outerFunctionURI = "mcsr:createArray" + } + else { + outerFunctionURI = "mcsr:addToArray" + } + sourceFunctionResource = generateFuncURI(sourcePropertyInfo.id, false) + outerFunctionResource = generateFuncURI(sourcePropertyInfo.id, true) + m.addModel(createFunctionModel(sourceFunctionResource, sourceFunctionURI, params)) + m.addModel(createOuterFunctionModel(outerFunctionResource, outerFunctionURI, sourceFunctionResource} + + latestFunctionURI = outerFunctionResource + return latestFunctionURI + +def addMappingFuncModel(mappingInfo, sourceFuncURI, m) + mappingFunctionURI = "mscr:func:passthrough" + if(mappingInfo.processing != null) + mappingFunctionURI = mappingInfo.processing.functionURI + mappingFunctionResource = generateFuncURI(mappingInfo.id) + m.addModel(createOuterFunctionModel(mappingFunctionResource, mappingFunctionURI, sourceFuncURI)) + return mappingFunctionResource + +def addTargetFuncModel(targetPropertyInfoList, mappingFuncURI, m) + + for(targetPropertyInfo in targetPropertyInfoList) + functionURI = "mscr:func:passthrough" + if(targetPropertyInfo.processing != null) + functionURI = targetPropertyInfo.processing.functionURI + params = targetPropertyInfo.processing.params + targetFunctionResource = generateFuncURI(targetPropertyInfo.id, false) + m.addModel(createOuterFunctionModel(targetFunctionResource, functionURI, mappingFuncURI} + def getProcessingModel(uri, inputGraph, mappingURI) mappingInfo = getMappingInfo(mappingURI) m = new Graph() + if(mappingInfo.processing == null && mappingInfo.source.filter(x: x.processing != null).isEmpty && mappingInfo.target.filter(x: x.processing != null).isEmpty) + # mapping does not include any kind of processing configuration + return null - function = m.createResource() - functionValue = m.createResource() - m.addTriple(function, fnml:functionValue, functionValue) - + sourceFuncURI = addSourceFuncModel(mappingInfo.source, m) + mappingFuncURI = addMappingFuncModel(mappingInfo, sourceFuncURI, m) + addTargetFuncModel(mappingInfo.target, mappingFuncURI, m) + return m def getSourcePropertyURIs(mappingURI, inputGraph) @@ -78,6 +209,7 @@ def getSourcePropertyURIs(mappingURI, inputGraph) order by ASC(?index) ) +# Return a graph that contains all information related to single subjectMap def getSubjectMapModel(uri, targetShapeURI, inputGraph): mappingURI = getSubjectSourceMapping(targetShapeURI, inputGraph) subjectMap = new Graph() @@ -89,7 +221,7 @@ def getSubjectMapModel(uri, targetShapeURI, inputGraph): subjectMap.addTriple(uri, rdf.type, rr:SubjectMap) processingURI = getProcessingURI(...) - processingModel = getProsessingModel(processingURI, inputGraph, mappingURI) + processingModel = getProcessingModel(processingURI, inputGraph, mappingURI) if(processingModel != null) subjectMap.addModel(processingModel) subjectMap.addTriple(uri, fnml:functionValue, processingURI) From d38e885885be73bf9d7205090522c836102a6944 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Wed, 22 Jan 2025 23:46:50 +0200 Subject: [PATCH 05/12] Update README.md --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0debdde..f8aa4aa 100644 --- a/README.md +++ b/README.md @@ -175,15 +175,14 @@ def addMappingFuncModel(mappingInfo, sourceFuncURI, m) m.addModel(createOuterFunctionModel(mappingFunctionResource, mappingFunctionURI, sourceFuncURI)) return mappingFunctionResource -def addTargetFuncModel(targetPropertyInfoList, mappingFuncURI, m) +def addTargetFuncModel(uri, targetPropertyInfoList, mappingFuncURI, m) for(targetPropertyInfo in targetPropertyInfoList) functionURI = "mscr:func:passthrough" if(targetPropertyInfo.processing != null) functionURI = targetPropertyInfo.processing.functionURI params = targetPropertyInfo.processing.params - targetFunctionResource = generateFuncURI(targetPropertyInfo.id, false) - m.addModel(createOuterFunctionModel(targetFunctionResource, functionURI, mappingFuncURI} + m.addModel(createOuterFunctionModel(uri, functionURI, mappingFuncURI} def getProcessingModel(uri, inputGraph, mappingURI) @@ -195,7 +194,7 @@ def getProcessingModel(uri, inputGraph, mappingURI) sourceFuncURI = addSourceFuncModel(mappingInfo.source, m) mappingFuncURI = addMappingFuncModel(mappingInfo, sourceFuncURI, m) - addTargetFuncModel(mappingInfo.target, mappingFuncURI, m) + addTargetFuncModel(uri, mappingInfo.target, mappingFuncURI, m) return m From e52e95001c3b0002957bcc09528d9a1d39e7956a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Thu, 23 Jan 2025 08:49:22 +0200 Subject: [PATCH 06/12] Update README.md --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f8aa4aa..0c22bf8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,10 @@ # mscr-rmlgenerator -## Preconditions +## Preconditions / limitations 1. Iterator mappings must be one-to-one mappings i.e. only only one property is mapped for source and target AND there can be only one iterator mapping per NodeShape. The reason fro this is that there is currently no way of grouping other mappings under specific iterator mapping. TODO: Add examples (screenshots from MSCR). 2. Subject source mapping must have only one target property (i.e. the generated subject source property) 3. There can only be one pair of iterator/subject source mappings per SHACL shape. How significant restriction is this? + 4. ## Function calls @@ -192,10 +193,10 @@ def getProcessingModel(uri, inputGraph, mappingURI) # mapping does not include any kind of processing configuration return null - sourceFuncURI = addSourceFuncModel(mappingInfo.source, m) - mappingFuncURI = addMappingFuncModel(mappingInfo, sourceFuncURI, m) - addTargetFuncModel(uri, mappingInfo.target, mappingFuncURI, m) - return m + sourceFuncURI = addSourceFuncModel(mappingInfo.source, m) + mappingFuncURI = addMappingFuncModel(mappingInfo, sourceFuncURI, m) + addTargetFuncModel(uri, mappingInfo.target, mappingFuncURI, m) + return m def getSourcePropertyURIs(mappingURI, inputGraph) From 2e915939c5af588bb7071771a5cffa647fe58c5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Fri, 24 Jan 2025 09:59:54 +0200 Subject: [PATCH 07/12] Update README.md --- README.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0c22bf8..26d3501 100644 --- a/README.md +++ b/README.md @@ -233,9 +233,19 @@ def getSubjectMapModel(uri, targetShapeURI, inputGraph): # add also rr:class ? subjectMap.addTriple(uri, rr:tempType, rr:IRI) return subjectMap - -def getPredicateObjectMapModel(subjectURI): +# return mappingURIs for that have targets in target shape (excluding mappings to iterator and subject source) +def getPredicateObjectMapppings(targetShapeURI) + +def getPredicateObjectMapModel(subjectURI, targetShapeURI, inputGraph): + MappingMapper mapper = new MappingMapper(); + g = new Graph() + foreach(mappingURI in getPredicateObjectMapppings(targetShapeURI, inputGraph)) + mappingInfo = mapper.mapToMappingDTO(mappingURI, inputModel); + # do processing until mappingFunc + # foreach target doTargetProcessing(mappingFunc, targetIndex) + + def generateRMLFromMSCRGraph(inputGraph) validate(inputGraph) # check if the preconditions hold sourceSchemaURI = getSourceSchemaURI(inputGraph) From 7c307da6d0b1ce32f9a28e8bf2affa7681760e06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Fri, 24 Jan 2025 16:11:54 +0200 Subject: [PATCH 08/12] WIP: new implementation --- .../mscr/tranformation/rml/RMLGenerator2.java | 462 +++++++++++++++++ .../rml/functions/CustomFunctions.java | 45 ++ src/test/resources/crosswalk1-input.ttl | 464 ++++++++++++++++++ src/test/resources/crosswalk1.json | 107 ++++ src/test/resources/schemas/arrays-schema.json | 35 ++ src/test/resources/schemas/arrays-schema.xsd | 17 + src/test/resources/schemas/person-schema.json | 23 + src/test/resources/schemas/person-schema.xsd | 12 + src/test/resources/schemas/person-shapes.ttl | 44 ++ src/test/resources/schemas/shapes.ttl | 23 + 10 files changed, 1232 insertions(+) create mode 100644 src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java create mode 100644 src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java create mode 100644 src/test/resources/crosswalk1-input.ttl create mode 100644 src/test/resources/crosswalk1.json create mode 100644 src/test/resources/schemas/arrays-schema.json create mode 100644 src/test/resources/schemas/arrays-schema.xsd create mode 100644 src/test/resources/schemas/person-schema.json create mode 100644 src/test/resources/schemas/person-schema.xsd create mode 100644 src/test/resources/schemas/person-shapes.ttl create mode 100644 src/test/resources/schemas/shapes.ttl diff --git a/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java b/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java new file mode 100644 index 0000000..74ae856 --- /dev/null +++ b/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java @@ -0,0 +1,462 @@ +package fi.vm.yti.datamodel.api.v2.transformation; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; + +import org.apache.jena.query.QueryExecution; +import org.apache.jena.query.QueryExecutionFactory; +import org.apache.jena.query.QuerySolution; +import org.apache.jena.query.ResultSet; +import org.apache.jena.rdf.model.Literal; +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ModelFactory; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.vocabulary.RDF; + +import fi.vm.yti.datamodel.api.v2.dto.MSCR; +import fi.vm.yti.datamodel.api.v2.dto.MappingInfoDTO; +import fi.vm.yti.datamodel.api.v2.dto.NodeInfo; +import fi.vm.yti.datamodel.api.v2.mapper.MappingMapper; + +public class RMLGenerator2 { + + String nsRML = "http://semweb.mmlab.be/ns/rml#"; + String nsQL = "http://semweb.mmlab.be/ns/ql#"; + String nsRR = "http://www.w3.org/ns/r2rml#"; + String nsFNO = "https://w3id.org/function/ontology#"; + String nsFNML = "http://semweb.mmlab.be/ns/fnml#"; + String nsGREL = "http://users.ugent.be/~bjdmeest/function/grel.ttl#"; + + + + record IteratorData(String iteratorPropertyURI, String targetShapeURI, String sourcePropertyURI, String mappingURI) {} + + + private String generateRandomURI(String suffix, String prefix) { + return suffix + ":" + UUID.randomUUID().toString() + ":" + prefix; + } + public Model generateRMLFromMSCRGraph(Model inputModel, String crosswalkURI, String sourceSchemaURI) { + Model m = ModelFactory.createDefaultModel(); + List iterators = getIterators(inputModel); + for (IteratorData iteratorData : iterators) { + String triplesMapURI = generateRandomURI("triplesMap", ""); + String logicalSourceURI = generateRandomURI("logicalSource", ""); + String subjectMapURI = generateRandomURI("subjectMap", ""); + //String predicateObjecMapURI = generateRandomURI("", ""); + + Resource triplesMap = m.createResource(triplesMapURI); + triplesMap.addProperty(RDF.type, m.createResource(nsRR + "TriplesMap")); + + Resource logicalSource = addLogicalSourceModel(logicalSourceURI, inputModel, m, sourceSchemaURI, iteratorData.sourcePropertyURI); + triplesMap.addProperty(m.createProperty(nsRML + "logicalSource"), logicalSource); + + + Resource subjectMap = addSubjectMapModel(subjectMapURI, iteratorData.iteratorPropertyURI, iteratorData.targetShapeURI, inputModel, m); + triplesMap.addProperty(m.createProperty(nsRR + "subjectMap"), subjectMap); + + addPredicateObjectMapModel(triplesMap, inputModel, m, iteratorData.targetShapeURI); + + } + return m; + } + + private void addPredicateObjectMapModel(Resource triplesMap, Model inputModel, Model outputModel, String targetShapeURI) { + MappingMapper mapper = new MappingMapper(); + List mappings = getPredicateObjectMappings(inputModel, targetShapeURI); + for (Resource mappingResource : mappings) { + MappingInfoDTO mappingInfo = mapper.mapToMappingDTO(mappingResource.getURI(), inputModel); + if(mappingInfo.getProcessing() == null && + mappingInfo.getSource().stream().filter(NodeInfo::hasProcessing).collect(Collectors.toList()).isEmpty() && + mappingInfo.getTarget().stream().filter(NodeInfo::hasProcessing).collect(Collectors.toList()).isEmpty()) { + for (NodeInfo targetNode : mappingInfo.getTarget()) { + // there should be only one source property since there are no functions involved + Resource pom = outputModel.createResource(); + Literal sourcePath = inputModel.getResource(mappingInfo.getSource().get(0).getId()).getProperty(MSCR.instancePath).getLiteral(); + Resource pomObjectMap = outputModel.createResource(); + pomObjectMap.addProperty(outputModel.createProperty(nsRML+"reference"), outputModel.createLiteral(sourcePath.getString())); + pom.addProperty(outputModel.createProperty(nsRR+"objectMap"), pomObjectMap); + + Resource predicate = inputModel.getResource(targetNode.getId()); + pom.addProperty(outputModel.createProperty(nsRR+"predicate"), predicate); + + triplesMap.addProperty(outputModel.createProperty(nsRR + "predicateObjectMap"), pom); + } + } + else { + Resource sourceFunc = addSourceFuncModel(outputModel, mappingInfo.getSource()); + Resource mappingFunc = addMappingFuncModel(outputModel, mappingInfo, sourceFunc); + + for (int targetIndex = 0; targetIndex < mappingInfo.getTarget().size(); targetIndex++) { + NodeInfo targetNode = mappingInfo.getTarget().get(targetIndex); + Resource targetFunc = addTargetFuncModel(outputModel, targetNode, targetIndex, mappingFunc); + + Resource pom = outputModel.createResource(); + pom.addProperty(outputModel.createProperty(nsRR+"objectMap"), targetFunc); + + Resource predicate = inputModel.getResource(targetNode.getId()); + pom.addProperty(outputModel.createProperty(nsRR+"predicate"), predicate); + + triplesMap.addProperty(outputModel.createProperty(nsRR + "predicateObjectMap"), pom); + + } + } + + addPredicateObjectMapProcessing(triplesMap, mappingInfo, inputModel, outputModel); + } + } + private void addPredicateObjectMapProcessing(Resource triplesMap, MappingInfoDTO mappingInfo, Model inputModel, Model outputModel) { + Resource mappingFuncValue = null; + for (NodeInfo targetNode : mappingInfo.getTarget()) { + + } + + } + private List getPredicateObjectMappings(Model inputModel, String targetShapeURI) { + String q =""" +PREFIX rdf: +PREFIX : +prefix sh: +select ?mappingURI +where { + bind(URI("%s") as ?targetShape) + ?mappingURI a :Mapping . + ?mappingURI :target/(<>|!<>)*/:id ?targetPropertyURI . + bind(URI(?targetPropertyURI) as ?targetProperty) + ?targetShape sh:property ?targetProperty . +} + """.formatted(targetShapeURI); + QueryExecution qe = QueryExecutionFactory.create(q, inputModel); + ResultSet results = qe.execSelect(); + List list = new ArrayList(); + while(results.hasNext()) { + QuerySolution soln = results.next(); + Resource mapping = soln.get("mappingURI").asResource(); + list.add(mapping); + } + + return list; + } + private Resource addSubjectMapModel(String subjectMapURI, String targetShapeURI, String targetClass, Model inputModel, Model outputModel) { + String mappingURI = getSubjectSourceMapping(targetShapeURI, inputModel); + if(mappingURI == null) { + // no subject source mapping -> blank nodes + return null; + } + else { + MappingMapper mapper = new MappingMapper(); + MappingInfoDTO mappingInfo = mapper.mapToMappingDTO(mappingURI, inputModel); + // there should be only one + NodeInfo sourcePropertyInfo = mappingInfo.getSource().get(0); + Resource processingURI = addProcessingModel(outputModel, mappingInfo, 0); + if(processingURI == null) { + Resource subjectMap = outputModel.createResource(subjectMapURI); + Literal sourcePath = inputModel.getResource(sourcePropertyInfo.getId()).getProperty(MSCR.instancePath).getLiteral(); + subjectMap.addProperty(outputModel.createProperty(nsRML+"reference"), sourcePath); + subjectMap.addProperty(outputModel.createProperty(nsRR + "class"), outputModel.createResource(targetClass)); + subjectMap.addProperty(outputModel.createProperty(nsRR + "termType"), outputModel.createResource(nsRR + "IRI")); + return subjectMap; + } + else { + processingURI.addProperty(outputModel.createProperty(nsRR + "class"), outputModel.createResource(targetClass)); + + processingURI.addProperty(outputModel.createProperty(nsRR + "termType"), outputModel.createResource(nsRR + "IRI")); + return processingURI; + } + + } + } + + + private Resource addProcessingModel(Model outputModel, MappingInfoDTO mappingInfo, int targetIndex) { + if(mappingInfo.getProcessing() == null && + mappingInfo.getSource().stream().filter(NodeInfo::hasProcessing).collect(Collectors.toList()).isEmpty() && + mappingInfo.getTarget().stream().filter(NodeInfo::hasProcessing).collect(Collectors.toList()).isEmpty()) { + return null; + } + Resource sourceFunc = addSourceFuncModel(outputModel, mappingInfo.getSource()); + Resource mappingFunc = addMappingFuncModel(outputModel, mappingInfo, sourceFunc); + Resource targetFunc = addTargetFuncModel(outputModel, mappingInfo.getTarget().get(targetIndex), targetIndex, mappingFunc); + return targetFunc; + } + + private Resource addTargetFuncModel(Model outputModel, NodeInfo targetPropertyInfo, int targetIndex, Resource mappingFunc) { + String targetFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#passthrough"; + Map params = null; + if(targetPropertyInfo.getProcessing() != null) { + targetFunctionURI = targetPropertyInfo.getProcessing().getId(); + params = targetPropertyInfo.getProcessing().getParams(); + } + + String innerFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#arrayGet"; + Resource innerFunctionResource = outputModel.createResource(generateRandomURI(targetPropertyInfo.getId(), ":getValue")); + + Resource function1Value = outputModel.createResource(); + innerFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), function1Value); + + + Resource funcPom1 = outputModel.createResource(); + function1Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1); + funcPom1.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); + Resource funcPom1ObjectMap = outputModel.createResource(); + funcPom1ObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(innerFunctionURI)); + funcPom1.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap); + + Resource funcPom2 = outputModel.createResource(); + function1Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom2); + funcPom2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"p_param_a2")); + funcPom2.addProperty(outputModel.createProperty(nsRR+"objectMap"), mappingFunc); + + Resource funcPom3 = outputModel.createResource(); + function1Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom3); + funcPom3.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"indexParameter")); + Resource funcPom3ObjectMap = outputModel.createResource(); + funcPom3ObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createTypedLiteral(targetIndex)); + funcPom3.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom3ObjectMap); + + + + Resource outerFunctionResource = outputModel.createResource(generateRandomURI(targetPropertyInfo.getId(), ":outerfunc")); + + Resource function2Value = outputModel.createResource(); + outerFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), function2Value); + + Resource funcPom1_2 = outputModel.createResource(); + function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1_2); + funcPom1_2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); + Resource funcPom1ObjectMap2 = outputModel.createResource(); + funcPom1ObjectMap2.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(targetFunctionURI)); + funcPom1_2.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap2); + + + Resource funcPom2_2 = outputModel.createResource(); + function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom2_2); + funcPom2_2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"valueParameter")); + funcPom2_2.addProperty(outputModel.createProperty(nsRR+"objectMap"), innerFunctionResource); + + if(params != null) { + for (String key : params.keySet()) { + if(key.equals("input")) { + continue; + } + Object value = params.get(key); + Resource funcPom = outputModel.createResource(); + function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom); + funcPom.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(key)); + Resource funcPomObjectMap = outputModel.createResource(); + funcPomObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createLiteral(value.toString())); + funcPom.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPomObjectMap); + + } + + } + + return outerFunctionResource; + + } + private Resource addMappingFuncModel(Model outputModel, MappingInfoDTO mappingInfo, Resource sourceFunctionResource) { + String mappingFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#passthrough"; + Map params = null; + if(mappingInfo.getProcessing() != null) { + mappingFunctionURI = mappingInfo.getProcessing().getId(); + params = mappingInfo.getProcessing().getParams(); + } + + Resource mappingFunctionResource = outputModel.createResource(mappingInfo.getPID() + ":func"); + //addOuterFunctionModel(outputModel, mappingFunctionResource, mappingFunctionURI, sourceFunctionResource, null); + Resource functionValue = outputModel.createResource(); + mappingFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), functionValue); + + Resource funcPom1 = outputModel.createResource(); + functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1); + funcPom1.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); + Resource funcPom1ObjectMap = outputModel.createResource(); + funcPom1ObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(mappingFunctionURI)); + funcPom1.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap); + + Resource funcPom3 = outputModel.createResource(); + functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom3); + funcPom3.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"p_param_a2")); + funcPom3.addProperty(outputModel.createProperty(nsRR+"objectMap"), sourceFunctionResource); + + if(params != null) { + for (String key : params.keySet()) { + if(key.equals("input")) { + continue; + } + Object value = params.get(key); + Resource funcPom = outputModel.createResource(); + functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom); + funcPom.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(key)); + Resource funcPomObjectMap = outputModel.createResource(); + funcPomObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createLiteral(value.toString())); + funcPom.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPomObjectMap); + + } + + } + return mappingFunctionResource; + } + private Resource addSourceFuncModel(Model outputModel, List source) { + Resource latestFunction = null; + for(int i = 0; i < source.size(); i++) { + NodeInfo sourcePropertyInfo = source.get(i); + String sourceFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#passthrough"; + Map params = null; + if(sourcePropertyInfo.getProcessing() != null) { + sourceFunctionURI = sourcePropertyInfo.getProcessing().getId(); + params = sourcePropertyInfo.getProcessing().getParams(); + } + + String outerFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#createArray"; + if(i > 0) { + outerFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#addToArray"; + } + Resource sourceFunctionResource = outputModel.createResource(sourcePropertyInfo.getId() + ":" + source.hashCode() + ":func"); + Resource outerFunctionResource = outputModel.createResource(sourcePropertyInfo.getId() + ":" + source.hashCode() + ":outerfunc"); + addFunctionModel(outputModel, sourceFunctionResource, sourceFunctionURI, sourcePropertyInfo.getInstancePath(), params); + addOuterFunctionModel(outputModel, outerFunctionResource, outerFunctionURI, sourceFunctionResource, latestFunction); + + latestFunction = outerFunctionResource; + } + return latestFunction; + } + private void addOuterFunctionModel(Model m, Resource outerFunctionResource, String outerFunctionURI, Resource sourceFunctionResource, Resource prev) { + Resource functionValue = m.createResource(); + outerFunctionResource.addProperty(m.createProperty(nsFNML + "functionValue"), functionValue); + + Resource funcPom1 = m.createResource(); + functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom1); + funcPom1.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsFNO+"executes")); + Resource funcPom1ObjectMap = m.createResource(); + funcPom1ObjectMap.addProperty(m.createProperty(nsRR+"constant"), m.createResource(outerFunctionURI)); + funcPom1.addProperty(m.createProperty(nsRR+"objectMap"), funcPom1ObjectMap); + + Resource funcPom2 = m.createResource(); + functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom2); + funcPom2.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsGREL+"valueParameter")); + funcPom2.addProperty(m.createProperty(nsRR+"objectMap"), sourceFunctionResource); + + if(prev != null) { + Resource funcPom3 = m.createResource(); + functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom3); + funcPom3.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsGREL+"p_param_a2")); + funcPom3.addProperty(m.createProperty(nsRR+"objectMap"), prev); + + } + //sourceFunctionResource.addProperty(m.createProperty(nsRR + "class"), targetOntologyClass); + //outerFunctionResource.addProperty(m.createProperty(nsRR + "termType"), m.createResource(nsRR + "IRI")); + + } + + private void addFunctionModel(Model m, Resource sourceFunctionResource, String sourceFunctionURI, + String instancePath, Map params) { + Resource functionValue = m.createResource(); + sourceFunctionResource.addProperty(m.createProperty(nsFNML + "functionValue"), functionValue); + + Resource funcPom1 = m.createResource(); + functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom1); + funcPom1.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsFNO+"executes")); + Resource funcPom1ObjectMap = m.createResource(); + funcPom1ObjectMap.addProperty(m.createProperty(nsRR+"constant"), m.createResource(sourceFunctionURI)); + funcPom1.addProperty(m.createProperty(nsRR+"objectMap"), funcPom1ObjectMap); + + + Resource funcPom2 = m.createResource(); + functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom2); + funcPom2.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsGREL+"valueParameter")); + Resource funcPom2ObjectMap = m.createResource(); + funcPom2ObjectMap.addProperty(m.createProperty(nsRML+"reference"), m.createLiteral(instancePath)); + funcPom2.addProperty(m.createProperty(nsRR+"objectMap"), funcPom2ObjectMap); + + if(params != null) { + for (String key : params.keySet()) { + if(key.equals("input")) { + continue; + } + Object value = params.get(key); + Resource funcPom = m.createResource(); + functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom); + funcPom.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(key)); + Resource funcPomObjectMap = m.createResource(); + funcPomObjectMap.addProperty(m.createProperty(nsRR+"constant"), m.createLiteral(value.toString())); + funcPom.addProperty(m.createProperty(nsRR+"objectMap"), funcPomObjectMap); + + } + + } + //sourceFunctionResource.addProperty(m.createProperty(nsRR + "termType"), m.createResource(nsRR + "IRI")); + + } + private String getSubjectSourceMapping(String targetShapeURI, Model m) { + String q =""" +PREFIX rdf: +PREFIX : +select ?mappingURI +where { + ?mappingURI a :Mapping . + ?mappingURI :target/rdf:_1 ?target . + ?target :id ?targetShapeURI . + ?target :label ?targetLabel . + FILTER(?targetLabel=\"subject source\") +} + """; + QueryExecution qe = QueryExecutionFactory.create(q, m); + ResultSet results = qe.execSelect(); + if(!results.hasNext()) { + return null; + } + else { + return results.next().get("mappingURI").asResource().getURI(); + } + } + private Resource addLogicalSourceModel(String logicalSourceURI, Model inputModel, Model m, String sourceSchemaURI, + String sourcePropertyURI) { + + Resource logicalSource = m.createResource(logicalSourceURI); + logicalSource.addProperty(RDF.type, m.createResource(nsRML + "BaseSource")); + Resource referenceFormulation = m.createResource(nsQL + "JSONPath"); + logicalSource.addProperty(m.createProperty(nsRML + "referenceFormulation"), referenceFormulation); + logicalSource.addProperty(m.createProperty(nsRML + "source"), m.createLiteral("data/person.json")); + + Resource sourceProperty = inputModel.getResource(sourcePropertyURI); + Literal iteratorPath = sourceProperty.getProperty(MSCR.instancePath).getLiteral(); + logicalSource.addProperty(m.createProperty(nsRML + "iterator"), iteratorPath); + + return logicalSource; + } + private List getIterators(Model inputModel) { + String q =""" +PREFIX rdf: +PREFIX : +select ?targetShapeURI ?sourcePropertyURI ?mappingURI +where { + ?mappingURI a :Mapping . + ?mappingURI :target/rdf:_1 ?target . + ?mappingURI :source/rdf:_1/:id ?sourcePropertyURI . + ?target :id ?targetShapeURI . + ?target :label ?targetLabel . + FILTER(?targetLabel=\"iterator source\") +} + """; + QueryExecution qe = QueryExecutionFactory.create(q, inputModel); + ResultSet results = qe.execSelect(); + + List list = new ArrayList(); + while(results.hasNext()) { + QuerySolution soln = results.next(); + String targetShapeURI = soln.get("targetShapeURI").asLiteral().getString(); + String targetClass = targetShapeURI.substring(9); // TODO: remove this + list.add(new IteratorData( + targetShapeURI, + targetClass, + soln.get("sourcePropertyURI").asLiteral().getString(), + soln.get("mappingURI").asResource().getURI() + )); + } + + return list; + } +} diff --git a/src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java b/src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java new file mode 100644 index 0000000..1f9031f --- /dev/null +++ b/src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java @@ -0,0 +1,45 @@ +package fi.csc.mscr.tranformation.rml.functions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class CustomFunctions { + public static Object passthrough(Object obj) { + return obj; + } + + public static String addSuffix(String value, String suffix) { + return value + suffix; + } + + public static String addPrefix(Object value, String prefix) { + return prefix + value; + } + + public static List concat(List values, String delimiter) { + String result = String.join(delimiter, values); + return List.of(result); + } + + public static List split(String value, String delimiter) { + return Arrays.asList(value.split(delimiter)); + } + + public static Object arrayGet(List values, int index) { + String result = values.get(index); + return result; + } + + public static List createArray(String s) { + List a = new ArrayList(); + a.add(s); + return a; + } + + public static List addToArray(List a, String s) { + a.add(s); + return a; + + } +} diff --git a/src/test/resources/crosswalk1-input.ttl b/src/test/resources/crosswalk1-input.ttl new file mode 100644 index 0000000..69e6755 --- /dev/null +++ b/src/test/resources/crosswalk1-input.ttl @@ -0,0 +1,464 @@ +@prefix iow: . +@prefix dcap: . +@prefix owl: . +@prefix sh: . +@prefix rdf: . +@prefix xsd: . +@prefix skos: . +@prefix dcterms: . +@prefix rdfs: . +@prefix sourceschema: . +@prefix shapes: . +@prefix dash: . +@prefix mscr: . + + + a ; + rdfs:label "tset"@en ; + dcterms:created "2025-01-23T10:00:48.658Z"^^xsd:dateTime ; + dcterms:identifier "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172" ; + dcterms:language "en" ; + dcterms:modified "2025-01-23T10:00:48.658Z"^^xsd:dateTime ; + dcap:preferredXMLNamespace ; + dcap:preferredXMLNamespacePrefix + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172" ; + iow:contentModified "2025-01-23T10:00:48.657Z"^^xsd:dateTime ; + iow:creator "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + iow:modifier "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + iow:stateModified "2025-01-23T10:00:48.657Z"^^xsd:dateTime ; + + ; + + "MSCR" ; + + "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + + ; + + "DRAFT" ; + + "DATA_CROSSWALK" ; + + ; + + "1" ; + + "PRIVATE" ; + owl:versionInfo "DRAFT" . + + + + . + + + a ; + + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172@mapping=c001bb3a-18e5-4309-86f2-cb23ccc3789e" ; + + ; + + "2025-01-23T10:01:14.829Z"^^ ; + + "" ; + + ; + + [ a ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root" ; + + "Person" + ] + ] ; + + [ a ; + + [ + "iterator:https://shacl-play.sparna.fr/shapes/Person" ; + + "iterator source" ; + + + ] + ] . + + + a ; + + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172@mapping=5256cec5-1286-4157-b3a9-bfc38abf6c1f" ; + + ; + + "2025-01-23T10:35:30.272Z"^^ ; + + "" ; + + ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#concat" ; + + [ a ; + + [ + "input" ; + + "self" + ] ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#delimiterParameter" ; + + "/" + ] + ] + ] ; + + [ a ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-lastName" ; + + "lastName" ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#addPrefix" ; + + [ a ; + + [ + "input" ; + + "self" + ] ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#prefixParameter" ; + + "http://example2.com/" + ] + ] + ] ; + + + ] ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-firstName" ; + + "firstName" ; + + + ] + ] ; + + [ a ; + + [ + "subject:https://shacl-play.sparna.fr/shapes/Person" ; + + "subject source" ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#addSuffix" ; + + [ a ; + + [ + "input" ; + + "self" + ] ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#suffixParameter" ; + + "/test" + ] + ] + ] ; + + + ] + ] . + + + a ; + + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172@mapping=4de10154-0228-484b-8bee-0dd7730c0a26" ; + + ; + + "2025-01-24T11:21:38.052Z"^^ ; + + "" ; + + ; + + [ a ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-firstName" ; + + "firstName" ; + + + ] + ] ; + + [ a ; + + [ + "https://shacl-play.sparna.fr/shapes/Person_givenName" ; + + "givenName" ; + + + ] + ] . + + + + a ; + + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172@mapping=992bc267-ecc3-4a5d-b0ed-a505ca89b8bf" ; + + ; + + "2025-01-24T13:28:21.939Z"^^ ; + + "" ; + + ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#concat" ; + + [ a ; + + [ + "input" ; + + "self" + ] ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#delimiterParameter" ; + + ", " + ] + ] + ] ; + + [ a ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-lastName" ; + + "lastName" ; + + + ] ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-firstName" ; + + "firstName" ; + + + ] + ] ; + + [ a ; + + [ + "https://shacl-play.sparna.fr/shapes/Person_name" ; + + "name" ; + + + ] + ] . + + + a ; + rdfs:comment ""@en ; + rdfs:label "person json"@en ; + dcterms:created "2025-01-23T09:59:54.712Z"^^xsd:dateTime ; + dcterms:identifier "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771" ; + dcterms:language "en" ; + dcterms:modified "2025-01-23T10:00:34.741Z"^^xsd:dateTime ; + dcap:preferredXMLNamespace ; + dcap:preferredXMLNamespacePrefix + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771" ; + iow:contentModified "2025-01-23T09:59:54.712Z"^^xsd:dateTime ; + iow:creator "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + iow:modifier "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + iow:stateModified "2025-01-23T09:59:54.712Z"^^xsd:dateTime ; + + ; + + "JSONSCHEMA" ; + + ; + + "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + + "DRAFT" ; + + "DATA_SCHEMA" ; + + "1" ; + + "PUBLIC" ; + owl:versionInfo "DRAFT" . + + + + + "en" ; + + sourceschema:root-Root . + +sourceschema:root-Root a ; + + "Person" ; + + true ; + + "Person" ; + mscr:instancePath + "$" ; + + sourceschema:root-Root-age , sourceschema:root-Root-lastName , sourceschema:root-Root-firstName . + +sourceschema:root-Root-age a ; + + ; + + "$.age" ; + + "$.age" ; + + ; + + "Age in years which must be equal to or greater than zero." ; + + "1"^^ ; + + "0"^^ ; + + "age" ; + + sourceschema:root-Root-age . + +sourceschema:root-Root-lastName a ; + + ; + + "$.lastName" ; + + "$.lastName" ; + + ; + + "The person's last name." ; + + "1"^^ ; + + "lastName" ; + + sourceschema:root-Root-lastName . + +sourceschema:root-Root-firstName a ; + + ; + + "$.firstName" ; + + "$.firstName" ; + + ; + + "The person's first name." ; + + "1"^^ ; + + "firstName" ; + + sourceschema:root-Root-firstName . + + + a ; + rdfs:comment ""@en ; + rdfs:label "person shapes"@en ; + dcterms:created "2025-01-23T10:00:13.084Z"^^xsd:dateTime ; + dcterms:identifier "mscr:schema:5b042ba6-58a4-4d8b-bac1-47fa40204a0d" ; + dcterms:language "en" ; + dcterms:modified "2025-01-23T10:00:23.454Z"^^xsd:dateTime ; + dcap:preferredXMLNamespace ; + dcap:preferredXMLNamespacePrefix + "mscr:schema:5b042ba6-58a4-4d8b-bac1-47fa40204a0d" ; + iow:contentModified "2025-01-23T10:00:13.084Z"^^xsd:dateTime ; + iow:creator "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + iow:modifier "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + iow:stateModified "2025-01-23T10:00:13.084Z"^^xsd:dateTime ; + + ; + + "SHACL" ; + + ; + + "4ce70937-6fa4-49af-a229-b5f10328adb8" ; + + "DRAFT" ; + + "DATA_SCHEMA" ; + + "1" ; + + "PUBLIC" ; + owl:versionInfo "DRAFT" . + + + + shapes:Person . + +shapes:Person a sh:NodeShape ; + rdfs:label "Person"@en ; + sh:property shapes:Person_familyName , shapes:Person_givenName , shapes:Person_name , shapes:Person_age ; + sh:targetClass . + +shapes:Person_familyName + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "familyName"@en ; + sh:nodeKind sh:Literal ; + sh:path . + +shapes:Person_givenName + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "givenName"@en ; + sh:nodeKind sh:Literal ; + sh:path . + +shapes:Person_name dash:propertyRole dash:LabelRole ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "name"@en ; + sh:nodeKind sh:Literal ; + sh:path . + +shapes:Person_age dash:propertyRole dash:LabelRole ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "age"@en ; + sh:nodeKind sh:Literal ; + sh:path . \ No newline at end of file diff --git a/src/test/resources/crosswalk1.json b/src/test/resources/crosswalk1.json new file mode 100644 index 0000000..b2745ca --- /dev/null +++ b/src/test/resources/crosswalk1.json @@ -0,0 +1,107 @@ +[ + { + "type": "mscr:dataMapping", + "source": [ + { + "id": "mscr:schema:5a14637d-f262-4b2b-b015-a832a4b4b58c#root-Root-root", + "processing": null, + "mscrType": "default" + } + ], + "predicate": null, + "target": [ + { + "id": "http://uri.suomi.fi/datamodel/ns/mscr#Person1Shape", + "processing": null, + "mscrType": "iterator" + } + ], + "processing": null, + "notes": "", + "isPartOf": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8", + "id": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8@mapping=bcf3e7a2-756f-4112-a896-177214766e57" + }, + { + "type": "mscr:dataMapping", + "source": [ + { + "id": "mscr:schema:5a14637d-f262-4b2b-b015-a832a4b4b58c#root-Root-root-Root-firstName", + "processing": { + "id": "addPrefix", + "params": { + "prefix": "http://ex.com/" + } + }, + "mscrType": "default", + "index": 0 + }, + { + "id": "mscr:schema:5a14637d-f262-4b2b-b015-a832a4b4b58c#root-Root-root-Root-lastName", + "processing": null, + "mscrType": "default", + "index": 1 + } + ], + "predicate": null, + "target": [ + { + "id": "http://uri.suomi.fi/datamodel/ns/mscr#Person1Shape", + "processing": null, + "mscrType": "subject" + } + ], + "processing": { + "id": "concat", + "params": { + "separator": "/" + } + }, + "notes": "", + "isPartOf": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8", + "id": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8@mapping=bcf3e7a2-756f-4112-a896-177214766e57" + }, + { + "type": "mscr:dataMapping", + "source": [ + { + "id": "mscr:schema:5a14637d-f262-4b2b-b015-a832a4b4b58c#root-Root-root-Root-firstName", + "processing": null, + "mscrType": "default" + } + ], + "predicate": null, + "target": [ + { + "id": "mscr:schema:3a9d1aef-52ab-425c-90ec-2e15f9703ec9#28ad84b8471c0abdc37727a07b54a15c", + "processing": null, + "mscrType": "default" + } + ], + "processing": null, + "notes": "", + "isPartOf": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8", + "id": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8@mapping=107154e5-d282-47e9-86fc-eba6f97d3a12" + }, + { + "type": "mscr:dataMapping", + "source": [ + { + "id": "mscr:schema:5a14637d-f262-4b2b-b015-a832a4b4b58c#root-Root-root-Root-lastName", + "processing": null, + "mscrType": "default" + } + ], + "predicate": null, + "target": [ + { + "id": "mscr:schema:3a9d1aef-52ab-425c-90ec-2e15f9703ec9#88dc60d6f9d68169b18a30c9f52f5379", + "processing": null, + "mscrType": "default" + } + ], + "processing": null, + "notes": "", + "isPartOf": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8", + "id": "mscr:crosswalk:52d28f85-14d2-4127-8931-e9cb07074ba8@mapping=918d7337-9916-4c44-a2fa-61408f18fb7e" + } +] \ No newline at end of file diff --git a/src/test/resources/schemas/arrays-schema.json b/src/test/resources/schemas/arrays-schema.json new file mode 100644 index 0000000..0e9748f --- /dev/null +++ b/src/test/resources/schemas/arrays-schema.json @@ -0,0 +1,35 @@ +{ + "$id": "https://example.com/arrays.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "description": "Arrays of strings and objects", + "title": "Arrays", + "type": "object", + "properties": { + "fruits": { + "type": "array", + "items": { + "type": "string" + } + }, + "vegetables": { + "type": "array", + "items": { "$ref": "#/$defs/veggie" } + } + }, + "$defs": { + "veggie": { + "type": "object", + "required": [ "veggieName", "veggieLike" ], + "properties": { + "veggieName": { + "type": "string", + "description": "The name of the vegetable." + }, + "veggieLike": { + "type": "boolean", + "description": "Do I like this vegetable?" + } + } + } + } +} \ No newline at end of file diff --git a/src/test/resources/schemas/arrays-schema.xsd b/src/test/resources/schemas/arrays-schema.xsd new file mode 100644 index 0000000..17214a1 --- /dev/null +++ b/src/test/resources/schemas/arrays-schema.xsd @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/schemas/person-schema.json b/src/test/resources/schemas/person-schema.json new file mode 100644 index 0000000..a13fa0b --- /dev/null +++ b/src/test/resources/schemas/person-schema.json @@ -0,0 +1,23 @@ +{ + "$id": "https://example.com/person.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Person", + "type": "object", + "required": ["firstName", "lastName", "age"], + "additionalProperties": false, + "properties": { + "firstName": { + "type": "string", + "description": "The person's first name." + }, + "lastName": { + "type": "string", + "description": "The person's last name." + }, + "age": { + "description": "Age in years which must be equal to or greater than zero.", + "type": "integer", + "minimum": 0 + } + } +} \ No newline at end of file diff --git a/src/test/resources/schemas/person-schema.xsd b/src/test/resources/schemas/person-schema.xsd new file mode 100644 index 0000000..718d56c --- /dev/null +++ b/src/test/resources/schemas/person-schema.xsd @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/resources/schemas/person-shapes.ttl b/src/test/resources/schemas/person-shapes.ttl new file mode 100644 index 0000000..8e7914f --- /dev/null +++ b/src/test/resources/schemas/person-shapes.ttl @@ -0,0 +1,44 @@ +@prefix dash: . +@prefix rdf: . +@prefix rdfs: . +@prefix sh: . +@prefix shapes: . +@prefix xsd: . + +shapes:Person_familyName + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "familyName"@en ; + sh:nodeKind sh:Literal ; + sh:path . + +shapes:Person_givenName + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "givenName"@en ; + sh:nodeKind sh:Literal ; + sh:path . + +shapes:Person_name dash:propertyRole dash:LabelRole ; + sh:datatype xsd:string ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "name"@en ; + sh:nodeKind sh:Literal ; + sh:path . + +shapes:Person_age dash:propertyRole dash:LabelRole ; + sh:datatype xsd:integer ; + sh:maxCount 1 ; + sh:minCount 1 ; + sh:name "age"@en ; + sh:nodeKind sh:Literal ; + sh:path . + + +shapes:Person rdf:type sh:NodeShape ; + rdfs:label "Person"@en ; + sh:property shapes:Person_familyName , shapes:Person_givenName , shapes:Person_name, shapes:Person_age ; + sh:targetClass . \ No newline at end of file diff --git a/src/test/resources/schemas/shapes.ttl b/src/test/resources/schemas/shapes.ttl new file mode 100644 index 0000000..03472ac --- /dev/null +++ b/src/test/resources/schemas/shapes.ttl @@ -0,0 +1,23 @@ +@prefix mscr: . +@prefix rdf: . +@prefix rdfs: . +@prefix schemaorg: . +@prefix sh: . +@prefix xsd: . +@prefix dct: . + +mscr:Person1Shape a sh:NodeShape ; + rdfs:label "Person1" ; + sh:property + [ + sh:name "first name" ; + sh:datatype xsd:string ; + sh:path mscr:firstname ; + sh:maxCount 1 ; + ], + [ + sh:name "last name" ; + sh:datatype xsd:string ; + sh:path mscr:lastname ; + sh:maxCount 1 ; + ] . From 23f82ebef7c343f091bdb893b491057f5c6c9eba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Fri, 24 Jan 2025 16:13:24 +0200 Subject: [PATCH 09/12] Add documentation --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 26d3501..d9568ac 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ 1. Iterator mappings must be one-to-one mappings i.e. only only one property is mapped for source and target AND there can be only one iterator mapping per NodeShape. The reason fro this is that there is currently no way of grouping other mappings under specific iterator mapping. TODO: Add examples (screenshots from MSCR). 2. Subject source mapping must have only one target property (i.e. the generated subject source property) 3. There can only be one pair of iterator/subject source mappings per SHACL shape. How significant restriction is this? - 4. + 4. If mapping include more than one source properties a mapping function must be specified. ## Function calls From 188954c658d6fdb3fc754c823b328f542d113f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Fri, 24 Jan 2025 23:02:54 +0200 Subject: [PATCH 10/12] WIP --- .../mscr/tranformation/rml/RMLGenerator2.java | 193 +++++++++--------- .../rml/functions/CustomFunctions.java | 22 +- src/test/resources/crosswalk1-input.ttl | 118 ++++++++++- 3 files changed, 218 insertions(+), 115 deletions(-) diff --git a/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java b/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java index 74ae856..053f0e4 100644 --- a/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java +++ b/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java @@ -183,127 +183,111 @@ private Resource addProcessingModel(Model outputModel, MappingInfoDTO mappingInf } private Resource addTargetFuncModel(Model outputModel, NodeInfo targetPropertyInfo, int targetIndex, Resource mappingFunc) { - String targetFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#passthrough"; + String targetFunctionURI = null; Map params = null; if(targetPropertyInfo.getProcessing() != null) { targetFunctionURI = targetPropertyInfo.getProcessing().getId(); params = targetPropertyInfo.getProcessing().getParams(); - } - - String innerFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#arrayGet"; - Resource innerFunctionResource = outputModel.createResource(generateRandomURI(targetPropertyInfo.getId(), ":getValue")); - - Resource function1Value = outputModel.createResource(); - innerFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), function1Value); - - - Resource funcPom1 = outputModel.createResource(); - function1Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1); - funcPom1.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); - Resource funcPom1ObjectMap = outputModel.createResource(); - funcPom1ObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(innerFunctionURI)); - funcPom1.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap); + Resource outerFunctionResource = outputModel.createResource(generateRandomURI(targetPropertyInfo.getId(), ":outerfunc")); - Resource funcPom2 = outputModel.createResource(); - function1Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom2); - funcPom2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"p_param_a2")); - funcPom2.addProperty(outputModel.createProperty(nsRR+"objectMap"), mappingFunc); - - Resource funcPom3 = outputModel.createResource(); - function1Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom3); - funcPom3.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"indexParameter")); - Resource funcPom3ObjectMap = outputModel.createResource(); - funcPom3ObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createTypedLiteral(targetIndex)); - funcPom3.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom3ObjectMap); + Resource function2Value = outputModel.createResource(); + outerFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), function2Value); - - - Resource outerFunctionResource = outputModel.createResource(generateRandomURI(targetPropertyInfo.getId(), ":outerfunc")); + Resource funcPom1_2 = outputModel.createResource(); + function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1_2); + funcPom1_2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); + Resource funcPom1ObjectMap2 = outputModel.createResource(); + funcPom1ObjectMap2.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(targetFunctionURI)); + funcPom1_2.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap2); + + + Resource funcPom2_2 = outputModel.createResource(); + function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom2_2); + funcPom2_2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"anyObjectParam")); + funcPom2_2.addProperty(outputModel.createProperty(nsRR+"objectMap"), mappingFunc); + + if(params != null) { + for (String key : params.keySet()) { + if(key.equals("input")) { + continue; + } + Object value = params.get(key); + Resource funcPom = outputModel.createResource(); + function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom); + funcPom.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(key)); + Resource funcPomObjectMap = outputModel.createResource(); + funcPomObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createLiteral(value.toString())); + funcPom.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPomObjectMap); + + } + + } + return outerFunctionResource; + } + else { + return mappingFunc; + } - Resource function2Value = outputModel.createResource(); - outerFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), function2Value); - Resource funcPom1_2 = outputModel.createResource(); - function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1_2); - funcPom1_2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); - Resource funcPom1ObjectMap2 = outputModel.createResource(); - funcPom1ObjectMap2.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(targetFunctionURI)); - funcPom1_2.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap2); - - Resource funcPom2_2 = outputModel.createResource(); - function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom2_2); - funcPom2_2.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"valueParameter")); - funcPom2_2.addProperty(outputModel.createProperty(nsRR+"objectMap"), innerFunctionResource); - if(params != null) { - for (String key : params.keySet()) { - if(key.equals("input")) { - continue; - } - Object value = params.get(key); - Resource funcPom = outputModel.createResource(); - function2Value.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom); - funcPom.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(key)); - Resource funcPomObjectMap = outputModel.createResource(); - funcPomObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createLiteral(value.toString())); - funcPom.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPomObjectMap); - - } - - } - return outerFunctionResource; } private Resource addMappingFuncModel(Model outputModel, MappingInfoDTO mappingInfo, Resource sourceFunctionResource) { - String mappingFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#passthrough"; + String mappingFunctionURI = null; Map params = null; if(mappingInfo.getProcessing() != null) { mappingFunctionURI = mappingInfo.getProcessing().getId(); params = mappingInfo.getProcessing().getParams(); - } - - Resource mappingFunctionResource = outputModel.createResource(mappingInfo.getPID() + ":func"); - //addOuterFunctionModel(outputModel, mappingFunctionResource, mappingFunctionURI, sourceFunctionResource, null); - Resource functionValue = outputModel.createResource(); - mappingFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), functionValue); - - Resource funcPom1 = outputModel.createResource(); - functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1); - funcPom1.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); - Resource funcPom1ObjectMap = outputModel.createResource(); - funcPom1ObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(mappingFunctionURI)); - funcPom1.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap); + + Resource mappingFunctionResource = outputModel.createResource(mappingInfo.getPID() + ":func"); + //addOuterFunctionModel(outputModel, mappingFunctionResource, mappingFunctionURI, sourceFunctionResource, null); + Resource functionValue = outputModel.createResource(); + mappingFunctionResource.addProperty(outputModel.createProperty(nsFNML + "functionValue"), functionValue); + + Resource funcPom1 = outputModel.createResource(); + functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom1); + funcPom1.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsFNO+"executes")); + Resource funcPom1ObjectMap = outputModel.createResource(); + funcPom1ObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createResource(mappingFunctionURI)); + funcPom1.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPom1ObjectMap); - Resource funcPom3 = outputModel.createResource(); - functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom3); - funcPom3.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"p_param_a2")); - funcPom3.addProperty(outputModel.createProperty(nsRR+"objectMap"), sourceFunctionResource); + Resource funcPom3 = outputModel.createResource(); + functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom3); + funcPom3.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(nsGREL+"p_param_a2")); + funcPom3.addProperty(outputModel.createProperty(nsRR+"objectMap"), sourceFunctionResource); - if(params != null) { - for (String key : params.keySet()) { - if(key.equals("input")) { - continue; - } - Object value = params.get(key); - Resource funcPom = outputModel.createResource(); - functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom); - funcPom.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(key)); - Resource funcPomObjectMap = outputModel.createResource(); - funcPomObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createLiteral(value.toString())); - funcPom.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPomObjectMap); + if(params != null) { + for (String key : params.keySet()) { + if(key.equals("input")) { + continue; + } + Object value = params.get(key); + Resource funcPom = outputModel.createResource(); + functionValue.addProperty(outputModel.createProperty(nsRR+"predicateObjectMap"), funcPom); + funcPom.addProperty(outputModel.createProperty(nsRR+"predicate"), outputModel.createResource(key)); + Resource funcPomObjectMap = outputModel.createResource(); + funcPomObjectMap.addProperty(outputModel.createProperty(nsRR+"constant"), outputModel.createLiteral(value.toString())); + funcPom.addProperty(outputModel.createProperty(nsRR+"objectMap"), funcPomObjectMap); + } + } - - } - return mappingFunctionResource; + return mappingFunctionResource; + } + else { + return sourceFunctionResource; + } + + + } private Resource addSourceFuncModel(Model outputModel, List source) { Resource latestFunction = null; for(int i = 0; i < source.size(); i++) { NodeInfo sourcePropertyInfo = source.get(i); - String sourceFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#passthrough"; + String sourceFunctionURI = null; Map params = null; if(sourcePropertyInfo.getProcessing() != null) { sourceFunctionURI = sourcePropertyInfo.getProcessing().getId(); @@ -314,9 +298,18 @@ private Resource addSourceFuncModel(Model outputModel, List source) { if(i > 0) { outerFunctionURI = "http://users.ugent.be/~bjdmeest/function/grel.ttl#addToArray"; } - Resource sourceFunctionResource = outputModel.createResource(sourcePropertyInfo.getId() + ":" + source.hashCode() + ":func"); + Resource sourceFunctionResource = null; Resource outerFunctionResource = outputModel.createResource(sourcePropertyInfo.getId() + ":" + source.hashCode() + ":outerfunc"); - addFunctionModel(outputModel, sourceFunctionResource, sourceFunctionURI, sourcePropertyInfo.getInstancePath(), params); + if(sourceFunctionURI != null) { + sourceFunctionResource = outputModel.createResource(sourcePropertyInfo.getId() + ":" + source.hashCode() + ":func"); + addFunctionModel(outputModel, sourceFunctionResource, sourceFunctionURI, sourcePropertyInfo.getInstancePath(), params); + + } + else { + sourceFunctionResource = outputModel.createResource(); + sourceFunctionResource.addProperty(outputModel.createProperty(nsRML+"reference"), outputModel.createLiteral(sourcePropertyInfo.getInstancePath())); + + } addOuterFunctionModel(outputModel, outerFunctionResource, outerFunctionURI, sourceFunctionResource, latestFunction); latestFunction = outerFunctionResource; @@ -336,7 +329,7 @@ private void addOuterFunctionModel(Model m, Resource outerFunctionResource, Stri Resource funcPom2 = m.createResource(); functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom2); - funcPom2.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsGREL+"valueParameter")); + funcPom2.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsGREL+"anyObjectParam")); funcPom2.addProperty(m.createProperty(nsRR+"objectMap"), sourceFunctionResource); if(prev != null) { @@ -353,6 +346,7 @@ private void addOuterFunctionModel(Model m, Resource outerFunctionResource, Stri private void addFunctionModel(Model m, Resource sourceFunctionResource, String sourceFunctionURI, String instancePath, Map params) { + Resource functionValue = m.createResource(); sourceFunctionResource.addProperty(m.createProperty(nsFNML + "functionValue"), functionValue); @@ -366,7 +360,7 @@ private void addFunctionModel(Model m, Resource sourceFunctionResource, String s Resource funcPom2 = m.createResource(); functionValue.addProperty(m.createProperty(nsRR+"predicateObjectMap"), funcPom2); - funcPom2.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsGREL+"valueParameter")); + funcPom2.addProperty(m.createProperty(nsRR+"predicate"), m.createResource(nsGREL+"anyObjectParam")); Resource funcPom2ObjectMap = m.createResource(); funcPom2ObjectMap.addProperty(m.createProperty(nsRML+"reference"), m.createLiteral(instancePath)); funcPom2.addProperty(m.createProperty(nsRR+"objectMap"), funcPom2ObjectMap); @@ -386,7 +380,8 @@ private void addFunctionModel(Model m, Resource sourceFunctionResource, String s } - } + } + //sourceFunctionResource.addProperty(m.createProperty(nsRR + "termType"), m.createResource(nsRR + "IRI")); } diff --git a/src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java b/src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java index 1f9031f..ed939ec 100644 --- a/src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java +++ b/src/main/java/fi/csc/mscr/tranformation/rml/functions/CustomFunctions.java @@ -5,11 +5,8 @@ import java.util.List; public class CustomFunctions { - public static Object passthrough(Object obj) { - return obj; - } - public static String addSuffix(String value, String suffix) { + public static String addSuffix(Object value, String suffix) { return value + suffix; } @@ -22,24 +19,19 @@ public static List concat(List values, String delimiter) { return List.of(result); } - public static List split(String value, String delimiter) { - return Arrays.asList(value.split(delimiter)); - } - - public static Object arrayGet(List values, int index) { - String result = values.get(index); + public static List split(List values, String delimiter) { + List result = Arrays.asList(values.get(0).toString().split(delimiter)); return result; } - public static List createArray(String s) { - List a = new ArrayList(); + public static List createArray(Object s) { + List a = new ArrayList(); a.add(s); return a; } - public static List addToArray(List a, String s) { - a.add(s); + public static List addToArray(List a, Object s) { + a.add(s.toString()); return a; - } } diff --git a/src/test/resources/crosswalk1-input.ttl b/src/test/resources/crosswalk1-input.ttl index 69e6755..3db8054 100644 --- a/src/test/resources/crosswalk1-input.ttl +++ b/src/test/resources/crosswalk1-input.ttl @@ -279,7 +279,123 @@ ] - ] . + ] . + + + a ; + + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172@mapping=ec13355a-bfdf-46ac-bbd7-a7518c4fa847" ; + + ; + + "2025-01-24T18:23:34.6Z"^^ ; + + "" ; + + ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#split" ; + + [ a ; + + [ + "input" ; + + "self" + ] ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#delimiterParameter" ; + + "_" + ] + ] + ] ; + + [ a ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-lastName" ; + + "lastName" ; + + + ] + ] ; + + [ a ; + + [ + "https://shacl-play.sparna.fr/shapes/Person_familyName" ; + + "familyName" ; + + + ] + ] . + + + a ; + + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172@mapping=9a36c787-2b66-44a2-ab94-81b81a2ede78" ; + + ; + + "2025-01-24T20:55:24.218Z"^^ ; + + "" ; + + ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#split" ; + + [ a ; + + [ + "input" ; + + "self" + ] ; + + [ + "http://users.ugent.be/~bjdmeest/function/grel.ttl#delimiter" ; + + "_" + ] + ] + ] ; + + [ a ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-lastName" ; + + "lastName" ; + + + ] + ] ; + + [ a ; + + [ + "https://shacl-play.sparna.fr/shapes/Person_givenName" ; + + "givenName" ; + + + ] ; + + [ + "https://shacl-play.sparna.fr/shapes/Person_familyName" ; + + "familyName" ; + + + ] + ] . a ; From 7f4f2959babd41ea287349c795a27ccd2c8195f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Fri, 24 Jan 2025 23:04:03 +0200 Subject: [PATCH 11/12] Fix typo --- src/test/resources/crosswalk1-input.ttl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/resources/crosswalk1-input.ttl b/src/test/resources/crosswalk1-input.ttl index 3db8054..3f6521e 100644 --- a/src/test/resources/crosswalk1-input.ttl +++ b/src/test/resources/crosswalk1-input.ttl @@ -360,7 +360,7 @@ ] ; [ - "http://users.ugent.be/~bjdmeest/function/grel.ttl#delimiter" ; + "http://users.ugent.be/~bjdmeest/function/grel.ttl#delimiterParameter" ; "_" ] From 8bcb7a84d38c96159616edb38afa61e81403623c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joonas=20Kes=C3=A4niemi?= Date: Fri, 24 Jan 2025 23:25:53 +0200 Subject: [PATCH 12/12] WIP --- .../mscr/tranformation/rml/RMLGenerator2.java | 40 ++++++++++++++++++- src/test/resources/crosswalk1-input.ttl | 35 ++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java b/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java index 053f0e4..7d9cba5 100644 --- a/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java +++ b/src/main/java/fi/csc/mscr/tranformation/rml/RMLGenerator2.java @@ -15,6 +15,7 @@ import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Resource; import org.apache.jena.vocabulary.RDF; +import org.topbraid.shacl.vocabulary.SH; import fi.vm.yti.datamodel.api.v2.dto.MSCR; import fi.vm.yti.datamodel.api.v2.dto.MappingInfoDTO; @@ -63,6 +64,33 @@ public Model generateRMLFromMSCRGraph(Model inputModel, String crosswalkURI, Str return m; } + record DatatypeInfo(Resource nodeKind, Resource datatype) {} + private DatatypeInfo getDataTypeInfo(Model inputModel, String targetShapeURI) { + Resource targetShape = inputModel.getResource(targetShapeURI); + Resource datatype = null; + if(targetShape.hasProperty(SH.datatype)) { + datatype = targetShape.getProperty(SH.datatype).getResource(); + } + Resource nodeKind = null; + if(targetShape.hasProperty(SH.nodeKind)) { + nodeKind = targetShape.getProperty(SH.nodeKind).getResource(); + } + return new DatatypeInfo(nodeKind, datatype); + } + + private void addDatatype(Model outputModel, Resource targetResource, Resource datatype, Resource nodeKind) { + if(datatype != null) { + targetResource.addProperty(outputModel.createProperty(nsRR+"datatype") , datatype); + targetResource.addProperty(outputModel.createProperty(nsRR+"termType") , outputModel.createProperty(nsRR+"Literal")); + } + else if(nodeKind != null) { + if(nodeKind.getURI().equals(SH.IRI.getURI())) { + targetResource.addProperty(outputModel.createProperty(nsRR+"termType") , outputModel.createProperty(nsRR+"IRI")); + } + } + + + } private void addPredicateObjectMapModel(Resource triplesMap, Model inputModel, Model outputModel, String targetShapeURI) { MappingMapper mapper = new MappingMapper(); List mappings = getPredicateObjectMappings(inputModel, targetShapeURI); @@ -79,9 +107,12 @@ private void addPredicateObjectMapModel(Resource triplesMap, Model inputModel, M pomObjectMap.addProperty(outputModel.createProperty(nsRML+"reference"), outputModel.createLiteral(sourcePath.getString())); pom.addProperty(outputModel.createProperty(nsRR+"objectMap"), pomObjectMap); - Resource predicate = inputModel.getResource(targetNode.getId()); + Resource predicate = inputModel.getResource(targetNode.getId()).getPropertyResourceValue(SH.path); pom.addProperty(outputModel.createProperty(nsRR+"predicate"), predicate); + DatatypeInfo dti = getDataTypeInfo(inputModel, targetNode.getId()); + addDatatype(outputModel, pomObjectMap, dti.datatype, dti.nodeKind); + triplesMap.addProperty(outputModel.createProperty(nsRR + "predicateObjectMap"), pom); } } @@ -96,9 +127,14 @@ private void addPredicateObjectMapModel(Resource triplesMap, Model inputModel, M Resource pom = outputModel.createResource(); pom.addProperty(outputModel.createProperty(nsRR+"objectMap"), targetFunc); - Resource predicate = inputModel.getResource(targetNode.getId()); + Resource predicate = inputModel.getResource(targetNode.getId()).getPropertyResourceValue(SH.path); pom.addProperty(outputModel.createProperty(nsRR+"predicate"), predicate); + + DatatypeInfo dti = getDataTypeInfo(inputModel, targetNode.getId()); + addDatatype(outputModel, targetFunc, dti.datatype, dti.nodeKind); + + triplesMap.addProperty(outputModel.createProperty(nsRR + "predicateObjectMap"), pom); } diff --git a/src/test/resources/crosswalk1-input.ttl b/src/test/resources/crosswalk1-input.ttl index 3f6521e..b0d2a25 100644 --- a/src/test/resources/crosswalk1-input.ttl +++ b/src/test/resources/crosswalk1-input.ttl @@ -396,6 +396,41 @@ ] ] . + + + a ; + + "mscr:crosswalk:170c9c32-3b18-4ac1-853c-5a48aa1b3172@mapping=ebc31480-e9f4-4297-9488-36d6d3e18081" ; + + ; + + "2025-01-24T21:23:51.053Z"^^ ; + + "" ; + + ; + + [ a ; + + [ + "mscr:schema:b2973de1-f9e6-4778-9390-039a86cb0771#root-Root-age" ; + + "age" ; + + + ] + ] ; + + [ a ; + + [ + "https://shacl-play.sparna.fr/shapes/Person_age" ; + + "age" ; + + + ] + ] . a ;