Merge pull request #23 from ahdis/olivergger_gf#21240_2

[gf#21240]: fixing pattern[x] slices validation
This commit is contained in:
Grahame Grieve 2019-05-20 14:57:22 +10:00 committed by GitHub
commit 58724b3694
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 544 additions and 22 deletions

View File

@ -2708,30 +2708,33 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
throws DefinitionException { throws DefinitionException {
if (cc.hasText()) if (cc.hasText())
throw new DefinitionException("Unsupported CodeableConcept pattern - using text - for discriminator(" + discriminator + ") for slice " + ed.getId()); throw new DefinitionException("Unsupported CodeableConcept pattern - using text - for discriminator(" + discriminator + ") for slice " + ed.getId());
if (!cc.hasCoding() || cc.getCoding().size() > 1) if (!cc.hasCoding())
throw new DefinitionException("Unsupported CodeableConcept pattern - must be just one coding - for discriminator(" + discriminator + ") for slice " + ed.getId()); throw new DefinitionException("Unsupported CodeableConcept pattern - must have at least one coding - for discriminator(" + discriminator + ") for slice " + ed.getId());
Coding c = cc.getCodingFirstRep(); if (cc.hasExtension())
if (c.hasExtension() || cc.hasExtension())
throw new DefinitionException("Unsupported CodeableConcept pattern - extensions are not allowed - for discriminator(" + discriminator + ") for slice " + ed.getId()); throw new DefinitionException("Unsupported CodeableConcept pattern - extensions are not allowed - for discriminator(" + discriminator + ") for slice " + ed.getId());
expression.append(" and " + discriminator + ".coding.where("); for(Coding c : cc.getCoding()) {
boolean first = true; if (c.hasExtension())
if (c.hasSystem()) { throw new DefinitionException("Unsupported CodeableConcept pattern - extensions are not allowed - for discriminator(" + discriminator + ") for slice " + ed.getId());
first = false; expression.append(" and " + discriminator + ".coding.where(");
expression.append("system = '"+c.getSystem()+"'"); boolean first = true;
if (c.hasSystem()) {
first = false;
expression.append("system = '"+c.getSystem()+"'");
}
if (c.hasVersion()) {
if (first) first = false; else expression.append(" and ");
expression.append("version = '"+c.getVersion()+"'");
}
if (c.hasCode()) {
if (first) first = false; else expression.append(" and ");
expression.append("code = '"+c.getCode()+"'");
}
if (c.hasDisplay()) {
if (first) first = false; else expression.append(" and ");
expression.append("display = '"+c.getDisplay()+"'");
}
expression.append(").exists()");
} }
if (c.hasVersion()) {
if (first) first = false; else expression.append(" and ");
expression.append("version = '"+c.getVersion()+"'");
}
if (c.hasCode()) {
if (first) first = false; else expression.append(" and ");
expression.append("code = '"+c.getCode()+"'");
}
if (c.hasDisplay()) {
if (first) first = false; else expression.append(" and ");
expression.append("display = '"+c.getDisplay()+"'");
}
expression.append(").exists()");
} }
private void buildFixedExpression(ElementDefinition ed, StringBuilder expression, String discriminator, ElementDefinition criteriaElement) throws DefinitionException { private void buildFixedExpression(ElementDefinition ed, StringBuilder expression, String discriminator, ElementDefinition criteriaElement) throws DefinitionException {

View File

@ -501,6 +501,13 @@
] ]
} }
}, },
"observation-bp-localcode.xml" : {
"errorCount": 0,
"profile" : {
"source" : "observation-bp-profile-twocodesrequired.xml",
"errorCount": 0
}
},
"observation-cholesterol-good.xml" : { "observation-cholesterol-good.xml" : {
"errorCount": 0 "errorCount": 0
}, },

View File

