diff --git a/.gitignore b/.gitignore index 46d8767..3329f18 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ -<<<<<<< HEAD # OS .DS_Store diff --git a/RadLex.owl b/RadLex.owl index 17fd4c2..0b18f42 100644 --- a/RadLex.owl +++ b/RadLex.owl @@ -10389,7 +10389,7 @@ duplicate term balloon dilation of structure RID10400 4.1 obs - RID11030 + Ballondilatation einer Struktur @@ -23277,7 +23277,7 @@ AND An artifact resulting in ghost images of a vessel extending across the image in the phase encoding direction. RID11488 - Betonung des pulsatilen Flussartefaktes + Betonung des pulsatilen Flussartefaktes accentuation of pulsatile flow artifact @@ -23889,7 +23889,7 @@ AND RID11529 - Komplikation eines Abszesses + Komplikation eines Abszesses abscess complication @@ -68441,7 +68441,7 @@ The LI-RADS definition of “size” correspons to the definition of the longest Brodmann area 5 of left post central gyrus RID13601 4.3 obs - RID25948 + Brodmann-Areal 5 des linken Gyrus postcentralis @@ -498439,7 +498439,7 @@ FMA has same as pelvis RID2507 - + tenia choroidea of lateral ventricle RID27787 3.14 obs @@ -540446,7 +540446,7 @@ US: A mass that is spherical, ball-shaped, circular or globular. A round mass h anterior thoracic region front of chest pectus - Vorderseite des Brustkorbs + Vorderseite des Brustkorbs anterior chest @@ -544783,7 +544783,7 @@ US: A mass that is spherical, ball-shaped, circular or globular. A round mass h lumbar region regio lumbalis regio lumbalis - Rückwand des Abdomens + Rückwand des Abdomens back of abdomen @@ -741605,7 +741605,7 @@ not yet enhanced early hepatic arterial phase RID39534 4.1 obs - RID11082 + LI-RADS early arterial phase (liver) früharterielle Phase der Leber @@ -741625,7 +741625,7 @@ enhanced late hepatic arterial phase RID39535 4.1 obs - RID39127 + LI-RADS spätarterielle Phase der Leber @@ -871055,7 +871055,7 @@ Enhancement from hypo on precontrast to iso on arterial phase does not qualify a RID45693 Playbook - Bildgebung in Bloodpool- phase + Bildgebung in Bloodpool-Phase blood pool imaging @@ -979816,7 +979816,7 @@ the apex - + "capsule of prostate" and "pseudocapsule of prostate" were determined to be the same entity. This term was deprecated in favor of the existing term with the preferred "pseudocapsule". 2014-07-07T00:00:00 PI-RADS: Tumor involvement of the “capsule” or extension across the “capsule” @@ -993046,7 +993046,7 @@ strong association with benignity RID50296 3.15 new PI-RADS v2.1 - PI-RADS 1 - Very low (Lesion) + PI-RADS 1 - Very low (Lesion) @@ -993060,7 +993060,7 @@ strong association with benignity RID50297 3.15 new PI-RADS v2.1 - PI-RADS 2 - Low (Lesion) + PI-RADS 2 - Low (Lesion) @@ -998169,7 +998169,7 @@ Does not apply to blood pool agents. Beverly Collins 2022-01-21T21:16:57.865324Z - RID60643 + RID50643 4.2 new LOINC view Canale @@ -998801,7 +998801,7 @@ Does not apply to blood pool agents. Beverly Collins 2022-08-19T16:24:49.983716Z - RID50580 + RID50680 4.2 new ‘CT Kidney and Abdominal Renal Mass’ report template invades collecting system diff --git a/tests/robot-report-profile.txt b/tests/robot-report-profile.txt index 00c1f4c..d04314d 100644 --- a/tests/robot-report-profile.txt +++ b/tests/robot-report-profile.txt @@ -1 +1,8 @@ -ERROR file:./tests/sparql/robot/leading_trailing_multi_whitespace.rq \ No newline at end of file +ERROR file:./tests/sparql/robot/leading_trailing_multi_whitespace.rq +ERROR file:./tests/sparql/robot/empty_annotation_value.rq +ERROR file:./tests/sparql/robot/mismatched_radlexid.rq +ERROR file:./tests/sparql/robot/literal_replaced_by_value.rq +ERROR file:./tests/sparql/robot/dangling_replaced_by_target.rq +ERROR file:./tests/sparql/robot/live_class_with_replaced_by.rq +ERROR file:./tests/sparql/robot/live_class_with_preferred_name_for_obsolete.rq +ERROR file:./tests/sparql/robot/live_class_under_obsolete_parent.rq diff --git a/tests/sparql/robot/dangling_replaced_by_target.rq b/tests/sparql/robot/dangling_replaced_by_target.rq new file mode 100644 index 0000000..e7206b2 --- /dev/null +++ b/tests/sparql/robot/dangling_replaced_by_target.rq @@ -0,0 +1,22 @@ +PREFIX owl: +PREFIX rid: + +# +# Part of the RadLex ontology SPARQL test suite. Bindings to this query represent violations of the test. +# +# Test that every rid:Replaced_by pointer aims at a class declared in RadLex. A pointer to an undeclared IRI, +# such as a mistyped RID, cannot be followed. A pointer to a class that is itself obsolete is allowed: the +# chain records the retirement history, and a consumer can follow it to the end. +# +# VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: +# - The obsolete class carrying the pointer. +# - rid:Replaced_by. +# - The undeclared target IRI. +# +SELECT ?entity ?property ?value +WHERE { + BIND(rid:Replaced_by AS ?property) + ?entity ?property ?value . + FILTER(isIRI(?value)) + FILTER NOT EXISTS { ?value a owl:Class } +} diff --git a/tests/sparql/robot/empty_annotation_value.rq b/tests/sparql/robot/empty_annotation_value.rq new file mode 100644 index 0000000..508fba3 --- /dev/null +++ b/tests/sparql/robot/empty_annotation_value.rq @@ -0,0 +1,22 @@ +PREFIX rdfs: +PREFIX owl: + +# +# Part of the RadLex ontology SPARQL test suite. Bindings to this query represent violations of the test. +# +# Test that no annotation assertion has an empty or whitespace-only value. An empty assertion falsely signals +# that the field is populated. Every declared owl:AnnotationProperty is covered, plus rdfs:label, which is a +# built-in and therefore not declared. +# +# VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: +# - The entity carrying the empty assertion. +# - The annotation property. +# - The empty or whitespace value. +# +SELECT ?entity ?property ?value +WHERE { + { ?property a owl:AnnotationProperty } UNION { BIND(rdfs:label AS ?property) } + ?entity ?property ?value . + FILTER(isLiteral(?value)) + FILTER(REGEX(STR(?value), "^\\s*$")) +} diff --git a/tests/sparql/robot/leading_trailing_multi_whitespace.rq b/tests/sparql/robot/leading_trailing_multi_whitespace.rq index 6b255df..67a1128 100644 --- a/tests/sparql/robot/leading_trailing_multi_whitespace.rq +++ b/tests/sparql/robot/leading_trailing_multi_whitespace.rq @@ -9,6 +9,10 @@ PREFIX rid: # Test for stray whitespace on values (strings) of the annotation properties used for names. Specifically, this test # prohibits: leading or trailing whitespace, or consecutive whitespace characters within a string. # +# The constrained properties are checked directly and through any declared sub-property. Matching only through +# rdfs:subPropertyOf would skip rdfs:label and rid:UMLS_Term, which have no sub-properties (rid:Synonym is caught +# that way only because it is declared as a sub-property of itself). +# # VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: # - The entity on which the violation occurs (e.g., the class). # - The property on which the violation occurs (i.e., the annotation property, e.g. rdfs:label). @@ -17,7 +21,7 @@ PREFIX rid: SELECT ?entity ?property ?value WHERE { VALUES ?constrained_property {rdfs:label rid:Synonym rid:UMLS_Term} . - ?property rdfs:subPropertyOf ?constrained_property . + ?property rdfs:subPropertyOf* ?constrained_property . ?entity ?property ?value . FILTER(REGEX(STR(?value), "^\\s|\\s+$|\\s\\s")) } diff --git a/tests/sparql/robot/literal_replaced_by_value.rq b/tests/sparql/robot/literal_replaced_by_value.rq new file mode 100644 index 0000000..b5944a2 --- /dev/null +++ b/tests/sparql/robot/literal_replaced_by_value.rq @@ -0,0 +1,19 @@ +PREFIX rid: + +# +# Part of the RadLex ontology SPARQL test suite. Bindings to this query represent violations of the test. +# +# Test that every rid:Replaced_by value is an IRI reference to another class, not a string literal such as +# "RID11030". A literal cannot be followed by tooling that walks obsolete terms to their replacements. +# +# VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: +# - The obsolete class carrying the pointer. +# - rid:Replaced_by. +# - The literal value that should have been an IRI. +# +SELECT ?entity ?property ?value +WHERE { + BIND(rid:Replaced_by AS ?property) + ?entity ?property ?value . + FILTER(isLiteral(?value)) +} diff --git a/tests/sparql/robot/live_class_under_obsolete_parent.rq b/tests/sparql/robot/live_class_under_obsolete_parent.rq new file mode 100644 index 0000000..8d02bf1 --- /dev/null +++ b/tests/sparql/robot/live_class_under_obsolete_parent.rq @@ -0,0 +1,24 @@ +PREFIX rdfs: +PREFIX rid: + +# +# Part of the RadLex ontology SPARQL test suite. Bindings to this query represent violations of the test. +# +# Test that no class is filed under an obsolete class without itself being marked obsolete. An obsolete class +# is one filed, directly or through another obsolete class, under RID15849 ("Obsolete RadLex Term"). Filing +# makes every descendant obsolete, so a live class left under a class being retired is retired silently. +# rid:Preferred_Name_for_Obsolete is the per-class mark that the retirement was intended. RID15849 itself is +# not an obsolete parent, since obsolete classes are meant to hang under it. +# +# VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: +# - The class that was never marked obsolete. +# - rdfs:subClassOf. +# - The obsolete parent. +# +SELECT ?entity ?property ?value +WHERE { + BIND(rdfs:subClassOf AS ?property) + ?entity ?property ?value . + ?value rdfs:subClassOf+ rid:RID15849 . + FILTER NOT EXISTS { ?entity rid:Preferred_Name_for_Obsolete ?_name } +} diff --git a/tests/sparql/robot/live_class_with_preferred_name_for_obsolete.rq b/tests/sparql/robot/live_class_with_preferred_name_for_obsolete.rq new file mode 100644 index 0000000..b99fd21 --- /dev/null +++ b/tests/sparql/robot/live_class_with_preferred_name_for_obsolete.rq @@ -0,0 +1,22 @@ +PREFIX rdfs: +PREFIX rid: + +# +# Part of the RadLex ontology SPARQL test suite. Bindings to this query represent violations of the test. +# +# Test that only obsolete classes carry rid:Preferred_Name_for_Obsolete. An obsolete class is one filed, +# directly or through another obsolete class, under RID15849 ("Obsolete RadLex Term"). A live class carrying +# the property was made obsolete in name but never filed under RID15849, so tools that exclude RID15849's subclasses +# still offer it as a live term. +# +# VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: +# - The live class carrying the property. +# - rid:Preferred_Name_for_Obsolete. +# - The obsolete name. +# +SELECT ?entity ?property ?value +WHERE { + BIND(rid:Preferred_Name_for_Obsolete AS ?property) + ?entity ?property ?value . + FILTER NOT EXISTS { ?entity rdfs:subClassOf+ rid:RID15849 } +} diff --git a/tests/sparql/robot/live_class_with_replaced_by.rq b/tests/sparql/robot/live_class_with_replaced_by.rq new file mode 100644 index 0000000..718df01 --- /dev/null +++ b/tests/sparql/robot/live_class_with_replaced_by.rq @@ -0,0 +1,21 @@ +PREFIX rdfs: +PREFIX rid: + +# +# Part of the RadLex ontology SPARQL test suite. Bindings to this query represent violations of the test. +# +# Test that only obsolete classes carry rid:Replaced_by. An obsolete class is one filed, directly or through +# another obsolete class, under RID15849 ("Obsolete RadLex Term"). A live class with a replacement pointer is +# contradictory: either the class was never filed as obsolete or the pointer is stray. +# +# VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: +# - The live class carrying the pointer. +# - rid:Replaced_by. +# - The pointer's target. +# +SELECT ?entity ?property ?value +WHERE { + BIND(rid:Replaced_by AS ?property) + ?entity ?property ?value . + FILTER NOT EXISTS { ?entity rdfs:subClassOf+ rid:RID15849 } +} diff --git a/tests/sparql/robot/mismatched_radlexid.rq b/tests/sparql/robot/mismatched_radlexid.rq new file mode 100644 index 0000000..1efd594 --- /dev/null +++ b/tests/sparql/robot/mismatched_radlexid.rq @@ -0,0 +1,28 @@ +PREFIX rdfs: +PREFIX owl: +PREFIX rid: + +# +# Part of the RadLex ontology SPARQL test suite. Bindings to this query represent violations of the test. +# +# Test that a class's rid:RadLexID restates the local name of its own IRI. The ID is redundant with the IRI by +# design, so any disagreement is a copy or typing error that desynchronises ID-keyed consumers from IRI-keyed +# ones. A class in the RID namespace with no rid:RadLexID at all is also a violation. +# +# Scope: classes whose IRI local name has the form RID. +# +# VIOLATIONS will be bindings that have, on ?entity, ?property, and ?value respectively: +# - The class whose ID disagrees with (or is missing from) its IRI. +# - rid:RadLexID. +# - The ID value found, or the empty string when the class carries none. +# +SELECT ?entity ?property ?value +WHERE { + ?entity a owl:Class . + FILTER(REGEX(STR(?entity), "^http://www\\.radlex\\.org/RID/RID[0-9]+$")) + BIND(rid:RadLexID AS ?property) + BIND(REPLACE(STR(?entity), "^http://www\\.radlex\\.org/RID/", "") AS ?expected) + OPTIONAL { ?entity rid:RadLexID ?id } + BIND(COALESCE(STR(?id), "") AS ?value) + FILTER(?value != ?expected) +}