Skip to content

Commit

Permalink
Merge pull request #607 from ucoProject/Feature-Issue-602-NewDictiona…
Browse files Browse the repository at this point in the history
…ries

Issue 602: Add review mechanisms for key-uniqueness in types:Dictionary
  • Loading branch information
plbt5 authored Jul 26, 2024
2 parents c4294c7 + 06392e9 commit 9a355e4
Show file tree
Hide file tree
Showing 8 changed files with 588 additions and 2 deletions.
102 changes: 100 additions & 2 deletions ontology/uco/types/types.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,47 @@ types:Dictionary
;
rdfs:subClassOf core:UcoInherentCharacterizationThing ;
rdfs:label "Dictionary"@en ;
rdfs:comment "A dictionary is list of (term/key, value) pairs with each term/key existing no more than once."@en ;
rdfs:comment "A dictionary is list of (term/key, value) pairs with each term/key having an expectation to exist no more than once. types:Dictionary alone does not validate this expectation, but validation is available. For use cases where this expectation must be validated, the subclass types:ProperDictionary should be used instead of types:Dictionary. For instances where this expectation has been found to be violated, the subclass types:ImproperDictionary should be used instead of types:Dictionary."@en ;
sh:property [
sh:class types:DictionaryEntry ;
sh:minCount "1"^^xsd:integer ;
sh:nodeKind sh:IRI ;
sh:path types:entry ;
] ;
sh:targetClass types:Dictionary ;
.

types:Dictionary-keyUniqueness-shape
a sh:NodeShape ;
sh:description "This shape is separated from the types:Dictionary class-shape in order to associate a warning-severity SPARQL-based shape."@en ;
sh:severity sh:Warning ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:message "A key in a dictionary should appear no more than once. The value literal does. Please consider using the types:ImproperDictionary class and types:repeatsKey property."@en ;
sh:select """
PREFIX types: <https://ontology.unifiedcyberontology.org/uco/types/>
SELECT $this ?value
WHERE {
$this
types:entry/types:key ?value ;
.
FILTER NOT EXISTS {
$this
a types:ImproperDictionary ;
.
}
FILTER NOT EXISTS {
$this
a types:ProperDictionary ;
.
}
}
GROUP BY ?value
HAVING (COUNT(?value) > 1)
""" ;
] ;
sh:targetClass types:Dictionary ;
.

types:DictionaryEntry
a
owl:Class ,
Expand Down Expand Up @@ -167,11 +198,64 @@ types:Identifier
rdfs:comment "An identifier is a string conformant to the specified UUID-based format for UCO object identifiers."@en ;
.

types:ImproperDictionary
a
owl:Class ,
sh:NodeShape
;
rdfs:subClassOf types:Dictionary ;
rdfs:label "ImproperDictionary"@en ;
owl:disjointWith types:ProperDictionary ;
sh:property [
sh:datatype xsd:string ;
sh:nodeKind sh:Literal ;
sh:path types:repeatsKey ;
] ;
sh:targetClass types:ImproperDictionary ;
.

types:ImproperDictionary-disjointWith-ProperDictionary-shape
a sh:NodeShape ;
sh:message "types:ImproperDictionary and types:ProperDictionary are disjoint classes."@en ;
sh:not [
a sh:NodeShape ;
sh:class types:ProperDictionary ;
] ;
sh:targetClass types:ImproperDictionary ;
.

types:NativeFormatString
a rdfs:Datatype ;
rdfs:comment "Specifies data in its native format of some external language. The data may be encoded in Base64 per [RFC4648]. Data encoded in Base64 must be denoted as such using the encoded property."@en ;
.

types:ProperDictionary
a
owl:Class ,
sh:NodeShape
;
rdfs:subClassOf types:Dictionary ;
rdfs:label "ProperDictionary"@en ;
rdfs:comment "A proper dictionary is list of (term/key, value) pairs with each term/key existing no more than once."@en ;
owl:disjointWith types:ImproperDictionary ;
sh:sparql [
a sh:SPARQLConstraint ;
sh:message "A key in a proper dictionary can appear no more than once."@en ;
sh:select """
PREFIX types: <https://ontology.unifiedcyberontology.org/uco/types/>
SELECT $this ?value
WHERE {
$this
types:entry/types:key ?value ;
.
}
GROUP BY ?value
HAVING (COUNT(?value) > 1)
""" ;
] ;
sh:targetClass types:ProperDictionary ;
.

types:StructuredText
a rdfs:Datatype ;
rdfs:comment "Expresses string-based data in some information structuring format (e.g., HTML5)."@en ;
Expand Down Expand Up @@ -269,6 +353,20 @@ types:key
rdfs:range xsd:string ;
.

