[GF#21240]: support for pattern primitive Types and CodeableConcept
This commit is contained in:
parent
9a0c619d28
commit
e6f0b26e81
|
@ -121,6 +121,7 @@ import org.hl7.fhir.r5.model.TypeDetails;
|
||||||
import org.hl7.fhir.r5.model.UriType;
|
import org.hl7.fhir.r5.model.UriType;
|
||||||
import org.hl7.fhir.r5.model.ValueSet;
|
import org.hl7.fhir.r5.model.ValueSet;
|
||||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
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.FHIRLexer.FHIRLexerException;
|
||||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||||
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
|
import org.hl7.fhir.r5.utils.FHIRPathEngine.IEvaluationContext;
|
||||||
|
@ -872,15 +873,55 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
return true;
|
return true;
|
||||||
return false;
|
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);
|
checkFixedValue(errors, path + ".text", focus.getNamedChild("text"), fixed.getTextElement(), "text", focus);
|
||||||
List<Element> codings = new ArrayList<Element>();
|
List<Element> codings = new ArrayList<Element>();
|
||||||
focus.getNamedChildren("coding", codings);
|
focus.getNamedChildren("coding", codings);
|
||||||
if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, codings.size() == fixed.getCoding().size(),
|
if (pattern) {
|
||||||
"Expected " + Integer.toString(fixed.getCoding().size()) + " but found " + Integer.toString(codings.size()) + " coding elements")) {
|
if (rule(errors, IssueType.VALUE, focus.line(), focus.col(), path, codings.size() >= fixed.getCoding().size(),
|
||||||
for (int i = 0; i < codings.size(); i++)
|
"Expected " + Integer.toString(fixed.getCoding().size()) + " but found " + Integer.toString(codings.size())
|
||||||
checkFixedValue(errors, path + ".coding", codings.get(i), fixed.getCoding().get(i), "coding", focus);
|
+ " 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();
|
// return b.toString();
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
|
|
||||||
private void checkFixedValue(List<ValidationMessage> errors, String path, Element focus, org.hl7.fhir.r5.model.Element fixed, String propName, Element parent) {
|
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)
|
if ((fixed == null || fixed.isEmpty()) && focus == null)
|
||||||
; // this is all good
|
; // this is all good
|
||||||
else if (fixed == null && focus != null)
|
else if (fixed == null && focus != null)
|
||||||
|
@ -1356,7 +1401,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
else if (fixed instanceof HumanName)
|
else if (fixed instanceof HumanName)
|
||||||
checkHumanName(errors, path, focus, (HumanName) fixed);
|
checkHumanName(errors, path, focus, (HumanName) fixed);
|
||||||
else if (fixed instanceof CodeableConcept)
|
else if (fixed instanceof CodeableConcept)
|
||||||
checkCodeableConcept(errors, path, focus, (CodeableConcept) fixed);
|
checkCodeableConcept(errors, path, focus, (CodeableConcept) fixed, pattern);
|
||||||
else if (fixed instanceof Timing)
|
else if (fixed instanceof Timing)
|
||||||
checkTiming(errors, path, focus, (Timing) fixed);
|
checkTiming(errors, path, focus, (Timing) fixed);
|
||||||
else if (fixed instanceof Period)
|
else if (fixed instanceof Period)
|
||||||
|
@ -1622,8 +1667,12 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.hasFixed())
|
if (context.hasFixed()) {
|
||||||
checkFixedValue(errors,path,e, context.getFixed(), context.getSliceName(), null);
|
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
|
// for nothing to check
|
||||||
}
|
}
|
||||||
|
@ -3819,6 +3868,9 @@ private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, L
|
||||||
if (ei.definition.hasFixed()) {
|
if (ei.definition.hasFixed()) {
|
||||||
checkFixedValue(errors,ei.path, ei.element, ei.definition.getFixed(), ei.definition.getSliceName(), null);
|
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")) {
|
if (type.equals("Identifier")) {
|
||||||
checkIdentifier(errors, ei.path, ei.element, ei.definition);
|
checkIdentifier(errors, ei.path, ei.element, ei.definition);
|
||||||
|
|
|
@ -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'"]
|
"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" : {
|
"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" : {
|
"observation-triglyceride-bad-wrongcode.xml" : {
|
||||||
"errorCount": 1,
|
"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"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,7 +69,7 @@
|
||||||
<system value="http://loinc.org" />
|
<system value="http://loinc.org" />
|
||||||
<code value="35217-9" />
|
<code value="35217-9" />
|
||||||
<display
|
<display
|
||||||
value="Triglyceride [Moles/​volume] in Serum or Plasma" />
|
value="Triglyceride [Moles/​volume] in Serum or Plasma" />
|
||||||
</coding>
|
</coding>
|
||||||
<coding>
|
<coding>
|
||||||
<system value="http://snomed.info/sct" />
|
<system value="http://snomed.info/sct" />
|
||||||
|
|
|
@ -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/​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>
|
Loading…
Reference in New Issue