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)
+}