Skip to content

Commit 2ef12ec

Browse files
committed
update shapes
1 parent 5d3a804 commit 2ef12ec

File tree

4 files changed

+94
-16
lines changed

4 files changed

+94
-16
lines changed

ontology/documentation/ontology.ttl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88

99
<http://w3id.org/rml/lv/> rdf:type owl:Ontology ;
1010
owl:versionIRI <http://w3id.org/rml/lv/> ;
11-
owl:imports <https://kg-construct.github.io/rml-core/ontology/documentation/ontology.ttl> ,
12-
<https://kg-construct.github.io/rml-io/ontology/documentation/ontology.ttl> ;
11+
owl:imports <http://w3id.org/rml/core/> ;
1312
<http://purl.org/dc/terms/contributor> "Davide Lanti" ,
1413
"Els de Vleeschauwer" ,
1514
"Pano Maria" ;

shapes/lv.ttl

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
<http://w3id.org/rml/lv/shapes> a owl:Ontology ;
99
owl:imports <http://w3id.org/rml/core/shapes> ;
10-
owl:imports <http://w3id.org/rml/io/shapes> ;
1110
.
1211

1312
# rml:LogicalView
@@ -23,6 +22,7 @@ rmlsh:LogicalViewShape a sh:NodeShape ;
2322
- at least one rml:field property, with a rml:Field as its value.
2423
""" ;
2524
sh:targetClass rml:LogicalView ;
25+
sh:targetSubjectsOf rml:viewOn ;
2626
sh:targetObjectsOf rml:parentLogicalView ;
2727
sh:property [
2828
sh:description """
@@ -34,14 +34,14 @@ rmlsh:LogicalViewShape a sh:NodeShape ;
3434
sh:path rml:viewOn ;
3535
sh:minCount 1 ;
3636
sh:maxCount 1 ;
37-
sh:node rmlsh:LogicalSource ;
37+
sh:node rmlsh:RMLAbstractLogicalSourceShape ;
3838
sh:nodeKind sh:BlankNodeOrIRI ;
3939
] , [
4040
sh:description """
4141
A field of the logical view.
4242
""" ;
4343
sh:message """
44-
At least one rml:field property must be specified for a rml:LogicalView, with a resource as its value.
44+
At least one rml:field property must be specified for a rml:LogicalView, with either an rml:ExpressionField or an rml:IterableField its value.
4545
""" ;
4646
sh:path rml:field ;
4747
sh:minCount 1 ;
@@ -130,7 +130,35 @@ rmlsh:ExpressionFieldShape a sh:NodeShape ;
130130
rml:ExpressionField requires what an rml:ExpressionMap and rml:Field requires.
131131
""" ;
132132
sh:targetClass rml:ExpressionField ;
133-
sh:node rmlsh:RMLExpressionMapShape, rmlsh:Field ;
133+
sh:node rmlsh:RMLExpressionMapShape ;
134+
## Not using sh:node rmlsh:Field here due to shape recursion problem https://github.com/RDFLib/pySHACL/issues/154
135+
sh:property [
136+
sh:description """
137+
The name of the field.
138+
""" ;
139+
sh:message """
140+
Exactly one rml:fieldName property must be specified for a rml:Field, with a string as its value.
141+
""" ;
142+
sh:path rml:fieldName ;
143+
sh:minCount 1 ;
144+
sh:maxCount 1 ;
145+
sh:datatype xsd:string ;
146+
sh:nodeKind sh:Literal ;
147+
] , [
148+
sh:description """
149+
A child field of the field.
150+
""" ;
151+
sh:message """
152+
The value of a rml:field property for a rml:Field must be a resource.
153+
""" ;
154+
sh:path rml:field ;
155+
sh:nodeKind sh:BlankNodeOrIRI ;
156+
## Disabled due to shape recursion. This is covered by rmlsh:FieldShape
157+
# sh:xone (
158+
# [ sh:node rmlsh:ExpressionFieldShape ]
159+
# [ sh:node rmlsh:IterableFieldShape ]
160+
# )
161+
]
134162
.
135163

136164
rmlsh:IterableFieldShape a sh:NodeShape ;
@@ -144,21 +172,32 @@ rmlsh:IterableFieldShape a sh:NodeShape ;
144172
Furthermore, rml:IterableField requires what an rml:Iterable and rml:Field requires.
145173
""" ;
146174
sh:targetClass rml:IterableField ;
147-
sh:node rmlsh:Iterable, rmlsh:Field ; # TODO requires rmlsh:Iterable to be defined in core
175+
sh:node rmlsh:RMLIterableShape ;
176+
## Not using sh:node rmlsh:Field here due to shape recursion problem https://github.com/RDFLib/pySHACL/issues/154
177+
sh:property [
178+
sh:description """
179+
The name of the field.
180+
""" ;
181+
sh:message """
182+
Exactly one rml:fieldName property must be specified for a rml:Field, with a string as its value.
183+
""" ;
184+
sh:path rml:fieldName ;
185+
sh:minCount 1 ;
186+
sh:maxCount 1 ;
187+
sh:datatype xsd:string ;
188+
sh:nodeKind sh:Literal ;
189+
] ;
148190
sh:property [
149191
sh:description """
150192
A child field of the iterable field.
151193
""" ;
152194
sh:message """
153-
The value of a rml:field property for a rml:Field must be a resource.
195+
The value of a rml:field property for a rml:Field must be a resource that describes an rml:ExpressionField.
154196
""" ;
155197
sh:path rml:field ;
156198
sh:minCount 1 ;
157199
sh:nodeKind sh:BlankNodeOrIRI ;
158-
sh:xone (
159-
[ sh:node rmlsh:ExpressionFieldShape ]
160-
[ sh:node rmlsh:IterableFieldShape ]
161-
)
200+
sh:node rmlsh:ExpressionFieldShape ;
162201
] .
163202

164203
rmlsh:LogicalViewJoinShape a sh:NodeShape ;

shapes/tests.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,32 @@
1414
from rdflib import Graph
1515

1616
from mapping_validator import MappingValidator
17+
from utils import replace_strings_in_file, cleanup_tmp_folder
1718

1819
TEST_CASES_DIR = os.path.join(os.path.abspath('../test-cases'), '*/*.ttl')
19-
SHAPE_FILE = os.path.abspath('lv.ttl')
20-
ONTOLOGY_FILE = os.path.abspath('../ontology/documentation/ontology.ttl')
20+
SHAPE_FILE_LOCATION = 'lv.ttl'
21+
ONTOLOGY_FILE_LOCATION = '../ontology/documentation/ontology.ttl'
22+
2123

2224
class MappingValidatorTests(unittest.TestCase):
2325
def _validate_rules(self, path: str) -> None:
2426
rules = Graph().parse(path, format='turtle')
25-
mapping_validator = MappingValidator(SHAPE_FILE, ONTOLOGY_FILE)
27+
28+
# Replace import statements
29+
# also include io shapes just to validate the logical sources in the test cases
30+
shapes = replace_strings_in_file(SHAPE_FILE_LOCATION, {
31+
'<http://w3id.org/rml/core/shapes>': '<https://raw.githubusercontent.com/kg-construct/rml-core/refs/heads/main/shapes/core.ttl>, <https://raw.githubusercontent.com/kg-construct/rml-io/refs/heads/main/shapes/io.ttl>'
32+
})
33+
ontology = replace_strings_in_file(ONTOLOGY_FILE_LOCATION, {
34+
'<http://w3id.org/rml/core/>': '<https://raw.githubusercontent.com/kg-construct/rml-core/refs/heads/main/ontology/documentation/ontology.ttl>'
35+
})
36+
37+
mapping_validator = MappingValidator(shapes, ontology)
2638
mapping_validator.validate(rules)
2739

40+
cleanup_tmp_folder(shapes)
41+
cleanup_tmp_folder(ontology)
42+
2843
def test_non_existing_mapping_rules(self) -> None:
2944
with self.assertRaises(FileNotFoundError):
3045
p = os.path.abspath('does_not_exist.ttl')
@@ -45,7 +60,7 @@ def test_validation_rules(self, path: str) -> None:
4560
parser = argparse.ArgumentParser(description='Execute tests for SHACL '
4661
'shapes on RML mapping rules.')
4762
parser.add_argument('--verbose', '-v', action='count', default=1,
48-
help='Set verbosity level of messages. Example: -vvvv')
63+
help='Set verbosity level of messages. Example: -vvv')
4964
args = parser.parse_args()
5065

5166
args.verbose = 70 - (10 * args.verbose) if args.verbose > 0 else 0

shapes/utils.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import os
2+
import shutil
3+
4+
def replace_strings_in_file(file_path: str, replacements: dict) -> str:
5+
abs_path = os.path.abspath(file_path)
6+
tmp_dir = os.path.join(os.path.dirname(abs_path), 'tmp')
7+
os.makedirs(tmp_dir, exist_ok=True)
8+
tmp_file_path = os.path.join(tmp_dir, os.path.basename(abs_path))
9+
10+
with open(abs_path, 'r') as file:
11+
file_data = file.read()
12+
13+
for old_string, new_string in replacements.items():
14+
file_data = file_data.replace(old_string, new_string)
15+
16+
with open(tmp_file_path, 'w') as file:
17+
file.write(file_data)
18+
19+
return tmp_file_path
20+
21+
def cleanup_tmp_folder(file_path: str) -> None:
22+
abs_path = os.path.abspath(file_path)
23+
tmp_dir = os.path.dirname(abs_path)
24+
if os.path.exists(tmp_dir):
25+
shutil.rmtree(tmp_dir)

0 commit comments

Comments
 (0)