validation fixes for US-Core testing

This commit is contained in:
Grahame Grieve 2019-05-28 19:18:04 +10:00
parent f60d17bb94
commit 847b6a1fc8
4 changed files with 133 additions and 30 deletions

View File

@ -22,11 +22,14 @@ package org.hl7.fhir.r5.terminologies;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.context.IWorkerContext.ValidationResult;
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
@ -36,7 +39,9 @@ import org.hl7.fhir.r5.model.Coding;
import org.hl7.fhir.r5.model.UriType;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceDesignationComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@ -45,6 +50,7 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
private ValueSet valueset;
private IWorkerContext context;
private Map<String, ValueSetCheckerSimple> inner = new HashMap<>();
public ValueSetCheckerSimple(ValueSet source, IWorkerContext context) {
this.valueset = source;
@ -159,7 +165,47 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
if (code.getDisplay().equalsIgnoreCase(ds.getValue()))
return new ValidationResult(cc);
}
return new ValidationResult(IssueSeverity.WARNING, "Display Name for "+code.getSystem()+"#"+code.getCode()+" must be one of '"+b.toString()+"'", cc);
// also check to see if the value set has another display
ConceptReferenceComponent vs = findValueSetRef(code.getSystem(), code.getCode());
if (vs != null && vs.hasDisplay()) {
b.append(vs.getDisplay());
if (code.getDisplay().equalsIgnoreCase(vs.getDisplay()))
return new ValidationResult(cc);
for (ConceptReferenceDesignationComponent ds : vs.getDesignation()) {
b.append(ds.getValue());
if (code.getDisplay().equalsIgnoreCase(ds.getValue()))
return new ValidationResult(cc);
}
}
return new ValidationResult(IssueSeverity.WARNING, "Display Name for "+code.getSystem()+"#"+code.getCode()+" should be one of '"+b.toString()+"'", cc);
}
private ConceptReferenceComponent findValueSetRef(String system, String code) {
if (valueset == null)
return null;
// if it has an expansion
for (ValueSetExpansionContainsComponent exp : valueset.getExpansion().getContains()) {
if (system.equals(exp.getSystem()) && code.equals(exp.getCode())) {
ConceptReferenceComponent cc = new ConceptReferenceComponent();
cc.setDisplay(exp.getDisplay());
cc.setDesignation(cc.getDesignation());
return cc;
}
}
for (ConceptSetComponent inc : valueset.getCompose().getInclude()) {
if (system.equals(inc.getSystem())) {
for (ConceptReferenceComponent cc : inc.getConcept()) {
if (cc.getCode().equals(code))
return cc;
}
}
for (CanonicalType url : inc.getValueSet()) {
ConceptReferenceComponent cc = getVs(url.asStringValue()).findValueSetRef(system, code);
if (cc != null)
return cc;
}
}
return null;
}
private String gen(Coding code) {
@ -295,15 +341,61 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
if (!system.equals(vsi.getSystem()))
return false;
if (vsi.hasFilter())
throw new FHIRException("Filters - not done yet");
if (vsi.hasFilter()) {
boolean ok = true;
for (ConceptSetFilterComponent f : vsi.getFilter())
if (!codeInFilter(system, f, code)) {
ok = false;
break;
}
if (ok)
return true;
}
CodeSystem def = context.fetchCodeSystem(system);
if (def.getContent() != CodeSystemContentMode.COMPLETE)
throw new FHIRException("Unable to resolve system "+vsi.getSystem()+" - system is not complete");
List<ConceptDefinitionComponent> list = def.getConcept();
return validateCodeInConceptList(code, def, list);
boolean ok = validateCodeInConceptList(code, def, list);
if (ok && vsi.hasConcept()) {
for (ConceptReferenceComponent cc : vsi.getConcept())
if (cc.getCode().equals(code))
return true;
return false;
} else
return ok;
}
private boolean codeInFilter(String system, ConceptSetFilterComponent f, String code) throws FHIRException {
CodeSystem cs = context.fetchCodeSystem(system);
if (cs == null)
throw new FHIRException("Unable to evaluate filters on unknown code system '"+system+"'");
if ("concept".equals(f.getProperty()))
return codeInConceptFilter(cs, f, code);
else {
System.out.println("todo: handle filters with property = "+f.getProperty());
throw new FHIRException("Unable to handle system "+cs.getUrl()+" filter with property = "+f.getProperty());
}
}
private boolean codeInConceptFilter(CodeSystem cs, ConceptSetFilterComponent f, String code) throws FHIRException {
switch (f.getOp()) {
case ISA: return codeInConceptIsAFilter(cs, f, code);
default:
System.out.println("todo: handle concept filters with op = "+f.getOp());
throw new FHIRException("Unable to handle system "+cs.getUrl()+" concept filter with op = "+f.getOp());
}
}
private boolean codeInConceptIsAFilter(CodeSystem cs, ConceptSetFilterComponent f, String code) {
if (code.equals(f.getProperty()))
return true;
ConceptDefinitionComponent cc = findCodeInConcept(cs.getConcept(), f.getValue());
if (cc == null)
return false;
cc = findCodeInConcept(cc.getConcept(), code);
return cc != null;
}
public boolean validateCodeInConceptList(String code, CodeSystem def, List<ConceptDefinitionComponent> list) {
@ -324,11 +416,19 @@ public class ValueSetCheckerSimple implements ValueSetChecker {
}
return false;
}
private ValueSetCheckerSimple getVs(String url) {
if (inner.containsKey(url)) {
return inner.get(url);
}
ValueSet vs = context.fetchResource(ValueSet.class, url);
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(vs, context);
inner.put(url, vsc);
return vsc;
}
private boolean inImport(String uri, String system, String code) throws FHIRException {
ValueSet vs = context.fetchResource(ValueSet.class, uri);
ValueSetCheckerSimple vsc = new ValueSetCheckerSimple(vs, context);
return vsc.codeInValueSet(system, code);
return getVs(uri).codeInValueSet(system, code);
}
}

