Closed dbooth-boston closed 2 years ago
REJECTED: Extension option 1a: Map underscore attributes to non-underscore (non-tree version). See https://github.com/fhircat/fhir_rdf_validator/blob/master/tutorial/FHIRR5.md#primitive-type-and-id-extensions---extensions-option-1-map-underscore-attributes-to-non-underscore
NOTE: This option was eliminated on 9/9/21
Example JSON:
{
"resourceType": "Patient",
"id": "example",
"birthDate": "1974-12-25",
"_birthDate": {
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/patient-birthTime",
"valueDateTime": "1974-12-25T14:35:45-05:00"
}
]
}
}
Corresponding Turtle 1a:
@prefix fhir: <http://hl7.org/fhir/> .
@prefix pt: <http://build.fhir.org/Patient/> .
pt:example a fhir:Patient ;
fhir:Patient.birthDate "1974-12-25" ;
fhir:Patient.birthDate [
fhir:DomainResource.extension _:b1 ;
fhir:DomainResource.extension [
fhir:ordered ( _:b1 ) .
] ;
] ;
fhir:Resource.id "example" ;
fhir:nodeRole "fhir:treeRoot" .
_:b1 fhir:Extension.url "http://hl7.org/fhir/StructureDefinition/patient-birthTime" ;
fhir:Extension.valueDateTime "1974-12-25T14:35:45-05:00" .
Pros:
foo
rather than to _foo
or something else.Cons:
REJECTED: Extension option 1b: Map underscore attributes to non-underscore (tree version). Similar to 1a, but simplified to use a tree structure (to eliminate explicit blank nodes), and to use the same extension structure that R4 used, in addition to directly indicating the primitive value.
NOTE: This option was eliminated on 9/9/21
Turtle 1b:
pt:example a fhir:Patient ;
fhir:Patient.birthDate "1974-12-25" ;
fhir:Patient.birthDate [
fhir:value "1974-12-25"^^xsd:date;
fhir:Element.extension [
fhir:index 0;
fhir:Extension.url [ fhir:value "http://hl7.org/fhir/StructureDefinition/patient-birthTime" ];
fhir:Extension.valueDateTime [ fhir:value "1974-12-25T14:35:45-05:00"^^xsd:dateTime ]
]
];
Pros:
foo
rather than to _foo
or something else.Cons:
REJECTED: Option 2: Sibling extension property with punning. In this option, an extension for Patient / birthDate
would be placed under Patient / extension / birthDate
, and an extension for Patient / name
would be placed under Patient / extension / name
, and so on. This means that the resulting object would have properties/attributes like this (using approximate SPARQL path syntax):
NOTE: This option was eliminated on 9/9/21
Patient / id
Patient / birthDate
Patient / name
Patient / extension / birthDate
Patient / extension / name
etc.
Primitive example in JSON:
{
"resourceType": "Patient",
"id": "example",
"birthDate": "1974-12-25",
"_birthDate": {
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/patient-birthTime",
"valueDateTime": "1974-12-25T14:35:45-05:00"
}
]
}
}
Primitive example as Turtle (option 2, REJECTED on 9/9/21):
<http://build.fhir.org/Patient/example>
fhir:nodeRole> "fhir:treeRoot" .
fhir:Resource.id "example" .
fhir:Patient.birthDate "1974-12-25" .
fhir:Patient.extension [
fhir:Patient.birthDate [
fhir:index 0; # Ordering mechanism TBD
fhir:Extension.url "http://hl7.org/fhir/StructureDefinition/patient-birthTime" .
fhir:Extension.valueDateTime> "1974-12-25T14:35:45-05:00" .
] .
] .
Pros:
foo
to _foo
.Cons:
extension/foo
instead of foo/extension
.REJECTED: Extension option 3: Use underscore attributes for extensions, like in FHIR/JSON. This option would directly follow existing FHIR/JSON, but use ontology relationships to connect attributes to their underscore versions. See https://github.com/fhircat/FHIRCat/issues/4
NOTE: This option was eliminated on 9/9/21
JSON:
"active": true,
"_active": {
"extension" : [ {
"url" : "http://example.org/fhir/boolean/Certainty",
"valueDecimal" : 0.75
}]
}
Turtle (option 3):
[] fhir:active true ;
fhir:_active [
fhir:extension [
fhir:index 0 ; # To retain ordering of multiple extensions
fhir:url "http://example.org/fhir/boolean/Certainty" ;
fhir:valueDecimal 0.75
]
] .
. . .
# Ontology relationship:
fhir:active fhir:extensionProperty fhir:_active .
Pros:
Cons:
Turtle (option 3U):
[] fhir:active true ;
fhir:_active [
fhir:extension [
fhir:index 0 ; # To retain ordering of multiple extensions
<http://example.org/fhir/boolean/Certainty> 0.75 # i.e. "0.75"^^xsd:Decimal
]
] .
. . .
# Ontology relationships:
fhir:active fhir:extensionHook fhir:_active .
fhir:extensionProperty <http://example.org/fhir/boolean/Certainty> .
Pros:
Cons:
Option 3b:
[] fhir:active true ;
fhir:_active [
a fhir:Extension ;
fhir:index 0 ; # To retain ordering of multiple extensions
fhir:url "http://example.org/fhir/boolean/Certainty" ;
fhir:valueDecimal "0.75"^^xsd:decimal
] .
. . .
# Ontology relationship:
fhir:active fhir:extensionProperty fhir:_active .
Pros:
Cons:
Option 3b.1:
Same as 3b but keeps the original value in the extension for parity with modifier extensions:
[] fhir:active true ;
fhir:_active [
a fhir:Extension ;
fhir:originalValue true ; # <---
fhir:index 0 ; # To retain ordering of multiple extensions
fhir:url "http://example.org/fhir/boolean/Certainty" ;
fhir:valueDecimal "0.75"^^xsd:decimal
] .
Option 3c:
Keep non-modifier extension processing uniform regardless of whether there's a modifier extension on the same scalar
[] fhir:active true ;
fhir:_active [
a fhir:Extension ;
fhir:origValueBoolean true ; # redunancy against `fhir:active true`
fhir:index 0 ; # To retain ordering of multiple extensions
fhir:url "http://example.org/fhir/boolean/Certainty" ;
fhir:valueDecimal 0.75
] .
. . .
Pros:
Cons:
Option 3bU:
[] fhir:active true ;
fhir:_active [
a fhir:Extension ;
fhir:index 0 ; # To retain ordering of multiple extensions
<http://example.org/fhir/boolean/Certainty> 0.75
] .
. . .
# Ontology relationships:
fhir:active fhir:extensionHook fhir:_active .
fhir:extensionProperty <http://example.org/fhir/boolean/Certainty> .
Pros:
Cons:
FYI, there was a question about this in the FHIR Community forum: http://community.fhir.org/t/anonymous-blank-nodes-in-ttl-files-vs-resource-nodes/1940/2
I like extension option 2, suboption "Primitive example converted to R5 JSON-LD". However, I think the Turtle example is slightly wrong, since I don't think you can include dictionary-type structures directly in Turtle confusing, because then we can't set a domain on the fhir:Patient.birthDate
property, which could be either an extension or a patient. I think this would work better:
REJECTED: Option 2b: Sibling extension property connected by fhir:extensionPath:
NOTE: This option was eliminated on 9/9/21
<http://build.fhir.org/Patient/example>
fhir:nodeRole "fhir:treeRoot" ;
fhir:Resource.id "example" ;
fhir:Patient.birthDate "1974-12-25" ;
fhir:extension
[
fhir:extensionPath fhir:Patient.birthDate ;
fhir:index 0 ; # Ordering mechanism TBD
fhir:Extension.url <http://hl7.org/fhir/StructureDefinition/patient-birthTime> ;
fhir:Extension.valueDateTime "1974-12-25T14:35:45-05:00"
]
Note: I (@dbooth-boston ) took the liberty of slightly editing this to remove the unneeded outer list around the extension, since the fhir:index property is intended to retain the ordering of multiple extensions.
Pros:
foo
to _foo
.Cons:
extension/foo
instead of foo/extension
.REJECTED Extension option 4a: Have both a primary object property and a short-cut datatype property
Note: This option was eliminated on 9/16/21.
This is conceptually similar to option 3, in that it uses two properties, though the naming convention differs and the object would include the entire R4 object instead of only holding the extension:
fhir:Patient.birthDateValue "1974-12-25"^^xsd:date ;
fhir:Patient.birthDate [
fhir:value "1974-12-25"^^xsd:date;
fhir:Element.extension [
fhir:index 0;
fhir:Extension.url [ fhir:value "http://hl7.org/fhir/StructureDefinition/patient-birthTime" ];
fhir:Extension.valueDateTime [ fhir:value "1974-12-25T14:35:45-05:00"^^xsd:dateTime ]
]
];
. . .
# Ontology relationship:
fhir:Patient.birthDateValue fhir:extensionProperty fhir:Patient.birthDate .
Pros:
Cons:
REJECTED: Extension option 4b: Have both a primary datatype property and an adjunct object property
Note: This option was eliminated on 9/16/21.
Similar to option 4a, but reversing the naming convention:
fhir:Patient.birthDate "1974-12-25"^^xsd:date ;
fhir:Patient.birthDateExtension [
fhir:value "1974-12-25"^^xsd:date;
fhir:Element.extension [
fhir:index 0;
fhir:Extension.url [ fhir:value "http://hl7.org/fhir/StructureDefinition/patient-birthTime" ];
fhir:Extension.valueDateTime [ fhir:value "1974-12-25T14:35:45-05:00"^^xsd:dateTime ]
]
];
. . .
# Ontology relationship:
fhir:Patient.birthDate fhir:extensionProperty fhir:Patient.birthDateExtension .
Pros:
Cons:
fhir:Patient.birthDate [
fhir:value "1974-12-25"^^xsd:date ;
<http://hl7.org/fhir/StructureDefinition/patient-birthTime> [
fhir:index 0;
fhir:Extension.valueDateTime "1974-12-25T14:35:45-05:00"^^xsd:dateTime
] ;
# Ontology:
<http://hl7.org/fhir/StructureDefinition/patient-birthTime> a fhir:ExtensionProperty .
# Extension ontology:
fhir:Patient.birthDate fhir:extensionProperty <http://hl7.org/fhir/StructureDefinition/patient-birthTime> .
Pros:
Cons:
Copied this checklist item from the preprocessing checklist issue: Connect FHIR extension element "_foo" to element "foo", so that an RDF query can traverse from any element ?foo to its extensions, without hard-coding the element names. See slide 8: https://lists.w3.org/Archives/Public/www-archive/2019Nov/att-0000/FHIRRdf.pdf
The issue of connecting FHIR extension element "_foo" to element "foo" does not necessarily have to be addressed in the preprocessor, because it is a static relationship -- it does not depend on the instance data -- so it could be included in the ontology instead of being generated in the instance data.
While hoisted scalars are wayyy nicer to query or access via graph API, hoisting conflicts with the fact that OWL (DL?) forces a choice between ObjectProperties and DatatypeProperties. This arises with e.g. rd**H fhir:code:
fhir:code [
fhir:coding (
[
a <http://loinc.org/rdf#15074-8>;
fhir:system "http://loinc.org"^^xsd:anyURI;
fhir:code "15074-8";
fhir:display "Glucose [Moles/volume] in Blood"
]
)
];
where fhir:code appears to be both an ObjectProperty:
<Obvservation> rdfs:subClassOf [owl:obProperty fhir:code ; owl:allValuesFrom <CodeableConcept>].
and a DatatypeProperty:
<Coding> rdfs:subClassOf [owl:obProperty fhir:code ; owl:allValuesFrom xsd:string].
Another example is rdv*H fhir:value:
fhir:value [
a fhir:Quantity;
fhir:value 6.3;
fhir:system "http://unitsofmeasure.org"^^xsd:anyURI;
fhir:code "mmol/L"
];
with fhir:value an ObjectProperty:
<Observation> rdfs:subClassOf [
owl:onProperty fhir:value ;
owl:allValuesFrom [owl:unionOf (<Quantity>, <CodeableConcept>, <string> …) ] ] .
and a DatatypeProperty:
<Quantity> rdfs:subClassOf [owl:onProperty fhir:value; owl:allValuesFrom xsd:decimal].
In resolving #102, we also resolved this issue: AGREED: option 5 [of issue 102], not hoist scalars (same as R4)
The problem is that when we designed FHIR RDF R4 (the initial version of FHIR RDF), we introduced an extra blank node and fhir:value property on primitive properties. For example, fhir:gender is represented like this:
instead of simply being:
We designed it this way intentionally, because FHIR allows any property to be extended, so the extra blank node provides a place to attach the extension (if needed). (See example below.) However, in the years since that design, after accumulating some practical experience using FHIR RDF, it has become clear that the extra blank node and fhir:value property makes it significantly more difficult to access and query those simple properties, which usually are not extended anyway. In other words, we made every use of a primitive property more difficult, just to accommodate the rare case in which someone wants to add a FHIR extension to it. This violates the general design guidance of making the common use cases easy, and the rare use cases possible. Hence, the point of this issue is to reconsider this design choice, to see if we can make the common use case easy -- without requiring the extra blank node and property -- while still somehow enabling the property to have a FHIR extension if needed.
[Sub-issue: How should modifying extensions be represented? NOTE: Discussion of modifier extensions has now been moved to issue #93 .]
Option 0: Do nothing. Keep the R4 approach of everything being an object property
JSON example of non-modifying extension, from R4:
Turtle equivalent in R4: