Merge pull request #568 from aehrc/feature/dstu2_1_profile_paths

Correct paths to profiles and valuesets/codesystems
This commit is contained in:
James Agnew 2017-03-17 06:41:36 -04:00 committed by GitHub
commit 54376a54c6
5 changed files with 58 additions and 36 deletions

View File

@ -72,9 +72,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
codeSystems = new HashMap<String, CodeSystem>();
valueSets = new HashMap<String, ValueSet>();
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/instance/model/dstu3/valueset/valuesets.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/instance/model/dstu3/valueset/v2-tables.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/instance/model/dstu3/valueset/v3-codesystems.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu2016may/valueset/valuesets.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu2016may/valueset/v2-tables.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu2016may/valueset/v3-codesystems.xml");
myCodeSystems = codeSystems;
myValueSets = valueSets;
@ -91,7 +91,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
@Override
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
Validate.notBlank(theUri, "theUri must not be null or blank");
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
return (T) fetchStructureDefinition(theContext, theUri);
}
@ -210,9 +210,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
if (structureDefinitions == null) {
structureDefinitions = new HashMap<String, StructureDefinition>();
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/instance/model/dstu3/profile/profiles-resources.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/instance/model/dstu3/profile/profiles-types.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/instance/model/dstu3/profile/profiles-others.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu2016may/profile/profiles-resources.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu2016may/profile/profiles-types.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu2016may/profile/profiles-others.xml");
myStructureDefinitions = structureDefinitions;
}
@ -227,9 +227,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
if (cs.hasCaseSensitive()) {
caseSensitive = cs.getCaseSensitive();
}
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
if (retVal != null) {
return retVal;
}
@ -243,7 +243,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
if (theCaseSensitive == false) {
code = code.toUpperCase();
}
return testIfConceptIsInListInner(conceptList, theCaseSensitive, code);
}
@ -265,7 +265,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
break;
}
}
return retVal;
}

View File

@ -31,13 +31,18 @@ import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptReferenceComponent;
import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.dstu2016may.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.dstu2016may.model.ValueSet.ValueSetExpansionContainsComponent;
import org.hl7.fhir.dstu2016may.terminologies.ValueSetExpander;
import org.hl7.fhir.dstu2016may.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
import org.hl7.fhir.dstu2016may.terminologies.ValueSetExpanderFactory;
import org.hl7.fhir.dstu2016may.terminologies.ValueSetExpanderSimple;
import org.hl7.fhir.dstu2016may.utils.IWorkerContext;
import org.hl7.fhir.dstu2016may.validation.IResourceValidator;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public final class HapiWorkerContext implements IWorkerContext {
public final class HapiWorkerContext implements IWorkerContext, ValueSetExpanderFactory {
private final FhirContext myCtx;
private Map<String, Resource> myFetchedResourceCache = new HashMap<String, Resource>();
private IValidationSupport myValidationSupport;
@ -201,8 +206,8 @@ public final class HapiWorkerContext implements IWorkerContext {
}
}
}
boolean caseSensitive = true;
if (isNotBlank(theSystem)) {
CodeSystem system = fetchCodeSystem(theSystem);
@ -259,10 +264,27 @@ public final class HapiWorkerContext implements IWorkerContext {
return new ValidationResult(IssueSeverity.ERROR, "Unknown code[" + theCode + "] in system[" + theSystem + "]");
}
@Override
public ValueSetExpander getExpander() {
ValueSetExpanderSimple retVal = new ValueSetExpanderSimple(this, this);
return retVal;
}
@Override
public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk) {
throw new UnsupportedOperationException();
ValueSetExpansionOutcome vso;
try {
vso = getExpander().expand(theSource);
} catch (InvalidRequestException e) {
throw e;
} catch (Exception e) {
throw new InternalErrorException(e);
}
if (vso.getError() != null) {
throw new InvalidRequestException(vso.getError());
} else {
return vso;
}
}
@Override

View File

@ -25,13 +25,13 @@ import org.hl7.fhir.utilities.Utilities;
public abstract class ParserBase {
interface IErrorNotifier {
}
public enum ValidationPolicy { NONE, QUICK, EVERYTHING }
public static boolean isPrimitive(String code) {
return Utilities.existsInList(code,
"xhtml", "boolean", "integer", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime",
return Utilities.existsInList(code,
"xhtml", "boolean", "integer", "string", "decimal", "uri", "base64Binary", "instant", "date", "dateTime",
"time", "code", "oid", "id", "markdown", "unsignedInt", "positiveInt", "xhtml", "base64Binary");
}
@ -49,12 +49,12 @@ public abstract class ParserBase {
this.policy = policy;
this.errors = errors;
}
public abstract Element parse(InputStream stream) throws Exception;
public abstract void compose(Element e, OutputStream destination, OutputStyle style, String base) throws Exception;
public void logError(int line, int col, String path, IssueType type, String message, IssueSeverity level) throws FHIRFormatError {
if (policy == ValidationPolicy.EVERYTHING) {
ValidationMessage msg = new ValidationMessage(Source.InstanceValidator, type, line, col, path, message, level);
@ -62,8 +62,8 @@ public abstract class ParserBase {
} else if (level == IssueSeverity.FATAL || (level == IssueSeverity.ERROR && policy == ValidationPolicy.QUICK))
throw new FHIRFormatError(message+String.format(" at line %d col %d", line, col));
}
protected StructureDefinition getDefinition(int line, int col, String ns, String name) throws FHIRFormatError {
if (ns == null) {
logError(line, col, name, IssueType.STRUCTURE, "This cannot be parsed as a FHIR object (no namespace)", IssueSeverity.FATAL);
@ -74,7 +74,7 @@ public abstract class ParserBase {
return null;
}
for (StructureDefinition sd : context.allStructures()) {
if (name.equals(sd.getId())) {
if (name.equals(sd.getIdElement().getIdPart())) {
if((ns == null || ns.equals(FormatUtilities.FHIR_NS)) && !ToolingExtensions.hasExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace"))
return sd;
String sns = ToolingExtensions.readStringExtension(sd, "http://hl7.org/fhir/StructureDefinition/elementdefinition-namespace");
@ -92,7 +92,7 @@ public abstract class ParserBase {
return null;
}
for (StructureDefinition sd : context.allStructures()) {
if (name.equals(sd.getId())) {
if (name.equals(sd.getIdElement().getIdPart())) {
return sd;
}
}
@ -100,7 +100,7 @@ public abstract class ParserBase {
return null;
}
protected List<Property> getChildProperties(Property property, String elementName, String statedType) throws DefinitionException {
ElementDefinition ed = property.getDefinition();
StructureDefinition sd = property.getStructure();
@ -128,12 +128,12 @@ public abstract class ParserBase {
if (t == null && ToolingExtensions.hasExtension(ed, "http://hl7.org/fhir/StructureDefinition/elementdefinition-defaultype"))
t = ToolingExtensions.readStringExtension(ed, "http://hl7.org/fhir/StructureDefinition/elementdefinition-defaultype");
boolean ok = false;
for (TypeRefComponent tr : ed.getType())
if (tr.getCode().equals(t))
for (TypeRefComponent tr : ed.getType())
if (tr.getCode().equals(t))
ok = true;
if (!ok)
throw new DefinitionException("Type '"+t+"' is not an acceptable type for '"+elementName+"' on property "+property.getDefinition().getPath());
} else {
t = elementName.substring(tail(ed.getPath()).length() - 3);
if (isPrimitive(lowFirst(t)))

View File

@ -20460,7 +20460,7 @@
<key value="dom-3"/>
<severity value="error"/>
<human value="If the resource is contained in another resource, it SHALL be referred to from elsewhere in the resource"/>
<expression value="contained.select(('#'+id in $context.descendents().reference).not()).empty()"/>
<expression value="contained.select(('#'+id in %resource.descendents().reference).not()).empty()"/>
<xpath value="not(exists(for $id in f:contained/*/@id return $id[not(ancestor::f:contained/parent::*/descendant::f:reference/@value=concat('#', $id))]))"/>
</constraint>
<constraint>
@ -20649,7 +20649,7 @@
<key value="dom-3"/>
<severity value="error"/>
<human value="If the resource is contained in another resource, it SHALL be referred to from elsewhere in the resource"/>
<expression value="contained.select(('#'+id in $context.descendents().reference).not()).empty()"/>
<expression value="contained.select(('#'+id in %resource.descendents().reference).not()).empty()"/>
<xpath value="not(exists(for $id in f:contained/*/@id return $id[not(ancestor::f:contained/parent::*/descendant::f:reference/@value=concat('#', $id))]))"/>
</constraint>
<constraint>
@ -121071,7 +121071,7 @@
<key value="obs-7"/>
<severity value="error"/>
<human value="Component code SHALL not be same as observation code"/>
<expression value="component.where(code = $context.code).empty()"/>
<expression value="component.where(code = %resource.code).empty()"/>
<xpath value="not(exists(f:component/f:code)) or count(for $coding in f:code/f:coding return parent::*/f:component/f:code/f:coding[f:code/@value=$coding/f:code/@value and f:system/@value=$coding/f:system/@value])=0"/>
</constraint>
<mapping>
@ -122307,7 +122307,7 @@
<key value="obs-7"/>
<severity value="error"/>
<human value="Component code SHALL not be same as observation code"/>
<expression value="component.where(code = $context.code).empty()"/>
<expression value="component.where(code = %resource.code).empty()"/>
<xpath value="not(exists(f:component/f:code)) or count(for $coding in f:code/f:coding return parent::*/f:component/f:code/f:coding[f:code/@value=$coding/f:code/@value and f:system/@value=$coding/f:system/@value])=0"/>
</constraint>
<mapping>
@ -154515,7 +154515,7 @@
<key value="sdf-8"/>
<severity value="error"/>
<human value="In any snapshot or differential, all the elements except the first have to have a path that starts with the path of the first + &quot;.&quot;"/>
<expression value="snapshot.element.tail().all(path.startsWith($context.snapshot.element.first().path+'.')) and differential.element.tail().all(path.startsWith($context.differential.element.first().path+'.'))"/>
<expression value="snapshot.element.tail().all(path.startsWith(%resource.snapshot.element.first().path+'.')) and differential.element.tail().all(path.startsWith(%resource.differential.element.first().path+'.'))"/>
<xpath value="string-join(for $elementName in f:*[self::f:snapshot or self::f:differential]/f:element[position()>1]/f:path/@value return if (starts-with($elementName, concat($elementName/ancestor::f:element/parent::f:*/f:element[1]/f:path/@value, '.'))) then '' else $elementName,'')=''"/>
</constraint>
<constraint>
@ -155580,7 +155580,7 @@
<key value="sdf-8"/>
<severity value="error"/>
<human value="In any snapshot or differential, all the elements except the first have to have a path that starts with the path of the first + &quot;.&quot;"/>
<expression value="snapshot.element.tail().all(path.startsWith($context.snapshot.element.first().path+'.')) and differential.element.tail().all(path.startsWith($context.differential.element.first().path+'.'))"/>
<expression value="snapshot.element.tail().all(path.startsWith(%resource.snapshot.element.first().path+'.')) and differential.element.tail().all(path.startsWith(%resource.differential.element.first().path+'.'))"/>
<xpath value="string-join(for $elementName in f:*[self::f:snapshot or self::f:differential]/f:element[position()>1]/f:path/@value return if (starts-with($elementName, concat($elementName/ancestor::f:element/parent::f:*/f:element[1]/f:path/@value, '.'))) then '' else $elementName,'')=''"/>
</constraint>
<constraint>

View File

@ -4681,7 +4681,7 @@
<key value="ref-1"/>
<severity value="error"/>
<human value="SHALL have a local reference if the resource is provided inline"/>
<expression value="reference.startsWith('#').not() or ($context.reference.substring(1).trace('url') in $resource.contained.id.trace('ids'))"/>
<expression value="reference.startsWith('#').not() or (reference.substring(1).trace('url') in %resource.contained.id.trace('ids'))"/>
<xpath value="not(starts-with(f:reference/@value, '#')) or exists(ancestor::*[self::f:entry or self::f:parameter]/f:resource/f:*/f:contained/f:*[f:id/@value=substring-after(current()/f:reference/@value, '#')]|/*/f:contained/f:*[f:id/@value=substring-after(current()/f:reference/@value, '#')])"/>
</constraint>
<mapping>
@ -4779,7 +4779,7 @@
<key value="ref-1"/>
<severity value="error"/>
<human value="SHALL have a local reference if the resource is provided inline"/>
<expression value="reference.startsWith('#').not() or ($context.reference.substring(1).trace('url') in $resource.contained.id.trace('ids'))"/>
<expression value="reference.startsWith('#').not() or (reference.substring(1).trace('url') in %resource.contained.id.trace('ids'))"/>
<xpath value="not(starts-with(f:reference/@value, '#')) or exists(ancestor::*[self::f:entry or self::f:parameter]/f:resource/f:*/f:contained/f:*[f:id/@value=substring-after(current()/f:reference/@value, '#')]|/*/f:contained/f:*[f:id/@value=substring-after(current()/f:reference/@value, '#')])"/>
</constraint>
<mapping>