types:repeatsKey
a owl:DatatypeProperty ;
rdfs:label "repeatsKey"@en ;
rdfs:comment "A key found to be repeated in multiple dictionary entries within one dictionary."@en ;
rdfs:domain types:ImproperDictionary ;
rdfs:range xsd:string ;
.

types:repeatsKey-subjects-shape
a sh:NodeShape ;
sh:class types:ImproperDictionary ;
sh:targetSubjectsOf types:repeatsKey ;
.

types:threadNextItem
a owl:ObjectProperty ;
rdfs:subPropertyOf types:threadSuccessor ;
Expand Down
4 changes: 4 additions & 0 deletions tests/examples/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ all: \
configuration_setting_XFAIL_validation.ttl \
database_records_PASS_validation.ttl \
database_records_XFAIL_validation.ttl \
dictionary_PASS_validation.ttl \
dictionary_XFAIL_validation.ttl \
disjointedness_PASS_validation.ttl \
event_XFAIL_validation.ttl \
file_url_PASS_validation.ttl \
Expand Down Expand Up @@ -101,6 +103,8 @@ check: \
configuration_setting_XFAIL_validation.ttl \
database_records_PASS_validation.ttl \
database_records_XFAIL_validation.ttl \
dictionary_PASS_validation.ttl \
dictionary_XFAIL_validation.ttl \
disjointedness_PASS_validation.ttl \
event_XFAIL_validation.ttl \
file_url_PASS_validation.ttl \
Expand Down
26 changes: 26 additions & 0 deletions tests/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,32 @@ Two instance data files are currently in the directory:
SHACL validation results are stored in corresponding files named `..._validation.ttl`, to present the current state of validation conditions.


## Design of the Dictionary tests

The `Dictionary` objects in the `dictionary_*.json` files cover these combinations of asserted type (proper dictionary, improper dictionary, or the generic parent class), whether a dictionary entry key is repeated in the data, and whether the `repeatsKey` property is asserted. (P/X denotes whether the instance is a PASS or XFAIL test case.)

| uuid | P/X | Dictionary type | Key repeats | repeatsKey asserted |
| --- | --- | --- | --- | --- |
| `3bb38b3e` | P | `Dictionary` | no | no |
| `e6dc9c2e` | X | `Dictionary` | no | yes |
| `e9adf6c1` | P | `Dictionary` | yes | no |
| `34ac0c49` | X | `Dictionary` | yes | yes |
| `cbc1c80d` | P | `ImproperDictionary` | no | no |
| `7fa3ea45` | P | `ImproperDictionary` | no | yes |
| `14e28425` | P | `ImproperDictionary` | yes | no |
| `a8e5e8e1` | P | `ImproperDictionary` | yes | yes |
| `eaded28e` | P | `ProperDictionary` | no | no |
| `8114819f` | X | `ProperDictionary` | no | yes |
| `b2baf8af` | X | `ProperDictionary` | yes | no |
| `f5ae2e6a` | X | `ProperDictionary` | yes | yes |

Other miscellaneous tests are added without full combinatoric review:

* `kb:ProperDictionary-f5ae2e6a-9b10-46f3-8441-30aada36aa1b` also demonstrates an XFAIL case where a key-value *pair* is repeated.
* `kb:ImproperDictionary-7fa3ea45-6426-4ad3-bb5f-7559e07adeb4` also demonstrates a PASS case where `repeatsKey`'s value is not in the supplied dictionary.
* `kb:Dictionary-5bc55661-4808-48e6-9e02-80a153eee5d3` demonstrates an XFAIL case where the disjoint `Dictionary` subtypes are both asserted.


## Design of the Relationship tests