View File

@ -4130,20 +4130,24 @@ public class FHIRPathEngine {
element = slice;
}
List<ElementDefinition> childDefinitions;
childDefinitions = ProfileUtilities.getChildMap(sd, element);
// if that's empty, get the children of the type
if (childDefinitions.isEmpty()) {
if (expr.getName().equals("$this")) {
focus = element;
} else {
List<ElementDefinition> childDefinitions;
childDefinitions = ProfileUtilities.getChildMap(sd, element);
// if that's empty, get the children of the type
if (childDefinitions.isEmpty()) {
sd = fetchStructureByType(element);
if (sd == null)
throw new DefinitionException("Problem with use of resolve() - profile '"+element.getType().get(0).getProfile()+"' on "+element.getId()+" could not be resolved");
childDefinitions = ProfileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep());
}
for (ElementDefinition t : childDefinitions) {
if (tailMatches(t, expr.getName())) {
focus = t;
break;
sd = fetchStructureByType(element);
if (sd == null)
throw new DefinitionException("Problem with use of resolve() - profile '"+element.getType().get(0).getProfile()+"' on "+element.getId()+" could not be resolved");
childDefinitions = ProfileUtilities.getChildMap(sd, sd.getSnapshot().getElementFirstRep());
}
for (ElementDefinition t : childDefinitions) {
if (tailMatches(t, expr.getName())) {
focus = t;
break;
}
}
}
} else if (expr.getKind() == Kind.Function) {
@ -4186,7 +4190,7 @@ public class FHIRPathEngine {
}
if (focus == null)
throw new DefinitionException("Unable to resolve discriminator");
throw new DefinitionException("Unable to resolve discriminator: "+expr.toString());
else if (expr.getInner() == null)
return focus;
else {

View File

@ -4230,11 +4230,11 @@ public class NarrativeGenerator implements INarrativeGenerator {
boolean hasHistory = false;
boolean hasUpdates = false;
for (CapabilityStatementRestResourceComponent r : rest.getResource()) {
hasVRead = hasOp(r, TypeRestfulInteraction.VREAD);
hasPatch = hasOp(r, TypeRestfulInteraction.PATCH);
hasDelete = hasOp(r, TypeRestfulInteraction.DELETE);
hasHistory = hasOp(r, TypeRestfulInteraction.HISTORYTYPE);
hasUpdates = hasOp(r, TypeRestfulInteraction.HISTORYINSTANCE);
hasVRead = hasVRead || hasOp(r, TypeRestfulInteraction.VREAD);
hasPatch = hasPatch || hasOp(r, TypeRestfulInteraction.PATCH);
hasDelete = hasDelete || hasOp(r, TypeRestfulInteraction.DELETE);
hasHistory = hasHistory || hasOp(r, TypeRestfulInteraction.HISTORYTYPE);
hasUpdates = hasUpdates || hasOp(r, TypeRestfulInteraction.HISTORYINSTANCE);
}
t = x.table(null);

View File

@ -837,7 +837,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
txWarning(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, s.getMessage());
return true;
}
if (s.getErrorClass().isInfrastructure())
if (s.getErrorClass() != null && s.getErrorClass().isInfrastructure())
txWarning(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, s.getMessage());
else if (s.getSeverity() == IssueSeverity.INFORMATION)
txHint(errors, s.getTxLink(), IssueType.CODEINVALID, element.line(), element.col(), path, s == null, s.getMessage());
@ -898,8 +898,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
return false;
}
private void checkCodeableConcept(List<ValidationMessage> errors, String path, Element focus, CodeableConcept fixed,
boolean pattern) {
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);