Stream: conformance
Topic: pattern discriminators and pattern[x]/binding
Chris Moesel (Jul 06 2020 at 20:18):
According to the R4 spec for discriminators:
Each slice must use the element definition for the element(s) in the discriminator(s) to ensure that the slices are clearly differentiated by assigning an appropriate value domain, depending on the discriminator type. If the type is value, or pattern, then the element definition must use either:
- ElementDefinition.fixed[x], or
- ElementDefinition.pattern[x], or
- if the element has a terminology binding, a required binding with a Value Set that enumerates the list of possible codes in the value set ("extensional definition")
I take this to mean that if a discriminator type is pattern
then the element pointed to by the discriminator path
must have either a pattern[x]
or binding
property directly on it (and maybe a fixed[x]
would be OK - not sure).
But... I've found that the IG Publisher doesn't seem to care. The following FSH produces no errors or warnings in the IG Publisher:
CodeSystem: ExampleComponentCS
Id: example-component-cs
* #foo "Foo" "Foo"
* #bar "Bar" "Bar"
* #boo "Boo" "Boo"
* #far "Far" "Far"
ValueSet: BooFarVS
Id: boo-far-vs
* ExampleComponentCS#boo "Boo"
* ExampleComponentCS#far "Far"
Profile: PractitionerBadSlicing
Parent: Practitioner
* identifier ^slicing.rules = #open
* identifier ^slicing.discriminator.type = #pattern
* identifier ^slicing.discriminator.path = "$this" // <-- $this
* identifier contains foo 0..1 and bar 0..1 and booFar 0..2
* identifier[foo].type = ExampleComponentCS#foo // <-- NOT on $this
* identifier[bar].type = ExampleComponentCS#bar // <-- NOT on $this
* identifier[booFar].type from BooFarVS // <-- NOT on $this
I expected some flack from the publisher because the identifier
discriminator type is pattern
and the path is $this
-- but the pattern[x]
and binding
are not on identifier
(which is $this
), but rather are on identifier.type
.
Am I misunderstanding? Are patterns and binding on nested elements (below the discriminator path) valid for discrimination on? Or is the IG Publisher just not flagging this even though it is invalid?
Grahame Grieve (Jul 08 2020 at 01:37):
well, I think it looks wrong, and I would've expected an error. how can I reproduce this?
Chris Moesel (Jul 08 2020 at 02:37):
Is a standalone StructureDefinition that demonstrates it good enough? Or do you prefer a whole buildable IG? And if you think this is a bug, then I should file it in Jira, right?
Grahame Grieve (Jul 08 2020 at 04:22):
filing it with Jira is good. Ideally, I'll a structure definition and a valid and an invalid example. then I can add it to the unit tests
Igor Sirkovich (Jul 08 2020 at 05:10):
I'm just wondering if $this pattern slicing above would work in case slices are defined on different sub-elements of identifier, e.g. the last 3 lines would be:
- identifier[foo].type = ExampleComponentCS#foo
- identifier[bar].system = http://myidsystem.com/bar
- identifier[booFar].type from BooFarVS
Alternatively, would this require slicing on discriminator=type and re-slicing on discriminator=system?
Is this a valid scenario generally speaking?
Chris Moesel (Jul 08 2020 at 13:26):
Issue filed here: https://jira.hl7.org/browse/FHIR-27927
Chris Moesel (Jul 08 2020 at 13:31):
@Igor Sirkovich -- I think there needs to be a constraint on the direct element the discriminator path points to (based on my reading of the spec). So you would probably need a patternIdentifier
that specifies the type
and system
for that to work. If constraints on sub-path elements also counted for discrimination then I'm not sure why we would ever discriminate on anything other than $this
.
Igor Sirkovich (Jul 08 2020 at 13:45):
Thank you @Chris Moesel
Would the following definition work in this case? I'm just trying to ensure I understand your explanation.
* identifier ^slicing.rules = #open
* identifier ^slicing.discriminator.type = #pattern
* identifier ^slicing.discriminator.path = "$this"
* identifier contains foo 0..1 and bar 0..1 and booFar 0..2
* identifier[foo].type = ExampleComponentCS#foo
* identifier[bar].system = http://myidsystem.com/bar
* identifier[booFar].type from BooFarVS
Chris Moesel said:
Igor Sirkovich -- I think there needs to be a constraint on the direct element the discriminator path points to (based on my reading of the spec). So you would probably need a
patternIdentifier
that specifies thetype
andsystem
for that to work. If constraints on sub-path elements also counted for discrimination then I'm not sure why we would ever discriminate on anything other than$this
.
Chris Moesel (Jul 08 2020 at 13:58):
Hi @Igor Sirkovich -- no, I don't think so. The FSH above says to discriminate by pattern
on $this
-- which is identifier
. So I think there should be a patternIdentifier
constraint on the identifier
element in each slice. Instead that FSH produces the following constraints:
patternCodeableConcept
onidentifier.type
(infoo
slice)patternUri
onidentifier.system
(inbar
slice)binding
onidentifier.type
(inbooFar
slice)
It's also not quite correct because the slices are not mutually exclusive. For example, if an identifier had a type
that matched the foo
slice and a system
that matched the bar
slice, it's ambiguous which slice it belongs to.
Chris Moesel (Jul 08 2020 at 14:22):
Also note that right now... SUSHI only supports patterns on arbitrary datatypes by using caret syntax. Fixing my original example to use patterns on identifier
you'd need to do this:
Profile: PractitionerBadSlicing
Parent: Practitioner
* identifier ^slicing.rules = #open
* identifier ^slicing.discriminator.type = #pattern
* identifier ^slicing.discriminator.path = "$this"
* identifier contains foo 0..1 and bar 0..1 and booFar 0..2
* identifier[foo] ^patternIdentifier.type = ExampleComponentCS#foo
* identifier[bar] ^patternIdentifier.type = ExampleComponentCS#bar
* identifier[booFar].type from BooFarVS // <-- This is actually still wrong, but there's no way to apply it at the `identifier` level
FSH supports another way, but it's not yet supported in SUSHI
Instance: FooIdentifier
InstanceOf: Identifier
Usage: #inline
* type = ExampleComponentCS#foo
Instance: BarIdentifier
InstanceOf: Identifier
Usage: #inline
* type = ExampleComponentCS#foo
Profile: PractitionerBadSlicing
Parent: Practitioner
* identifier ^slicing.rules = #open
* identifier ^slicing.discriminator.type = #pattern
* identifier ^slicing.discriminator.path = "$this"
* identifier contains foo 0..1 and bar 0..1 and booFar 0..2
* identifier[foo] = FooIdentifier
* identifier[bar] = BarIdentifier
* identifier[booFar].type from BooFarVS // <-- This is actually still wrong, but there's no way to apply it at the `identifier` level
EDIT: Actually, it's pretty much impossible to fix it for the VS constraint (since we can pop it up a level and we can't represent it in patternIdentifier
. So I had to edit that out.
Igor Sirkovich (Jul 09 2020 at 00:32):
Thank you @Chris Moesel. This is super helpful. Complex slicing is always a lot of fun :)
Igor Sirkovich (Jul 09 2020 at 00:35):
Just a thought: any chance the following might work?
* identifier[booFar] ^patternIdentifier.type from BooFarVS
I've never seen this, so I assume it's not valid, but probably worth checking.
Chris Moesel (Jul 09 2020 at 03:06):
I don't think there is a way to say that something in a pattern[x]
should be bound to a value set. binding
is a property on ElementDefinition
, as is pattern[x]
-- so they're at the same level, making it difficult to apply one to the other. Although pattern[x]
allows you to specify values from a child path (via the pattern itself), I think binding
can only be applies to the exact element it is on (no child paths).
It's hard to explain, and I feel like I'm probably not saying it very well, but hopefully that is helpful anyway!
Last updated: Apr 12 2022 at 19:14 UTC