The `Relationship` objects in the `relationship_*.json` files include a numbering scheme in their identifiers, (object class)-(lexical value)-(datatype). These track the following matrix of test cases:
Expand Down
125 changes: 125 additions & 0 deletions tests/examples/dictionary_PASS.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
{
"@context": {
"kb": "http://example.org/kb/",
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
"types": "https://ontology.unifiedcyberontology.org/uco/types/"
},
"@graph": [
{
"@id": "kb:Dictionary-3bb38b3e-d47a-43c8-8a77-afc0e6655ce1",
"@type": "types:Dictionary",
"types:entry": [
{
"@id": "kb:DictionaryEntry-b8a01d49-53c1-440f-a2d5-618b58801d37",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "1"
},
{
"@id": "kb:DictionaryEntry-6cac6c2c-5d4e-45f5-b784-c029c9f9fb6d",
"@type": "types:DictionaryEntry",
"types:key": "y",
"types:value": "2"
}
]
},
{
"@id": "kb:ProperDictionary-eaded28e-0bf8-4df1-aee8-84d22c09702c",
"@type": "types:ProperDictionary",
"types:entry": [
{
"@id": "kb:DictionaryEntry-314212eb-39c4-4bf3-be3a-f07c38f0eae8",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "1"
},
{
"@id": "kb:DictionaryEntry-9ec24a1a-7e99-41c9-ba7d-9d23f11babb4",
"@type": "types:DictionaryEntry",
"types:key": "y",
"types:value": "2"
}
]
},
{
"@id": "kb:ImproperDictionary-a8e5e8e1-b3de-4ac4-99dd-e36f96beea4d",
"@type": "types:ImproperDictionary",
"types:repeatsKey": "x",
"types:entry": [
{
"@id": "kb:DictionaryEntry-55786f64-534d-4e8c-8a64-616f708ea4d3",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "1"
},
{
"@id": "kb:DictionaryEntry-d1a83c3d-cbe6-40b0-bb26-3527c47a01d8",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "2"
}
]
},
{
"@id": "kb:Dictionary-e9adf6c1-0287-4290-95a9-c94a128d7ff6",
"@type": "types:Dictionary",
"rdfs:comment": "This dictionary, not being typed as a ProperDictionary, will not trigger a warning from having two entries keyed with value 'x'.",
"types:entry": [
{
"@id": "kb:DictionaryEntry-20431f00-64a3-4c0f-94a4-1eb09f8a6b6a",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "1"
},
{
"@id": "kb:DictionaryEntry-f187ee7f-12fb-4580-966d-47bf1afd4975",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "1"
}
]
},
{
"@id": "kb:ImproperDictionary-7fa3ea45-6426-4ad3-bb5f-7559e07adeb4",
"@type": "types:ImproperDictionary",
"repeatsKey": "z"
},
{
"@id": "kb:ImproperDictionary-14e28425-00c1-4f11-b2ed-21390fc0749a",
"@type": "types:ImproperDictionary",
"types:entry": [
{
"@id": "kb:DictionaryEntry-09f23642-389b-4553-b5be-283a6160f534",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "1"
},
{
"@id": "kb:DictionaryEntry-7a84a0d6-d1cd-4291-afb4-c834d611898d",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "2"
}
]
},
{
"@id": "kb:ImproperDictionary-cbc1c80d-1bad-4947-8459-c53ff61e8bfa",
"@type": "types:ImproperDictionary",
"rdfs:comment": "This improper dictionary has no repeated key or assertion of a repeated key. This should not trigger a data error, because the information in the graph could merely be incomplete.",
"types:entry": [
{
"@id": "kb:DictionaryEntry-ca1910ab-fa26-402a-86bb-229f490dd89a",
"@type": "types:DictionaryEntry",
"types:key": "x",
"types:value": "1"
},
{
"@id": "kb:DictionaryEntry-2a13e674-5e95-4a7a-9fac-c90417dcd97c",
"@type": "types:DictionaryEntry",
"types:key": "y",
"types:value": "2"
}
]
}
]
}
46 changes: 46 additions & 0 deletions tests/examples/dictionary_PASS_validation.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .
@prefix types: <https://ontology.unifiedcyberontology.org/uco/types/> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

[]
a sh:ValidationReport ;
sh:conforms "true"^^xsd:boolean ;
sh:result [
a sh:ValidationResult ;
sh:focusNode <http://example.org/kb/Dictionary-e9adf6c1-0287-4290-95a9-c94a128d7ff6> ;
sh:resultMessage "A key in a dictionary should appear no more than once. The value literal does. Please consider using the types:ImproperDictionary class and types:repeatsKey property." ;
sh:resultSeverity sh:Warning ;
sh:sourceConstraint [
a sh:SPARQLConstraint ;
sh:message "A key in a dictionary should appear no more than once. The value literal does. Please consider using the types:ImproperDictionary class and types:repeatsKey property."@en ;
sh:select """
PREFIX types: <https://ontology.unifiedcyberontology.org/uco/types/>
SELECT $this ?value
WHERE {
$this
types:entry/types:key ?value ;
.
FILTER NOT EXISTS {
$this
a types:ImproperDictionary ;
.
}
FILTER NOT EXISTS {
$this
a types:ProperDictionary ;
.
}
}
GROUP BY ?value
HAVING (COUNT(?value) > 1)
""" ;
] ;
sh:sourceConstraintComponent sh:SPARQLConstraintComponent ;
sh:sourceShape types:Dictionary-keyUniqueness-shape ;
sh:value "x" ;
] ;
.

Loading

0 comments on commit 9a355e4

Please sign in to comment.