validation fixes for US-Core testing
This commit is contained in:
parent
f60d17bb94
commit
847b6a1fc8
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue