Skip to content
Snippets Groups Projects
Commit 1661d6f6 authored by Paul Moosmann's avatar Paul Moosmann
Browse files

Merge branch 'bugfix/complexStructures' into 'main'

Bugfix when complex structures have to be displayed in the frontend.

See merge request eclipse/xfsc/self-description-tooling/sd-creation-wizard-api!18
parents 8b57ef8a 4aa631ac
No related branches found
No related tags found
No related merge requests found
Pipeline #45867 failed
......@@ -16,10 +16,7 @@ import org.topbraid.shacl.vocabulary.SH;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
......@@ -58,8 +55,30 @@ public class ConversionService {
.map(Shape::getShapeResource)
.map(shape -> constructVicShape(shape, prefixList))
.collect(Collectors.toList());
// sort shapes so the deepest shapes are at first and can be handled correctly by the frontend.
var shapesSorted = shapes.stream()
.sorted(Comparator.comparingInt(shape -> calculateDepth(shape, shapes)))
.collect(Collectors.toList());
return new ShaclModel(prefixList, shapesSorted);
}
private static int calculateDepth(VicShape shape, List<VicShape> shapes) {
int depth = 0;
for (ShapeProperties property : shape.getConstraints()) {
String children = property.getChildren();
if (children != null) {
VicShape childShape = getShapeByName(children, shapes);
if (childShape != null) {
depth = Math.max(depth, 1 + calculateDepth(childShape, shapes));
}
}
}
return depth;
}
return new ShaclModel(prefixList, shapes);
private static VicShape getShapeByName(String shapeName, List<VicShape> shapes) {
return shapes.stream().filter(shape -> shape.getSchema().equals(shapeName)).findFirst().orElse(null);
}
private static List<ShapeProperties> extractProperties(SHShape shape, List<Map<String, String>> prefixList) {
......
......@@ -47,6 +47,9 @@ public class ConversionServicePositiveTests {
public String inputFilename;
@Parameter(value = 1)
public String outputFilename;
@Parameter(value = 2)
public boolean strictComparison;
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
......@@ -56,100 +59,103 @@ public class ConversionServicePositiveTests {
return Arrays.asList(new Object[][]{
//0. Preliminary test for converting shacl shapes to json object
{"input-shacl-file.ttl", "output.json"},
{"input-shacl-file.ttl", "output.json", false},
//1. sh:datatype in shacl file
{"test-datatype.ttl", "test-datatype-output.json"},
{"test-datatype.ttl", "test-datatype-output.json", false},
//2. custom datatypes in shacl file
{"test-datatype2.ttl", "test-datatype2-output.json"},
{"test-datatype2.ttl", "test-datatype2-output.json", false},
//3. sh:description in shacl file
{"test-description.ttl", "test-description-output.json"},
{"test-description.ttl", "test-description-output.json", false},
//4. sh:group in shacl file
{"test-group.ttl", "test-group-output.json"},
{"test-group.ttl", "test-group-output.json", false},
//5. sh:in in shacl file with a list of strings
{"test-in-property.ttl", "test-in-property-output.json"},
{"test-in-property.ttl", "test-in-property-output.json", false},
//6. sh:in handling for different types
{"test-in-property2.ttl", "test-in-property2-output.json"},
{"test-in-property2.ttl", "test-in-property2-output.json", false},
//7. sh:maxcount in shacl file
{"test-max-count.ttl", "test-max-count-output.json"},
{"test-max-count.ttl", "test-max-count-output.json", false},
//8. sh:mincount in shacl file
{"test-min-count.ttl", "test-min-count-output.json"},
{"test-min-count.ttl", "test-min-count-output.json", false},
//9. sh:maxinclusive in shacl file
{"test-max-inclusive.ttl", "test-max-inclusive-output.json"},
{"test-max-inclusive.ttl", "test-max-inclusive-output.json", false},
//10. sh:maxinclusive in shacl file with negative value
{"test-negative-max-inclusive.ttl", "test-negative-max-inclusive-output.json"},
{"test-negative-max-inclusive.ttl", "test-negative-max-inclusive-output.json", false},
//11. sh:mininclusive in shacl file
{"test-min-inclusive.ttl", "test-min-inclusive-output.json"},
{"test-min-inclusive.ttl", "test-min-inclusive-output.json", false},
//12. sh:mininclusive in shacl file with negative value
{"test-negative-min-inclusive.ttl", "test-negative-min-inclusive-output.json"},
{"test-negative-min-inclusive.ttl", "test-negative-min-inclusive-output.json", false},
//13. sh:maxlengtht in shacl file
{"test-max-length.ttl", "test-max-length-output.json"},
{"test-max-length.ttl", "test-max-length-output.json", false},
//14. sh:maxlengtht in shacl file with negative value
{"test-negative-max-length.ttl", "test-negative-max-length-output.json"},
{"test-negative-max-length.ttl", "test-negative-max-length-output.json", false},
//15. sh:minlength in shacl file
{"test-min-length.ttl", "test-min-length-output.json"},
{"test-min-length.ttl", "test-min-length-output.json", false},
//16. sh:minlength in shacl file with negative value
{"test-negative-min-length.ttl", "test-negative-min-length-output.json"},
{"test-negative-min-length.ttl", "test-negative-min-length-output.json", false},
//17. sh:order in shacl file
{"test-order.ttl", "test-order-output.json"},
{"test-order.ttl", "test-order-output.json", false},
//18. sh:order in shacl file with negative value
{"test-negative-order.ttl", "test-negative-order-output.json"},
{"test-negative-order.ttl", "test-negative-order-output.json", false},
//19. sh:path in shacl file
{"test-path.ttl", "test-path-output.json"},
{"test-path.ttl", "test-path-output.json", false},
//20. multiple not connected shapes in a shacl file
{"test-multiple-shapes.ttl", "test-multiple-shapes-output.json"},
{"test-multiple-shapes.ttl", "test-multiple-shapes-output.json", false},
//21. nested shapes in a shacl file
{"test-nested-shapes.ttl", "test-nested-shapes-output.json"},
{"test-nested-shapes.ttl", "test-nested-shapes-output.json", false},
//22. sh:name in shacl file
{"test-name.ttl", "test-name-output.json"},
{"test-name.ttl", "test-name-output.json", false},
//23. sh:minExclusive in shacl file
{"test-min-exclusive.ttl", "test-min-exclusive-output.json"},
{"test-min-exclusive.ttl", "test-min-exclusive-output.json", false},
//24. sh:minExclusive in shacl file with -ve value
{"test-negative-min-exclusive.ttl", "test-negative-min-exclusive-output.json"},
{"test-negative-min-exclusive.ttl", "test-negative-min-exclusive-output.json", false},
//25. sh:maxExclusive in shacl file
{"test-max-exclusive.ttl", "test-max-exclusive-output.json"},
{"test-max-exclusive.ttl", "test-max-exclusive-output.json", false},
//26. sh:maxExclusive in shacl file with negative value
{"test-negative-max-exclusive.ttl", "test-negative-max-exclusive-output.json"},
{"test-negative-max-exclusive.ttl", "test-negative-max-exclusive-output.json", false},
//27. sh:class in shacl file
{"test-class.ttl", "test-class-output.json"},
{"test-class.ttl", "test-class-output.json", false},
//28. sh:or in shacl file with mincount
{"test-sh-or-mincount.ttl", "test-sh-or-mincount-output.json"},
{"test-sh-or-mincount.ttl", "test-sh-or-mincount-output.json", false},
//29. sh:or in shacl file with maxcount
{"test-sh-or-maxcount.ttl", "test-sh-or-maxount-output.json"},
{"test-sh-or-maxcount.ttl", "test-sh-or-maxount-output.json", false},
//30. sh:or in shacl file with datatype and class
{"test-sh-or.ttl", "test-sh-or-output.json"},
{"test-sh-or.ttl", "test-sh-or-output.json", false},
//31. unhandled/unsupported properties in shacl file
{"test-unhandled-properties.ttl", "test-unhandled-properties-output.json"}
{"test-unhandled-properties.ttl", "test-unhandled-properties-output.json", false},
//32. checking if objects are sorted from high nested level to low / no nested level (leaf to root)
{"test-complex-structure-sorted.ttl", "test-complex-structure-sorted-output.json", true}
}
);
}
......@@ -183,7 +189,6 @@ public class ConversionServicePositiveTests {
.file(mockMultipartFile);
MvcResult mvcResult = mockMvc.perform(builder).andExpect(ok).andReturn();
JSONAssert.assertEquals(outputFile, mvcResult.getResponse().getContentAsString(), false);
JSONAssert.assertEquals(outputFile, mvcResult.getResponse().getContentAsString(), strictComparison);
}
}
{
"prefixList": [
{
"alias": "xsd",
"url": "http://www.w3.org/2001/XMLSchema#"
},
{
"alias": "General",
"url": "https://example.org/general/"
},
{
"alias": "skos",
"url": "http://www.w3.org/2004/02/skos/core#"
},
{
"alias": "HD-Map",
"url": "https://example.org/hdmap/"
},
{
"alias": "sh",
"url": "http://www.w3.org/ns/shacl#"
}
],
"shapes": [
{
"schema": "OtherShape",
"targetClassPrefix": "General",
"targetClassName": "Other",
"constraints": [
{
"path": {
"prefix": "General",
"value": "yMax"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
},
{
"path": {
"prefix": "General",
"value": "xMax"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
}
]
},
{
"schema": "LinkShape",
"targetClassPrefix": "General",
"targetClassName": "Link",
"constraints": [
{
"path": {
"prefix": "General",
"value": "yMax"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
},
{
"path": {
"prefix": "General",
"value": "other"
},
"datatype": {},
"in": [],
"validations": [],
"children": "OtherShape"
},
{
"path": {
"prefix": "General",
"value": "xMax"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
}
]
},
{
"schema": "BoundingBoxShape",
"targetClassPrefix": "General",
"targetClassName": "BoundingBox",
"constraints": [
{
"path": {
"prefix": "General",
"value": "yMax"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
},
{
"path": {
"prefix": "General",
"value": "licence_link"
},
"datatype": {},
"in": [],
"validations": [],
"children": "LinkShape"
},
{
"path": {
"prefix": "General",
"value": "xMax"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
},
{
"path": {
"prefix": "General",
"value": "yMin"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
},
{
"path": {
"prefix": "General",
"value": "xMin"
},
"datatype": {
"prefix": "xsd",
"value": "float"
},
"in": [],
"validations": []
}
]
},
{
"schema": "BasicAttributesShape",
"targetClassPrefix": "General",
"targetClassName": "BasicAttributes",
"constraints": [
{
"path": {
"prefix": "General",
"value": "General_position_bounding"
},
"name": "bounding",
"datatype": {},
"minCount": 1,
"maxCount": 1,
"description": {
"en": "Bounding box with lat/lon values in WGS84"
},
"in": [],
"validations": [],
"children": "BoundingBoxShape"
},
{
"path": {
"prefix": "General",
"value": "General_format_format_version"
},
"name": "format_version",
"datatype": {
"prefix": "xsd",
"value": "string"
},
"minCount": 1,
"maxCount": 1,
"description": {
"en": "nan"
},
"example": "1.5",
"in": [],
"validations": []
}
]
},
{
"schema": "HDMapShape",
"targetClassPrefix": "HD-Map",
"targetClassName": "HDMap",
"constraints": [
{
"path": {
"prefix": "General",
"value": "BasicAttributes"
},
"name": "Basic Description",
"datatype": {},
"minCount": 1,
"maxCount": 1,
"description": {
"en": "Reference to a Basic Description Shape"
},
"in": [],
"validations": [],
"children": "BasicAttributesShape"
},
{
"path": {
"prefix": "HD-Map",
"value": "HD-Map_quality_accuracy_lane_model_height"
},
"name": "accuracy_lane_model_height",
"datatype": {
"prefix": "xsd",
"value": "float"
},
"minCount": 0,
"maxCount": 1,
"description": {
"en": "accuracy lane modell height"
},
"example": "0.1",
"in": [],
"validations": []
},
{
"path": {
"prefix": "HD-Map",
"value": "HD-Map_quality_accuracy_lane_model_2d"
},
"name": "accuracy_lane_model_2d",
"datatype": {
"prefix": "xsd",
"value": "float"
},
"minCount": 0,
"maxCount": 1,
"description": {
"en": "accuracy of lane modell 2d"
},
"example": "0.1",
"in": [],
"validations": []
}
]
}
]
}
\ No newline at end of file
@prefix HD-Map: <https://example.org/hdmap/> .
@prefix General: <https://example.org/general/> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix skos: <http://www.w3.org/2004/02/skos/core#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
HD-Map:HDMapShape a sh:NodeShape ;
sh:property [
skos:example "0.1" ;
sh:datatype xsd:float ;
sh:description "accuracy of lane modell 2d"@en ;
sh:maxCount "1"^^xsd:unsignedInt ;
sh:message "Validation of accuracy_lane_model_2d failed!"@en ;
sh:minCount "0"^^xsd:unsignedInt ;
sh:name "accuracy_lane_model_2d"@en ;
sh:path HD-Map:HD-Map_quality_accuracy_lane_model_2d ],
[
skos:example "0.1" ;
sh:datatype xsd:float ;
sh:description "accuracy lane modell height"@en ;
sh:maxCount "1"^^xsd:unsignedInt ;
sh:message "Validation of accuracy_lane_model_height failed!"@en ;
sh:minCount "0"^^xsd:unsignedInt ;
sh:name "accuracy_lane_model_height"@en ;
sh:path HD-Map:HD-Map_quality_accuracy_lane_model_height ],
[
sh:node General:BasicAttributesShape ;
sh:description "Reference to a Basic Description Shape"@en ;
sh:maxCount 1 ;
sh:message "Validation of Basic Description failed!"@en ;
sh:minCount 1 ;
sh:name "Basic Description"@en ;
sh:path General:BasicAttributes ] ;
sh:targetClass HD-Map:HDMap .
General:BasicAttributesShape a sh:NodeShape ;
sh:property [
skos:example "1.5" ;
sh:datatype xsd:string ;
sh:description "nan"@en ;
sh:maxCount "1"^^xsd:unsignedInt ;
sh:message "Validation of format_version failed!"@en ;
sh:minCount "1"^^xsd:unsignedInt ;
sh:name "format_version"@en ;
sh:path General:General_format_format_version ] ,
[
sh:node General:BoundingBoxShape ;
sh:description "Bounding box with lat/lon values in WGS84"@en ;
sh:maxCount 1 ;
sh:message "Validation of bounding failed!"@en ;
sh:minCount 1 ;
sh:name "bounding"@en ;
sh:path General:General_position_bounding
] ;
sh:targetClass General:BasicAttributes .
General:BoundingBoxShape a sh:NodeShape ;
sh:property [
sh:datatype xsd:float ;
sh:path General:xMin ;
] ,
[
sh:datatype xsd:float ;
sh:path General:yMin ;
] ,
[
sh:datatype xsd:float ;
sh:path General:xMax ;
] ,
[
sh:node General:LinkShape ;
sh:path General:licence_link ;
] ,
[
sh:datatype xsd:float ;
sh:path General:yMax ;
] ;
sh:targetClass General:BoundingBox .
General:LinkShape a sh:NodeShape ;
sh:property [
sh:datatype xsd:float ;
sh:path General:xMax ;
] ,
[
sh:node General:OtherShape ;
sh:path General:other ;
] ,
[
sh:datatype xsd:float ;
sh:path General:yMax ;
] ;
sh:targetClass General:Link .
General:OtherShape a sh:NodeShape ;
sh:property [
sh:datatype xsd:float ;
sh:path General:xMax ;
] ,
[
sh:datatype xsd:float ;
sh:path General:yMax ;
] ;
sh:targetClass General:Other .
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment