[GF#21240]: support for pattern primitive Types and CodeableConcept

This commit is contained in:
Oliver Egger 2019-05-05 14:12:49 +02:00
parent 9a0c619d28
commit e6f0b26e81
4 changed files with 180 additions and 13 deletions

View File

@ -121,6 +121,7 @@ import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.r5.test.utils.TestingUtilities;
import org.hl7.fhir.r5.utils.FHIRLexer.FHIRLexerException;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
@ -872,15 +873,55 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return true;
return false;
}
private void checkCodeableConcept(List<ValidationMessage> errors, String path, Element focus, CodeableConcept fixed) {
private boolean hasErrors(List<ValidationMessage> errors) {
if (errors!=null) {
for (ValidationMessage vm : errors) {
if (vm.getLevel() == IssueSeverity.FATAL || vm.getLevel() == IssueSeverity.ERROR) {
return true;
}
}
}
return false;
}
private void checkCodeableConcept(List<ValidationMessage> errors, String path, Element focus, CodeableConcept fixed,
boolean pattern) {
checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), "text", focus);
List<Element> codings = new ArrayList<Element>();
focus.getNamedChildren("coding", codings);
if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, codings.size() == fixed.getCoding().size(),
"Expected " + Integer.toString(fixed.getCoding().size()) + " but found " + Integer.toString(codings.size()) + " coding elements")) {
for (int i = 0; i < codings.size(); i++)
checkFixedValue(errors, path + ".coding", codings.get(i), fixed.getCoding().get(i), "coding", focus);
if (pattern) {
if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, codings.size() >= fixed.getCoding().size(),
"Expected " + Integer.toString(fixed.getCoding().size()) + " but found " + Integer.toString(codings.size())
+ " coding elements")) {
for (int i = 0; i < fixed.getCoding().size(); i++) {
Coding fixedCoding = fixed.getCoding().get(i);
boolean found = false;
List<ValidationMessage> errorsFixed = null;
for (int j = 0; j < codings.size() && !found; ++j) {
errorsFixed = new ArrayList<ValidationMessage>();
checkFixedValue(errorsFixed, path + ".coding", codings.get(j), fixedCoding, "coding", focus);
if (!hasErrors(errorsFixed)) {
found = true;
}
}
if (!found) {
rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, false,
"Expected patternCodeableConcept not found for"+
" system: " + fixedCoding.getSystemElement().asStringValue() +
" code: " + fixedCoding.getCodeElement().asStringValue() +
" display: " + fixedCoding.getDisplayElement().asStringValue());
}
}
}
} else {
if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, codings.size() == fixed.getCoding().size(),
"Expected " + Integer.toString(fixed.getCoding().size()) + " but found " + Integer.toString(codings.size())
+ " coding elements")) {
for (int i = 0; i < codings.size(); i++)
checkFixedValue(errors, path + ".coding", codings.get(i), fixed.getCoding().get(i), "coding", focus);
}
}
}
@ -1292,8 +1333,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// return b.toString();
// }
//
private void checkFixedValue(List<ValidationMessage> errors, String path, Element focus, org.hl7.fhir.r5.model.Element fixed, String propName, Element parent) {
checkFixedValue(errors, path, focus, fixed, propName, parent, false);
}
private void checkFixedValue(List<ValidationMessage> errors, String path, Element focus, org.hl7.fhir.r5.model.Element fixed, String propName, Element parent, boolean pattern) {
if ((fixed == null || fixed.isEmpty()) && focus == null)
; // this is all good
else if (fixed == null && focus != null)
@ -1356,7 +1401,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
else if (fixed instanceof HumanName)
checkHumanName(errors, path, focus, (HumanName) fixed);
else if (fixed instanceof CodeableConcept)
checkCodeableConcept(errors, path, focus, (CodeableConcept) fixed);
checkCodeableConcept(errors, path, focus, (CodeableConcept) fixed, pattern);
else if (fixed instanceof Timing)
checkTiming(errors, path, focus, (Timing) fixed);
else if (fixed instanceof Period)
@ -1622,8 +1667,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
}
if (context.hasFixed())
checkFixedValue(errors,path,e, context.getFixed(), context.getSliceName(), null);
if (context.hasFixed()) {
checkFixedValue(errors,path,e, context.getFixed(), context.getSliceName(), null, false);
}
if (context.hasPattern()) {
checkFixedValue(errors, path, e, context.getPattern(), context.getSliceName(), null, true);
}
// for nothing to check
}
@ -3819,6 +3868,9 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
if (ei.definition.hasFixed()) {
checkFixedValue(errors,ei.path, ei.element, ei.definition.getFixed(), ei.definition.getSliceName(), null);
}
if (ei.definition.hasPattern()) {
checkFixedValue(errors,ei.path, ei.element, ei.definition.getPattern(), ei.definition.getSliceName(), null, true);
}
}
if (type.equals("Identifier")) {
checkIdentifier(errors, ei.path, ei.element, ei.definition);

View File

@ -484,11 +484,18 @@
"errors": ["ERROR: Observation.code.coding.code: Value is '13457-7' but must be '35200-5'","ERROR: Observation.code.coding.display: Value is 'Cholesterol in LDL [Mass/volume] in Serum or Plasma by calculation' but must be 'Cholesterol [Moles/?volume] in Serum or Plasma'"]
},
"observation-triglyceride-good.xml" : {
"errorCount": 0
"warningCount": 1,
"errorCount": 0,
"warnings": ["WARNING: Observation.code.coding[1]: The display \"Triglyceride [Moles/volume] in Serum or Plasma\" is not a valid display for the code {http://loinc.org}35217-9 - should be one of [\"Triglyceride [Mass or Moles/volume] in Serum or Plasma\",\"Trigl SerPl-msCnc\""]
},
"observation-triglyceride-good2.xml" : {
"warningCount": 1,
"errorCount": 0,
"warnings": ["WARNING: Observation.code.coding[2]: The display \"Triglyceride [Moles/volume] in Serum or Plasma\" is not a valid display for the code {http://loinc.org}35217-9 - should be one of [\"Triglyceride [Mass or Moles/volume] in Serum or Plasma\",\"Trigl SerPl-msCnc\""]
},
"observation-triglyceride-bad-wrongcode.xml" : {
"errorCount": 1,
"errors": ["ERROR: "]
"errors": ["ERROR: Observation.code: Expected patternCodeableConcept not found for system: http://loinc.org code: 35217-9 display: Triglyceride [Moles/volume] in Serum or Plasma"]
}
}
}

View File

@ -69,7 +69,7 @@
<system value="http://loinc.org" />
<code value="35217-9" />
<display
value="Triglyceride [Moles/​volume] in Serum or Plasma" />
value="Triglyceride [Moles/&#x200B;volume] in Serum or Plasma" />
</coding>
<coding>
<system value="http://snomed.info/sct" />

View File

@ -0,0 +1,108 @@
<Observation xmlns="http://hl7.org/fhir">
<!-- extract from http://hl7.org/fhir/triglyceride-examples.html, changed
id from triglyceride and added explicit profile reference to http://hl7.org/fhir/StructureDefinition/triglyceride
and added snomed ct code for triglyceride -->
<id value="observation-triglyceride-good2" />
<meta>
<profile
value="http://hl7.org/fhir/StructureDefinition/triglyceride" />
</meta>
<text>
<status value="generated" />
<div xmlns="http://www.w3.org/1999/xhtml">
<p>
<b> Generated Narrative with Details</b>
</p>
<p>
<b> id</b>
: triglyceride
</p>
<p>
<b> status</b>
: final
</p>
<p>
<b> code</b>
: Triglyceride
<span> (Details : {LOINC code '35217-9' = 'Triglyceride [Mass or
Moles/volume] in Serum or Plasma',
given as 'Triglyceride
[Moles/ââ¬â€¹volume] in Serum or Plasma'})
</span>
</p>
<p>
<b> subject</b>
:
<a> Patient/pat2</a>
</p>
<p>
<b> performer</b>
:
<a> Acme Laboratory, Inc</a>
</p>
<p>
<b> value</b>
: 1.3 mmol/L
<span> (Details: UCUM code mmol/L = 'mmol/L')</span>
</p>
<h3> ReferenceRanges</h3>
<table>
<tr>
<td> -</td>
<td>
<b> High</b>
</td>
</tr>
<tr>
<td> *</td>
<td>
2.0 mmol/L
<span> (Details: UCUM code mmol/L = 'mmol/L')</span>
</td>
</tr>
</table>
</div>
</text>
<status value="final" />
<code>
<coding>
<system value="http://snomed.info/sct" />
<code value="85600001" />
<display value="Triacylglycerol" />
</coding>
<coding>
<system value="http://loinc.org" />
<code value="35217-9" />
<display
value="Triglyceride [Moles/&#x200B;volume] in Serum or Plasma" />
</coding>
<coding>
<system value="http://snomed.info/sct" />
<code value="85600001" />
<display value="Triacylglycerol" />
</coding>
<text value="Triglyceride" />
</code>
<subject>
<reference value="Patient/pat2" />
</subject>
<performer>
<reference
value="Organization/1832473e-2fe0-452d-abe9-3cdb9879522f" />
<display value="Acme Laboratory, Inc" />
</performer>
<valueQuantity>
<value value="1.3" />
<unit value="mmol/L" />
<system value="http://unitsofmeasure.org" />
<code value="mmol/L" />
</valueQuantity>
<referenceRange>
<high>
<value value="2.0" />
<unit value="mmol/L" />
<system value="http://unitsofmeasure.org" />
<code value="mmol/L" />
</high>
</referenceRange>
</Observation>