@ -0,0 +1,256 @@
<Observation xmlns="http://hl7.org/fhir">
<!-- extract from https://www.hl7.org/fhir/observation-example-bloodpressure.xml,
changed id from blood-pressure to observation-bp -->
<id value="observation-bp" />
<text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml">
<p>
<b>Generated Narrative with Details</b>
</p>
<p>
<b>id</b>
: blood-pressure
</p>
<p>
<b>meta</b>
:
</p>
<p>
<b>identifier</b>
: urn:uuid:187e0c12-8dd2-67e2-99b2-bf273c878281
</p>
<p>
<b>basedOn</b>
:
</p>
<p>
<b>status</b>
: final
</p>
<p>
<b>category</b>
: Vital Signs
<span>(Details :
{http://terminology.hl7.org/CodeSystem/observation-category code
&#39;vital-signs&#39; = &#39;Vital Signs&#39;, given as &#39;Vital
Signs&#39;})</span>
</p>
<p>
<b>code</b>:
Blood pressure systolic &amp; diastolic
<span>(Details : {LOINC code &#39;85354-9&#39; = &#39;Blood pressure
panel with all children optional&#39;, given as &#39;Blood pressure
panel with all children optional&#39;})</span>
</p>
<p>
<b>subject</b>
:
<a>Patient/example</a>
</p>
<p>
<b>effective</b>
: 17/09/2012
</p>
<p>
<b>performer</b>
:
<a>Practitioner/example</a>
</p>
<p>
<b>interpretation</b>
: Below low normal
<span>(Details :
{http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation
code &#39;L&#39; = &#39;Low&#39;, given as &#39;low&#39;})</span>
</p>
<p>
<b>bodySite</b>
: Right arm
<span>(Details : {SNOMED CT code &#39;368209003&#39; = &#39;Right
upper arm&#39;, given as &#39;Right arm&#39;})</span>
</p>
<blockquote>
<p>
<b>component</b>
</p>
<p>
<b>code</b>
: Systolic blood pressure
<span>(Details : {LOINC code &#39;8480-6&#39; = &#39;Systolic blood
pressure&#39;, given as &#39;Systolic blood pressure&#39;};
{SNOMED CT code &#39;271649006&#39; = &#39;Systolic blood
pressure&#39;, given as &#39;Systolic blood pressure&#39;};
{http://acme.org/devices/clinical-codes code &#39;bp-s&#39; =
&#39;bp-s&#39;, given as &#39;Systolic Blood pressure&#39;})
</span>
</p>
<p>
<b>value</b>
: 107 mmHg
<span> (Details: UCUM code mm[Hg] = &#39;mmHg&#39;)</span>
</p>
<p>
<b>interpretation</b>
: Normal
<span>(Details :
{http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation
code &#39;N&#39; = &#39;Normal&#39;, given as &#39;normal&#39;})
</span>
</p>
</blockquote>
<blockquote>
<p>
<b>component</b>
</p>
<p>
<b>code</b>
: Diastolic blood pressure
<span>(Details : {LOINC code &#39;8462-4&#39; = &#39;Diastolic
blood pressure&#39;, given as &#39;Diastolic blood pressure&#39;})
</span>
</p>
<p>
<b>value</b>
: 60 mmHg
<span> (Details: UCUM code mm[Hg] = &#39;mmHg&#39;)</span>
</p>
<p>
<b>interpretation</b>
: Below low normal
<span>(Details :
{http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation
code &#39;L&#39; = &#39;Low&#39;, given as &#39;low&#39;})</span>
</p>
</blockquote>
</div>
</text>
<identifier>
<system value="urn:ietf:rfc:3986" />
<value value="urn:uuid:187e0c12-8dd2-67e2-99b2-bf273c878281" />
</identifier><!-- demonstrating the use of the baseOn element with a fictive
identifier -->
<basedOn>
<identifier>
<system value="https://acme.org/identifiers" />
<value value="1234" />
</identifier>
</basedOn>
<status value="final" />
<category>
<coding>
<system
value="http://terminology.hl7.org/CodeSystem/observation-category" />
<code value="vital-signs" />
<display value="Vital Signs" />
</coding>
</category>
<code><!-- replaced by 85354-9 <coding> <system value="http://loinc.org"/>
<code value="85354-9"/> <display value="Blood pressure systolic &amp; diastolic"/>
</coding> -->
<coding>
<system value="http://loinc.org" />
<code value="85354-9" />
<display
value="Blood pressure panel with all children optional" />
</coding>
<coding>
<system value="http://fhir.ch/ig/local" />
<code value="1234" />
</coding>
<text value="Blood pressure systolic &amp; diastolic" />
</code>
<subject>
<reference value="Patient/example" />
</subject>
<effectiveDateTime value="2012-09-17" />
<performer>
<reference value="Practitioner/example" />
</performer><!-- an interpretation offered to the combination observation
generally, it would only be appropriate to offer an interpretation of an
observation that has no value if it has "COMP" (component) observations -->
<interpretation>
<coding>
<system
value="http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation" />
<code value="L" />
<display value="low" />
</coding>
<text value="Below low normal" />
</interpretation><!-- The BodySite can be captured in a LOINC code but am
showing it here to demonstrate populating the element -->
<bodySite>
<coding>
<system value="http://snomed.info/sct" />
<code value="368209003" />
<display value="Right arm" />
</coding>
</bodySite>
<component><!-- Observations are often coded in multiple code systems. -
LOINC provides a very specific code (though not more specific in this particular
case) - snomed provides a clinically relevant code that is usually less granular
than LOINC - the source system provides its own code, which may be less or
more granular than LOINC this is shown here to demonstrate the concept of
translations within the codeableConcept datatype. The diastolic code below
only has a LOINC code -->
<code><!-- LOINC -code -->
<coding>
<system value="http://loinc.org" />
<code value="8480-6" />
<display value="Systolic blood pressure" />
</coding><!-- SNOMED CT Codes -->
<coding>
<system value="http://snomed.info/sct" />
<code value="271649006" />
<display value="Systolic blood pressure" />
</coding><!-- Also, a local code specific to the source system -->
<coding>
<system value="http://fhir.ch/ig/local" />
<code value="3456" />
</coding>
</code>
<valueQuantity>
<value value="107" />
<unit value="mmHg" />
<system value="http://unitsofmeasure.org" />
<code value="mm[Hg]" />
</valueQuantity><!-- an interpretation for the individual composite observation -->
<interpretation>
<coding>
<system
value="http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation" />
<code value="N" />
<display value="normal" />
</coding>
<text value="Normal" />
</interpretation><!-- Should have a refrange as well -->
</component>
<component><!-- this codes only has a LOINC code -->
<code>
<coding>
<system value="http://loinc.org" />
<code value="8462-4" />
<display value="Diastolic blood pressure" />
</coding>
<coding>
<system value="http://fhir.ch/ig/local" />
<code value="7890" />
</coding>
</code>
<valueQuantity>
<value value="60" />
<unit value="mmHg" />
<system value="http://unitsofmeasure.org" />
<code value="mm[Hg]" />
</valueQuantity><!-- an interpretation for the individual composite observation -->
<interpretation>
<coding>
<system
value="http://terminology.hl7.org/CodeSystem/v3-ObservationInterpretation" />
<code value="L" />
<display value="low" />
</coding>
<text value="Below low normal" />
</interpretation><!-- Should have a refrange as well -->
</component>
</Observation>

View File

@ -0,0 +1,256 @@
<StructureDefinition xmlns="http://hl7.org/fhir">
<id value="observation-bp-profile-twocodesrequired" />
<text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml">reworked official bp profile to use
patternCodeableConcept and require a local code system in addition
(http://fhir.ch/ig/local)
</div>
</text>
<url
value="http://hl7.org/fhir/StructureDefinition/observation-bp-profile" />
<version value="4.0.0" />
<name value="observation-bp" />
<title value="Observation Blood Pressure Profile" />
<status value="draft" />
<experimental value="false" />
<date value="2019-05-06" />
<publisher
value="Health Level Seven International (Orders and Observations Workgroup)" />
<contact>
<telecom>
<system value="url" />
<value
value="http://www.hl7.org/Special/committees/orders/index.cfm Orders and Observations" />
</telecom>
</contact>
<description value="FHIR Blood Pressure Profile" />
<fhirVersion value="4.0.0" />
<mapping>
<identity value="workflow" />
<uri value="http://hl7.org/fhir/workflow" />
<name value="Workflow Pattern" />
</mapping>
<mapping>
<identity value="sct-concept" />
<uri value="http://snomed.info/conceptdomain" />
<name value="SNOMED CT Concept Domain Binding" />
</mapping>
<mapping>
<identity value="v2" />
<uri value="http://hl7.org/v2" />
<name value="HL7 v2 Mapping" />
</mapping>
<mapping>
<identity value="rim" />
<uri value="http://hl7.org/v3" />
<name value="RIM Mapping" />
</mapping>
<mapping>
<identity value="w5" />
<uri value="http://hl7.org/fhir/fivews" />
<name value="FiveWs Pattern Mapping" />
</mapping>
<mapping>
<identity value="sct-attr" />
<uri value="http://snomed.org/attributebinding" />
<name value="SNOMED CT Attribute Binding" />
</mapping>
<kind value="resource" />
<abstract value="false" />
<type value="Observation" />
<baseDefinition
value="http://hl7.org/fhir/StructureDefinition/vitalsigns" />
<derivation value="constraint" />
<differential>
<element id="Observation">
<path value="Observation" />
<short value="FHIR Blood Pressure Profile" />
<definition
value="This profile defines how to represent Blood Pressure observations in FHIR using a standard LOINC code and UCUM units of measure. This is a grouping structure. It has no value in Observation.valueQuantity but contains at least one component (systolic and/or diastolic)." />
<min value="0" />
<max value="*" />
</element>
<element id="Observation.code">
<path value="Observation.code" />
<short value="Blood Pressure" />
<definition value="Blood Pressure" />
<min value="1" />
<max value="1" />
<type>
<code value="CodeableConcept" />
</type>
<patternCodeableConcept>
<coding>
<system value="http://loinc.org" />
<code value="85354-9" />
</coding>
<coding>
<system value="http://fhir.ch/ig/local" />
</coding>
</patternCodeableConcept>
<mustSupport value="true" />
</element>
<element id="Observation.valueQuantity">
<path value="Observation.valueQuantity" />
<min value="0" />
<max value="0" />
</element>
<element id="Observation.component">
<path value="Observation.component" />
<slicing>
<discriminator>
<type value="pattern" />
<path value="code" />
</discriminator>
<rules value="open" />
</slicing>
<min value="2" />
<max value="*" />
</element>
<element id="Observation.component:SystolicBP">
<path value="Observation.component" />
<sliceName value="SystolicBP" />
<short value="SystolicBP" />
<min value="1" />
<max value="1" />
</element>
<element id="Observation.component:SystolicBP.code">
<path value="Observation.component.code" />
<min value="1" />
<patternCodeableConcept>
<coding>
<system value="http://loinc.org" />
<code value="8480-6" />
</coding>
<coding>
<system value="http://fhir.ch/ig/local" />
</coding>
</patternCodeableConcept>
</element>
<element id="Observation.component:SystolicBP.valueQuantity">
<path value="Observation.component.valueQuantity" />
<type>
<code value="Quantity" />
</type>
</element>
<element
id="Observation.component:SystolicBP.valueQuantity.value">
<path value="Observation.component.valueQuantity.value" />
<min value="1" />
<max value="1" />
<type>
<code value="decimal" />
</type>
<mustSupport value="true" />
</element>
<element
id="Observation.component:SystolicBP.valueQuantity.unit">
<path value="Observation.component.valueQuantity.unit" />
<min value="1" />
<max value="1" />
<type>
<code value="string" />
</type>
<mustSupport value="true" />
</element>
<element
id="Observation.component:SystolicBP.valueQuantity.system">
<path value="Observation.component.valueQuantity.system" />
<min value="1" />
<max value="1" />
<type>
<code value="uri" />
</type>
<fixedUri value="http://unitsofmeasure.org" />
<mustSupport value="true" />
</element>
<element
id="Observation.component:SystolicBP.valueQuantity.code">
<path value="Observation.component.valueQuantity.code" />
<short
value="Coded responses from the common UCUM units for vital signs value set." />
<definition
value="Coded responses from the common UCUM units for vital signs value set." />
<min value="1" />
<max value="1" />
<type>
<code value="code" />
</type>
<fixedCode value="mm[Hg]" />
<mustSupport value="true" />
</element>
<element id="Observation.component:DiastolicBP">
<path value="Observation.component" />
<sliceName value="DiastolicBP" />
<short value="DiastolicBP" />
<min value="1" />
<max value="1" />
</element>
<element id="Observation.component:DiastolicBP">
<path value="Observation.component.code" />
<min value="1" />
<patternCodeableConcept>
<coding>
<system value="http://loinc.org" />
<code value="8462-4" />
</coding>
<coding>
<system value="http://fhir.ch/ig/local" />
</coding>
</patternCodeableConcept>
</element>
<element id="Observation.component:DiastolicBP.valueQuantity">
<path value="Observation.component.valueQuantity" />
<type>
<code value="Quantity" />
</type>
</element>
<element
id="Observation.component:DiastolicBP.valueQuantity.value">
<path value="Observation.component.valueQuantity.value" />
<min value="1" />
<max value="1" />
<type>
<code value="decimal" />
</type>
<mustSupport value="true" />
</element>
<element
id="Observation.component:DiastolicBP.valueQuantity.unit">
<path value="Observation.component.valueQuantity.unit" />
<min value="1" />
<max value="1" />
<type>
<code value="string" />
</type>
<mustSupport value="true" />
</element>
<element
id="Observation.component:DiastolicBP.valueQuantity.system">
<path value="Observation.component.valueQuantity.system" />
<min value="1" />
<max value="1" />
<type>
<code value="uri" />
</type>
<fixedUri value="http://unitsofmeasure.org" />
<mustSupport value="true" />
</element>
<element
id="Observation.component:DiastolicBP.valueQuantity.code">
<path value="Observation.component.valueQuantity.code" />
<short
value="Coded responses from the common UCUM units for vital signs value set." />
<definition
value="Coded responses from the common UCUM units for vital signs value set." />
<min value="1" />
<max value="1" />
<type>
<code value="code" />
</type>
<fixedCode value="mm[Hg]" />
<mustSupport value="true" />
</element>
</differential>
</StructureDefinition>