mirror of
https://github.com/hapifhir/hapi-fhir.git
synced 2025-02-08 14:05:02 +00:00
Validator enhancements
This commit is contained in:
parent
e436254c32
commit
552842e547
@ -1,10 +1,8 @@
|
|||||||
package ca.uhn.fhir.jpa.config;
|
package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
import org.hl7.fhir.dstu21.hapi.validation.DefaultProfileValidationSupport;
|
|
||||||
import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.dstu21.hapi.validation.FhirQuestionnaireResponseValidator;
|
import org.hl7.fhir.dstu21.hapi.validation.FhirQuestionnaireResponseValidator;
|
||||||
import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport;
|
import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport;
|
||||||
import org.hl7.fhir.dstu21.hapi.validation.ValidationSupportChain;
|
|
||||||
import org.hl7.fhir.dstu21.validation.IResourceValidator.BestPracticeWarningLevel;
|
import org.hl7.fhir.dstu21.validation.IResourceValidator.BestPracticeWarningLevel;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -28,8 +26,6 @@ import org.hl7.fhir.dstu21.validation.IResourceValidator.BestPracticeWarningLeve
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
@ -40,6 +36,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||||||
import ca.uhn.fhir.jpa.dao.FhirSearchDao;
|
import ca.uhn.fhir.jpa.dao.FhirSearchDao;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
import ca.uhn.fhir.jpa.dao.ISearchDao;
|
||||||
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu21;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ -94,15 +91,9 @@ public class BaseDstu21Config extends BaseConfig {
|
|||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean(autowire=Autowire.BY_NAME)
|
||||||
public IValidationSupport validationSupportChainDstu21() {
|
public IValidationSupport validationSupportChainDstu21() {
|
||||||
return new ValidationSupportChain(defaultProfileValidationSupport(), jpaValidationSupportDstu21());
|
return new JpaValidationSupportChainDstu21();
|
||||||
// return new ValidationSupportChain();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(destroyMethod="flush")
|
|
||||||
public DefaultProfileValidationSupport defaultProfileValidationSupport() {
|
|
||||||
return new DefaultProfileValidationSupport();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
package ca.uhn.fhir.jpa.validation;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
import org.hl7.fhir.dstu21.hapi.validation.DefaultProfileValidationSupport;
|
||||||
|
import org.hl7.fhir.dstu21.hapi.validation.ValidationSupportChain;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
|
public class JpaValidationSupportChainDstu21 extends ValidationSupportChain {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("myJpaValidationSupportDstu21")
|
||||||
|
public ca.uhn.fhir.jpa.dao.IJpaValidationSupportDstu21 myJpaValidationSupportDstu21;
|
||||||
|
|
||||||
|
public JpaValidationSupportChainDstu21() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport();
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void postConstruct() {
|
||||||
|
addValidationSupport(myDefaultProfileValidationSupport);
|
||||||
|
addValidationSupport(myJpaValidationSupportDstu21);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
myDefaultProfileValidationSupport.flush();
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,7 @@ import ca.uhn.fhir.jpa.config.WebsocketDstu21Config;
|
|||||||
import ca.uhn.fhir.jpa.dao.dstu21.BaseJpaDstu21Test;
|
import ca.uhn.fhir.jpa.dao.dstu21.BaseJpaDstu21Test;
|
||||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu21;
|
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu21;
|
||||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||||
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu21;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||||
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
|
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
|
||||||
@ -46,7 +47,7 @@ public abstract class BaseResourceProviderDstu21Test extends BaseJpaDstu21Test {
|
|||||||
private static Server ourServer;
|
private static Server ourServer;
|
||||||
protected static String ourServerBase;
|
protected static String ourServerBase;
|
||||||
protected static RestfulServer ourRestServer;
|
protected static RestfulServer ourRestServer;
|
||||||
private static DefaultProfileValidationSupport myValidationSupport;
|
private static JpaValidationSupportChainDstu21 myValidationSupport;
|
||||||
|
|
||||||
public BaseResourceProviderDstu21Test() {
|
public BaseResourceProviderDstu21Test() {
|
||||||
super();
|
super();
|
||||||
@ -133,7 +134,7 @@ public abstract class BaseResourceProviderDstu21Test extends BaseJpaDstu21Test {
|
|||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(subsServletHolder.getServlet().getServletConfig().getServletContext());
|
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(subsServletHolder.getServlet().getServletConfig().getServletContext());
|
||||||
myValidationSupport = wac.getBean(DefaultProfileValidationSupport.class);
|
myValidationSupport = wac.getBean(JpaValidationSupportChainDstu21.class);
|
||||||
|
|
||||||
ourClient = myFhirCtx.newRestfulGenericClient(ourServerBase);
|
ourClient = myFhirCtx.newRestfulGenericClient(ourServerBase);
|
||||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||||
|
@ -66,7 +66,7 @@ public class ResourceProviderQuestionnaireResponseDstu21Test extends BaseResourc
|
|||||||
ourClient.create().resource(qr1).execute();
|
ourClient.create().resource(qr1).execute();
|
||||||
fail();
|
fail();
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (UnprocessableEntityException e) {
|
||||||
assertThat(e.toString(), containsString("Answer to question with linkId[link1] found of type [DecimalType] but this is invalid for question of type [string]"));
|
assertThat(e.toString(), containsString("Answer value must be of type string"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ public class ResourceProviderQuestionnaireResponseDstu21Test extends BaseResourc
|
|||||||
ourClient.create().resource(qr1).execute();
|
ourClient.create().resource(qr1).execute();
|
||||||
fail();
|
fail();
|
||||||
} catch (UnprocessableEntityException e) {
|
} catch (UnprocessableEntityException e) {
|
||||||
assertThat(e.toString(), containsString("Answer to question with linkId[link1] found of type [DecimalType] but this is invalid for question of type [string]"));
|
assertThat(e.toString(), containsString("Answer value must be of type string"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ package ca.uhn.fhirtest.config;
|
|||||||
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
@ -10,10 +9,7 @@ import org.apache.commons.dbcp2.BasicDataSource;
|
|||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.DependsOn;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
@ -30,7 +26,6 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
|||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
|
||||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
package org.hl7.fhir.dstu21.validation;
|
package org.hl7.fhir.dstu21.validation;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.dstu21.exceptions.DefinitionException;
|
import org.hl7.fhir.dstu21.exceptions.DefinitionException;
|
||||||
import org.hl7.fhir.dstu21.exceptions.FHIRException;
|
import org.hl7.fhir.dstu21.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.dstu21.formats.FormatUtilities;
|
import org.hl7.fhir.dstu21.formats.FormatUtilities;
|
||||||
@ -13,6 +16,7 @@ import org.hl7.fhir.dstu21.model.Base;
|
|||||||
import org.hl7.fhir.dstu21.model.CodeableConcept;
|
import org.hl7.fhir.dstu21.model.CodeableConcept;
|
||||||
import org.hl7.fhir.dstu21.model.Coding;
|
import org.hl7.fhir.dstu21.model.Coding;
|
||||||
import org.hl7.fhir.dstu21.model.ContactPoint;
|
import org.hl7.fhir.dstu21.model.ContactPoint;
|
||||||
|
import org.hl7.fhir.dstu21.model.DomainResource;
|
||||||
import org.hl7.fhir.dstu21.model.ElementDefinition;
|
import org.hl7.fhir.dstu21.model.ElementDefinition;
|
||||||
import org.hl7.fhir.dstu21.model.ElementDefinition.ConstraintSeverity;
|
import org.hl7.fhir.dstu21.model.ElementDefinition.ConstraintSeverity;
|
||||||
import org.hl7.fhir.dstu21.model.ElementDefinition.ElementDefinitionBindingComponent;
|
import org.hl7.fhir.dstu21.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||||
@ -28,6 +32,9 @@ import org.hl7.fhir.dstu21.model.OperationOutcome.IssueType;
|
|||||||
import org.hl7.fhir.dstu21.model.Period;
|
import org.hl7.fhir.dstu21.model.Period;
|
||||||
import org.hl7.fhir.dstu21.model.Property;
|
import org.hl7.fhir.dstu21.model.Property;
|
||||||
import org.hl7.fhir.dstu21.model.Quantity;
|
import org.hl7.fhir.dstu21.model.Quantity;
|
||||||
|
import org.hl7.fhir.dstu21.model.Questionnaire;
|
||||||
|
import org.hl7.fhir.dstu21.model.Questionnaire.QuestionnaireItemComponent;
|
||||||
|
import org.hl7.fhir.dstu21.model.Questionnaire.QuestionnaireItemType;
|
||||||
import org.hl7.fhir.dstu21.model.Range;
|
import org.hl7.fhir.dstu21.model.Range;
|
||||||
import org.hl7.fhir.dstu21.model.Ratio;
|
import org.hl7.fhir.dstu21.model.Ratio;
|
||||||
import org.hl7.fhir.dstu21.model.Reference;
|
import org.hl7.fhir.dstu21.model.Reference;
|
||||||
@ -461,7 +468,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
|
ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
|
||||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, "Binding for " + path + " missing (cc)")) {
|
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, "Binding for " + path + " missing (cc)")) {
|
||||||
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
||||||
ValueSet valueset = resolveBindingReference(binding.getValueSet());
|
ValueSet valueset = resolveBindingReference(profile, binding.getValueSet());
|
||||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
||||||
try {
|
try {
|
||||||
CodeableConcept cc = readAsCodeableConcept(element);
|
CodeableConcept cc = readAsCodeableConcept(element);
|
||||||
@ -532,7 +539,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
|
ElementDefinitionBindingComponent binding = theElementCntext.getBinding();
|
||||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, "Binding for " + path + " missing")) {
|
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, binding != null, "Binding for " + path + " missing")) {
|
||||||
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
||||||
ValueSet valueset = resolveBindingReference(binding.getValueSet());
|
ValueSet valueset = resolveBindingReference(profile, binding.getValueSet());
|
||||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, valueset != null, "ValueSet " + describeReference(binding.getValueSet()) + " not found")) {
|
||||||
try {
|
try {
|
||||||
Coding c = readAsCoding(element);
|
Coding c = readAsCoding(element);
|
||||||
@ -848,7 +855,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
checkFixedValue(errors, path + ".end", focus.getNamedChild("end"), fixed.getEndElement(), "end");
|
checkFixedValue(errors, path + ".end", focus.getNamedChild("end"), fixed.getEndElement(), "end");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkPrimitive(List<ValidationMessage> errors, String path, String type, ElementDefinition context, WrapperElement e) {
|
private void checkPrimitive(List<ValidationMessage> errors, String path, String type, ElementDefinition context, WrapperElement e, StructureDefinition profile) {
|
||||||
if (type.equals("uri")) {
|
if (type.equals("uri")) {
|
||||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, !e.getAttribute("value").startsWith("oid:"), "URI values cannot start with oid:");
|
rule(errors, IssueType.INVALID, e.line(), e.col(), path, !e.getAttribute("value").startsWith("oid:"), "URI values cannot start with oid:");
|
||||||
rule(errors, IssueType.INVALID, e.line(), e.col(), path, !e.getAttribute("value").startsWith("uuid:"), "URI values cannot start with uuid:");
|
rule(errors, IssueType.INVALID, e.line(), e.col(), path, !e.getAttribute("value").startsWith("uuid:"), "URI values cannot start with uuid:");
|
||||||
@ -882,13 +889,13 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (context.hasBinding()) {
|
if (context.hasBinding()) {
|
||||||
checkPrimitiveBinding(errors, path, type, context, e);
|
checkPrimitiveBinding(errors, path, type, context, e, profile);
|
||||||
}
|
}
|
||||||
// for nothing to check
|
// for nothing to check
|
||||||
}
|
}
|
||||||
|
|
||||||
// note that we don't check the type here; it could be string, uri or code.
|
// note that we don't check the type here; it could be string, uri or code.
|
||||||
private void checkPrimitiveBinding(List<ValidationMessage> errors, String path, String type, ElementDefinition elementContext, WrapperElement element) {
|
private void checkPrimitiveBinding(List<ValidationMessage> errors, String path, String type, ElementDefinition elementContext, WrapperElement element, StructureDefinition profile) {
|
||||||
if (!element.hasAttribute("value"))
|
if (!element.hasAttribute("value"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -898,7 +905,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
// firstly, resolve the value set
|
// firstly, resolve the value set
|
||||||
ElementDefinitionBindingComponent binding = elementContext.getBinding();
|
ElementDefinitionBindingComponent binding = elementContext.getBinding();
|
||||||
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
if (binding.hasValueSet() && binding.getValueSet() instanceof Reference) {
|
||||||
ValueSet vs = resolveBindingReference(binding.getValueSet());
|
ValueSet vs = resolveBindingReference(profile, binding.getValueSet());
|
||||||
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "ValueSet {0} not found", describeReference(binding.getValueSet()))) {
|
if (warning(errors, IssueType.CODEINVALID, element.line(), element.col(), path, vs != null, "ValueSet {0} not found", describeReference(binding.getValueSet()))) {
|
||||||
ValidationResult vr = context.validateCode(null, value, null, vs);
|
ValidationResult vr = context.validateCode(null, value, null, vs);
|
||||||
if (!vr.isOk()) {
|
if (!vr.isOk()) {
|
||||||
@ -1157,6 +1164,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
private ElementDefinition getCriteriaForDiscriminator(String path, ElementDefinition ed, String discriminator, StructureDefinition profile) throws DefinitionException {
|
private ElementDefinition getCriteriaForDiscriminator(String path, ElementDefinition ed, String discriminator, StructureDefinition profile) throws DefinitionException {
|
||||||
List<ElementDefinition> childDefinitions = getChildMap(profile, ed);
|
List<ElementDefinition> childDefinitions = getChildMap(profile, ed);
|
||||||
List<ElementDefinition> snapshot = null;
|
List<ElementDefinition> snapshot = null;
|
||||||
|
int index;
|
||||||
if (childDefinitions.isEmpty()) {
|
if (childDefinitions.isEmpty()) {
|
||||||
// going to look at the type
|
// going to look at the type
|
||||||
if (ed.getType().size() == 0)
|
if (ed.getType().size() == 0)
|
||||||
@ -1173,14 +1181,14 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
type = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + ed.getType().get(0).getCode());
|
type = context.fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + ed.getType().get(0).getCode());
|
||||||
snapshot = type.getSnapshot().getElement();
|
snapshot = type.getSnapshot().getElement();
|
||||||
ed = snapshot.get(0);
|
ed = snapshot.get(0);
|
||||||
|
index = 0;
|
||||||
} else {
|
} else {
|
||||||
snapshot = profile.getSnapshot().getElement();
|
snapshot = childDefinitions;
|
||||||
|
index = -1;
|
||||||
}
|
}
|
||||||
String originalPath = ed.getPath();
|
String originalPath = ed.getPath();
|
||||||
String goal = originalPath + "." + discriminator;
|
String goal = originalPath + "." + discriminator;
|
||||||
|
|
||||||
int index = snapshot.indexOf(ed);
|
|
||||||
assert(index > -1);
|
|
||||||
index++;
|
index++;
|
||||||
while (index < snapshot.size() && !snapshot.get(index).getPath().equals(originalPath)) {
|
while (index < snapshot.size() && !snapshot.get(index).getPath().equals(originalPath)) {
|
||||||
if (snapshot.get(index).getPath().equals(goal))
|
if (snapshot.get(index).getPath().equals(goal))
|
||||||
@ -1344,11 +1352,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueSet resolveBindingReference(Type reference) {
|
private ValueSet resolveBindingReference(DomainResource ctxt, Type reference) {
|
||||||
if (reference instanceof UriType)
|
if (reference instanceof UriType)
|
||||||
return context.fetchResource(ValueSet.class, ((UriType) reference).getValue().toString());
|
return context.fetchResource(ValueSet.class, ((UriType) reference).getValue().toString());
|
||||||
else if (reference instanceof Reference)
|
else if (reference instanceof Reference) {
|
||||||
|
String s = ((Reference) reference).getReference();
|
||||||
|
if (s.startsWith("#")) {
|
||||||
|
for (Resource c : ctxt.getContained()) {
|
||||||
|
if (c.getId().equals(s.substring(1)) && (c instanceof ValueSet))
|
||||||
|
return (ValueSet) c;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} else
|
||||||
return context.fetchResource(ValueSet.class, ((Reference) reference).getReference());
|
return context.fetchResource(ValueSet.class, ((Reference) reference).getReference());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1490,9 +1507,239 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
validateBundle(errors, element, stack);
|
validateBundle(errors, element, stack);
|
||||||
if (element.getResourceType().equals("Observation"))
|
if (element.getResourceType().equals("Observation"))
|
||||||
validateObservation(errors, element, stack);
|
validateObservation(errors, element, stack);
|
||||||
|
if (element.getResourceType().equals("QuestionnaireResponse"))
|
||||||
|
validateQuestionannaireResponse(errors, element, stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateQuestionannaireResponse(List<ValidationMessage> errors, WrapperElement element, NodeStack stack) {
|
||||||
|
WrapperElement q = element.getNamedChild("questionnaire");
|
||||||
|
if (hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), q != null, "No questionnaire is identified, so no validation can be performed against the base questionnaire")) {
|
||||||
|
Questionnaire qsrc = context.fetchResource(Questionnaire.class, q.getNamedChildValue("reference"));
|
||||||
|
if (warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, "The questionnaire could not be resolved, so no validation can be performed against the base questionnaire"))
|
||||||
|
validateQuestionannaireResponseItems(qsrc, qsrc.getItem(), errors, element, stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, WrapperElement element, NodeStack stack) {
|
||||||
|
String text = element.getNamedChildValue("text");
|
||||||
|
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), Utilities.noString(text) || text.equals(qItem.getText()), "If text exists, it must match the questionnaire definition for linkId "+qItem.getLinkId());
|
||||||
|
|
||||||
|
List<WrapperElement> answers = new ArrayList<InstanceValidator.WrapperElement>();
|
||||||
|
element.getNamedChildren("answer", answers);
|
||||||
|
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), (answers.size() > 0) || !qItem.getRequired(), "No response answer found for required item "+qItem.getLinkId());
|
||||||
|
if (answers.size() > 1)
|
||||||
|
rule(errors, IssueType.INVALID, answers.get(1).line(), answers.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), "Only one response answer item with this linkId allowed");
|
||||||
|
|
||||||
|
for (WrapperElement answer : answers) {
|
||||||
|
NodeStack ns = stack.push(answer, -1, null, null);
|
||||||
|
switch (qItem.getType()) {
|
||||||
|
case GROUP:
|
||||||
|
rule(errors, IssueType.STRUCTURE, answer.line(), answer.col(), stack.getLiteralPath(), false, "Items of type group should not have answers");
|
||||||
|
break;
|
||||||
|
case DISPLAY: // nothing
|
||||||
|
break;
|
||||||
|
case BOOLEAN:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "boolean");
|
||||||
|
break;
|
||||||
|
case DECIMAL:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "decimal");
|
||||||
|
break;
|
||||||
|
case INTEGER:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "integer");
|
||||||
|
break;
|
||||||
|
case DATE:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "date");
|
||||||
|
break;
|
||||||
|
case DATETIME:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "dateTime");
|
||||||
|
break;
|
||||||
|
case INSTANT:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "instant");
|
||||||
|
break;
|
||||||
|
case TIME:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "time");
|
||||||
|
break;
|
||||||
|
case STRING:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "string");
|
||||||
|
break;
|
||||||
|
case TEXT:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "text");
|
||||||
|
break;
|
||||||
|
case URL:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "uri");
|
||||||
|
break;
|
||||||
|
case ATTACHMENT:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "Attachment");
|
||||||
|
break;
|
||||||
|
case REFERENCE:
|
||||||
|
validateQuestionnaireResponseItemType(errors, answer, ns, "Reference");
|
||||||
|
break;
|
||||||
|
case QUANTITY:
|
||||||
|
if (validateQuestionnaireResponseItemType(errors, answer, ns, "Quantity").equals("Quantity"))
|
||||||
|
if (qItem.hasExtension("???"))
|
||||||
|
validateQuestionnaireResponseItemQuantity(errors, answer, ns);
|
||||||
|
break;
|
||||||
|
case CHOICE:
|
||||||
|
if (validateQuestionnaireResponseItemType(errors, answer, ns, "Coding").equals("Coding"))
|
||||||
|
validateAnswerCode(errors, answer, ns, qsrc, qItem);
|
||||||
|
break;
|
||||||
|
case OPENCHOICE:
|
||||||
|
if (validateQuestionnaireResponseItemType(errors, answer, ns, "Coding", "string").equals("Coding"))
|
||||||
|
validateAnswerCode(errors, answer, ns, qsrc, qItem);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack);
|
||||||
|
}
|
||||||
|
if (qItem.getType() == QuestionnaireItemType.GROUP)
|
||||||
|
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, element, stack);
|
||||||
|
else {
|
||||||
|
List<WrapperElement> items = new ArrayList<InstanceValidator.WrapperElement>();
|
||||||
|
element.getNamedChildren("item", items);
|
||||||
|
for (WrapperElement item : items) {
|
||||||
|
NodeStack ns = stack.push(item, -1, null, null);
|
||||||
|
rule(errors, IssueType.STRUCTURE, answers.get(0).line(), answers.get(0).col(), stack.getLiteralPath(), false, "Items not of type group should not have items");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, List<WrapperElement> elements, NodeStack stack) {
|
||||||
|
if (elements.size() > 1)
|
||||||
|
rule(errors, IssueType.INVALID, elements.get(1).line(), elements.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), "Only one response item with this linkId allowed");
|
||||||
|
for (WrapperElement element : elements) {
|
||||||
|
NodeStack ns = stack.push(element, -1, null, null);
|
||||||
|
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getLinkIdIndex(List<QuestionnaireItemComponent> qItems, String linkId) {
|
||||||
|
for (int i = 0; i < qItems.size(); i++) {
|
||||||
|
if (linkId.equals(qItems.get(i).getLinkId()))
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateQuestionannaireResponseItems(Questionnaire qsrc, List<QuestionnaireItemComponent> qItems, List<ValidationMessage> errors, WrapperElement element, NodeStack stack) {
|
||||||
|
List<WrapperElement> items = new ArrayList<WrapperElement>();
|
||||||
|
element.getNamedChildren("item", items);
|
||||||
|
// now, sort into stacks
|
||||||
|
Map<String, List<WrapperElement>> map = new HashMap<String, List<WrapperElement>>();
|
||||||
|
int lastIndex = -1;
|
||||||
|
for (WrapperElement item : items) {
|
||||||
|
String linkId = item.getNamedChildValue("linkId");
|
||||||
|
if (rule(errors, IssueType.REQUIRED, item.line(), item.col(), stack.getLiteralPath(), !Utilities.noString(linkId), "No LinkId, so can't be validated")) {
|
||||||
|
int index = getLinkIdIndex(qItems, linkId);
|
||||||
|
if (index == -1) {
|
||||||
|
QuestionnaireItemComponent qItem = findQuestionnaireItem(qsrc, linkId);
|
||||||
|
if (qItem != null) {
|
||||||
|
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index > -1, "Structural Error: item is in the wrong place");
|
||||||
|
NodeStack ns = stack.push(item, -1, null, null);
|
||||||
|
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
rule(errors, IssueType.NOTFOUND, item.line(), item.col(), stack.getLiteralPath(), index > -1, "LinkId \""+linkId+"\" not found in questionnaire");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index >= lastIndex, "Structural Error: items are out of order");
|
||||||
|
lastIndex = index;
|
||||||
|
List<WrapperElement> mapItem = map.get(linkId);
|
||||||
|
if (mapItem == null) {
|
||||||
|
mapItem = new ArrayList<WrapperElement>();
|
||||||
|
map.put(linkId, mapItem);
|
||||||
|
}
|
||||||
|
mapItem.add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ok, now we have a list of known items, grouped by linkId. We"ve made an error for anything out of order
|
||||||
|
for (QuestionnaireItemComponent qItem : qItems) {
|
||||||
|
List<WrapperElement> mapItem = map.get(qItem.getLinkId());
|
||||||
|
if (mapItem != null)
|
||||||
|
validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack);
|
||||||
|
else
|
||||||
|
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), !qItem.getRequired(), "No response found for required item "+qItem.getLinkId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateQuestionnaireResponseItemQuantity( List<ValidationMessage> errors, WrapperElement answer, NodeStack stack) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private String validateQuestionnaireResponseItemType(List<ValidationMessage> errors, WrapperElement element, NodeStack stack, String... types) {
|
||||||
|
List<WrapperElement> values = new ArrayList<WrapperElement>();
|
||||||
|
element.getNamedChildrenWithWildcard("value[x]", values);
|
||||||
|
if (values.size() > 0) {
|
||||||
|
NodeStack ns = stack.push(values.get(0), -1, null, null);
|
||||||
|
CommaSeparatedStringBuilder l = new CommaSeparatedStringBuilder();
|
||||||
|
for (String s : types) {
|
||||||
|
l.append(s);
|
||||||
|
if (values.get(0).getName().equals("value"+Utilities.capitalize(s)))
|
||||||
|
return(s);
|
||||||
|
}
|
||||||
|
if (types.length == 1)
|
||||||
|
rule(errors, IssueType.STRUCTURE, values.get(0).line(), values.get(0).col(), ns.getLiteralPath(), false, "Answer value must be of type "+types[0]);
|
||||||
|
else
|
||||||
|
rule(errors, IssueType.STRUCTURE, values.get(0).line(), values.get(0).col(), ns.getLiteralPath(), false, "Answer value must be one of the types "+l.toString());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private QuestionnaireItemComponent findQuestionnaireItem(Questionnaire qSrc, String linkId) {
|
||||||
|
return findItem(qSrc.getItem(), linkId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QuestionnaireItemComponent findItem(List<QuestionnaireItemComponent> list, String linkId) {
|
||||||
|
for (QuestionnaireItemComponent item : list) {
|
||||||
|
if (linkId.equals(item.getLinkId()))
|
||||||
|
return item;
|
||||||
|
QuestionnaireItemComponent result = findItem(item.getItem(), linkId);
|
||||||
|
if (result != null)
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAnswerCode(List<ValidationMessage> errors, WrapperElement value, NodeStack stack, List<Coding> optionList) {
|
||||||
|
String system = value.getNamedChildValue("system");
|
||||||
|
String code = value.getNamedChildValue("code");
|
||||||
|
boolean found = false;
|
||||||
|
for (Coding c : optionList) {
|
||||||
|
if (StringUtils.equals(c.getSystem(), system) && StringUtils.equals(c.getCode(), code)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rule(errors, IssueType.STRUCTURE, value.line(), value.col(), stack.getLiteralPath(), found, "The code "+system+"::"+code+" is not a valid option");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAnswerCode(List<ValidationMessage> errors, WrapperElement value, NodeStack stack, Questionnaire qSrc, Reference ref) {
|
||||||
|
ValueSet vs = resolveBindingReference(qSrc, ref);
|
||||||
|
if (warning(errors, IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), vs != null, "ValueSet " + describeReference(ref) + " not found")) {
|
||||||
|
try {
|
||||||
|
Coding c = readAsCoding(value);
|
||||||
|
ValidationResult res = context.validateCode(c, vs);
|
||||||
|
if (!res.isOk())
|
||||||
|
rule(errors, IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), false, "The value provided is not in the options value set in the questionnaire");
|
||||||
|
} catch (Exception e) {
|
||||||
|
warning(errors, IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), false, "Error " + e.getMessage() + " validating Coding against Questionnaire Options");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateAnswerCode( List<ValidationMessage> errors, WrapperElement answer, NodeStack stack, Questionnaire qSrc, QuestionnaireItemComponent qItem) {
|
||||||
|
WrapperElement v = answer.getNamedChild("valueCoding");
|
||||||
|
NodeStack ns = stack.push(v, -1, null, null);
|
||||||
|
if (qItem.getOption().size() > 0)
|
||||||
|
validateAnswerCode(errors, v, stack, qItem.getOption());
|
||||||
|
else if (qItem.hasOptions())
|
||||||
|
validateAnswerCode(errors, v, stack, qSrc, qItem.getOptions());
|
||||||
|
else
|
||||||
|
hint(errors, IssueType.STRUCTURE, v.line(), v.col(), stack.getLiteralPath(), false, "Cannot validate options because no option or options are provided");
|
||||||
|
}
|
||||||
|
|
||||||
private String tail(String path) {
|
private String tail(String path) {
|
||||||
return path.substring(path.lastIndexOf(".") + 1);
|
return path.substring(path.lastIndexOf(".") + 1);
|
||||||
}
|
}
|
||||||
@ -1895,8 +2142,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
if (rule(errors, IssueType.INVALID, composition.line(), composition.col(), stack.getLiteralPath(), composition.getResourceType().equals("Composition"),
|
if (rule(errors, IssueType.INVALID, composition.line(), composition.col(), stack.getLiteralPath(), composition.getResourceType().equals("Composition"),
|
||||||
"The first entry in a document must be a composition")) {
|
"The first entry in a document must be a composition")) {
|
||||||
// the composition subject and section references must resolve in the bundle
|
// the composition subject and section references must resolve in the bundle
|
||||||
validateBundleReference(errors, entries, composition.getNamedChild("subject"), "Composition Subject", stack.push(composition.getNamedChild("subject"), -1, null, null), fullUrl, "Composition",
|
WrapperElement elem = composition.getNamedChild("subject");
|
||||||
id);
|
if (rule(errors, IssueType.INVALID, composition.line(), composition.col(), stack.getLiteralPath(), elem == null, "A document composition must have a subject"))
|
||||||
|
validateBundleReference(errors, entries, elem, "Composition Subject", stack.push(elem, -1, null, null), fullUrl, "Composition", id);
|
||||||
validateSections(errors, entries, composition, stack, fullUrl, id);
|
validateSections(errors, entries, composition, stack, fullUrl, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1922,7 +2170,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
}
|
}
|
||||||
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), !empty(element), "Elements must have some content (@value, extensions, or children elements)");
|
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), !empty(element), "Elements must have some content (@value, extensions, or children elements)");
|
||||||
|
|
||||||
checkInvariants(errors, stack.literalPath, profile, definition, null, null, resource, element);
|
checkInvariants(errors, stack.getLiteralPath(), profile, definition, null, null, resource, element);
|
||||||
|
|
||||||
// get the list of direct defined children, including slices
|
// get the list of direct defined children, including slices
|
||||||
List<ElementDefinition> childDefinitions = getChildMap(profile, definition.getName(), definition.getPath(), definition.getNameReference());
|
List<ElementDefinition> childDefinitions = getChildMap(profile, definition.getName(), definition.getPath(), definition.getNameReference());
|
||||||
@ -2039,7 +2287,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||||||
|
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
if (isPrimitiveType(type))
|
if (isPrimitiveType(type))
|
||||||
checkPrimitive(errors, ei.path, type, ei.definition, ei.element);
|
checkPrimitive(errors, ei.path, type, ei.definition, ei.element, profile);
|
||||||
else {
|
else {
|
||||||
if (type.equals("Identifier"))
|
if (type.equals("Identifier"))
|
||||||
checkIdentifier(errors, ei.path, ei.element, ei.definition);
|
checkIdentifier(errors, ei.path, ei.element, ei.definition);
|
||||||
|
@ -9,6 +9,7 @@ import static org.mockito.Matchers.any;
|
|||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@ -23,6 +24,7 @@ import org.hl7.fhir.dstu21.hapi.validation.DefaultProfileValidationSupport;
|
|||||||
import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.dstu21.hapi.validation.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport;
|
import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport;
|
||||||
import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport.CodeValidationResult;
|
import org.hl7.fhir.dstu21.hapi.validation.IValidationSupport.CodeValidationResult;
|
||||||
|
import org.hl7.fhir.dstu21.hapi.validation.ValidationSupportChain;
|
||||||
import org.hl7.fhir.dstu21.model.CodeType;
|
import org.hl7.fhir.dstu21.model.CodeType;
|
||||||
import org.hl7.fhir.dstu21.model.Observation;
|
import org.hl7.fhir.dstu21.model.Observation;
|
||||||
import org.hl7.fhir.dstu21.model.Observation.ObservationStatus;
|
import org.hl7.fhir.dstu21.model.Observation.ObservationStatus;
|
||||||
@ -33,6 +35,7 @@ import org.hl7.fhir.dstu21.model.ValueSet.ConceptDefinitionComponent;
|
|||||||
import org.hl7.fhir.dstu21.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.dstu21.model.ValueSet.ConceptSetComponent;
|
||||||
import org.hl7.fhir.dstu21.model.ValueSet.ValueSetExpansionComponent;
|
import org.hl7.fhir.dstu21.model.ValueSet.ValueSetExpansionComponent;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -62,6 +65,11 @@ public class FhirInstanceValidatorDstu21Test {
|
|||||||
myValidConcepts.add(theSystem + "___" + theCode);
|
myValidConcepts.add(theSystem + "___" + theCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() {
|
||||||
|
myDefaultValidationSupport.flush();
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
@ -69,14 +77,17 @@ public class FhirInstanceValidatorDstu21Test {
|
|||||||
myVal.setValidateAgainstStandardSchema(false);
|
myVal.setValidateAgainstStandardSchema(false);
|
||||||
myVal.setValidateAgainstStandardSchematron(false);
|
myVal.setValidateAgainstStandardSchematron(false);
|
||||||
|
|
||||||
myInstanceVal = new FhirInstanceValidator(myDefaultValidationSupport);
|
myMockSupport = mock(IValidationSupport.class);
|
||||||
|
ValidationSupportChain validationSupport = new ValidationSupportChain(myMockSupport, myDefaultValidationSupport);
|
||||||
|
myInstanceVal = new FhirInstanceValidator(validationSupport);
|
||||||
|
|
||||||
myVal.registerValidatorModule(myInstanceVal);
|
myVal.registerValidatorModule(myInstanceVal);
|
||||||
|
|
||||||
mySupportedCodeSystemsForExpansion = new HashMap<String, ValueSet.ValueSetExpansionComponent>();
|
mySupportedCodeSystemsForExpansion = new HashMap<String, ValueSet.ValueSetExpansionComponent>();
|
||||||
|
|
||||||
myValidConcepts = new ArrayList<String>();
|
myValidConcepts = new ArrayList<String>();
|
||||||
|
|
||||||
myMockSupport = mock(IValidationSupport.class);
|
|
||||||
when(myMockSupport.expandValueSet(any(FhirContext.class), any(ConceptSetComponent.class))).thenAnswer(new Answer<ValueSetExpansionComponent>() {
|
when(myMockSupport.expandValueSet(any(FhirContext.class), any(ConceptSetComponent.class))).thenAnswer(new Answer<ValueSetExpansionComponent>() {
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent answer(InvocationOnMock theInvocation) throws Throwable {
|
public ValueSetExpansionComponent answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
@ -100,9 +111,14 @@ public class FhirInstanceValidatorDstu21Test {
|
|||||||
when(myMockSupport.fetchResource(any(FhirContext.class), any(Class.class), any(String.class))).thenAnswer(new Answer<IBaseResource>() {
|
when(myMockSupport.fetchResource(any(FhirContext.class), any(Class.class), any(String.class))).thenAnswer(new Answer<IBaseResource>() {
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource answer(InvocationOnMock theInvocation) throws Throwable {
|
public IBaseResource answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
IBaseResource retVal = myDefaultValidationSupport.fetchResource((FhirContext) theInvocation.getArguments()[0], (Class<IBaseResource>) theInvocation.getArguments()[1],
|
IBaseResource retVal;
|
||||||
(String) theInvocation.getArguments()[2]);
|
String id = (String) theInvocation.getArguments()[2];
|
||||||
ourLog.info("fetchResource({}, {}) : {}", new Object[] { theInvocation.getArguments()[1], theInvocation.getArguments()[2], retVal });
|
if ("Questionnaire/q_jon".equals(id)) {
|
||||||
|
retVal = ourCtx.newJsonParser().parseResource(IOUtils.toString(FhirInstanceValidatorDstu21Test.class.getResourceAsStream("/q_jon.json")));
|
||||||
|
} else {
|
||||||
|
retVal = myDefaultValidationSupport.fetchResource((FhirContext) theInvocation.getArguments()[0], (Class<IBaseResource>) theInvocation.getArguments()[1], id);
|
||||||
|
}
|
||||||
|
ourLog.info("fetchResource({}, {}) : {}", new Object[] { theInvocation.getArguments()[1], id, retVal });
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -214,7 +230,7 @@ public class FhirInstanceValidatorDstu21Test {
|
|||||||
ValidationResult output = null;
|
ValidationResult output = null;
|
||||||
int passes = 1;
|
int passes = 1;
|
||||||
for (int i = 0; i < passes; i++) {
|
for (int i = 0; i < passes; i++) {
|
||||||
ourLog.info("Pass {}", i+1);
|
ourLog.info("Pass {}", i + 1);
|
||||||
output = myVal.validateWithResult(input);
|
output = myVal.validateWithResult(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +257,16 @@ public class FhirInstanceValidatorDstu21Test {
|
|||||||
assertEquals("Element is unknown or does not match any slice", output.getMessages().get(0).getMessage());
|
assertEquals("Element is unknown or does not match any slice", output.getMessages().get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateQuestionnaireResponse() throws IOException {
|
||||||
|
String input = IOUtils.toString(FhirInstanceValidatorDstu21Test.class.getResourceAsStream("/qr_jon.xml"));
|
||||||
|
|
||||||
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
|
assertEquals(output.toString(), 12, output.getMessages().size());
|
||||||
|
ourLog.info(output.getMessages().get(0).getLocationString());
|
||||||
|
ourLog.info(output.getMessages().get(0).getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateResourceFailingInvariant() {
|
public void testValidateResourceFailingInvariant() {
|
||||||
Observation input = new Observation();
|
Observation input = new Observation();
|
||||||
@ -322,7 +348,7 @@ public class FhirInstanceValidatorDstu21Test {
|
|||||||
addValidConcept("http://loinc.org", "1234567");
|
addValidConcept("http://loinc.org", "1234567");
|
||||||
|
|
||||||
Observation input = new Observation();
|
Observation input = new Observation();
|
||||||
// input.getMeta().addProfile("http://hl7.org/fhir/StructureDefinition/devicemetricobservation");
|
// input.getMeta().addProfile("http://hl7.org/fhir/StructureDefinition/devicemetricobservation");
|
||||||
|
|
||||||
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
input.addIdentifier().setSystem("http://acme").setValue("12345");
|
||||||
input.getEncounter().setReference("http://foo.com/Encounter/9");
|
input.getEncounter().setReference("http://foo.com/Encounter/9");
|
||||||
|
1369
hapi-fhir-structures-dstu2.1/src/test/resources/q_jon.json
Normal file
1369
hapi-fhir-structures-dstu2.1/src/test/resources/q_jon.json
Normal file
File diff suppressed because it is too large
Load Diff
455
hapi-fhir-structures-dstu2.1/src/test/resources/qr_jon.xml
Normal file
455
hapi-fhir-structures-dstu2.1/src/test/resources/qr_jon.xml
Normal file
@ -0,0 +1,455 @@
|
|||||||
|
<QuestionnaireResponse xmlns="http://hl7.org/fhir">
|
||||||
|
<identifier>
|
||||||
|
<value value="1234567890"/>
|
||||||
|
</identifier>
|
||||||
|
<questionnaire>
|
||||||
|
<reference value="Questionnaire/q_jon"/>
|
||||||
|
</questionnaire>
|
||||||
|
<status value="completed"/>
|
||||||
|
<subject>
|
||||||
|
<reference value="http://fhirtest.uhn.ca/baseDstu2.1/Patient/proband"/>
|
||||||
|
</subject>
|
||||||
|
<author>
|
||||||
|
<reference value="http://fhirtest.uhn.ca/baseDstu2.1/Practitioner/f007"/>
|
||||||
|
</author>
|
||||||
|
<authored value="2016-01-08"/>
|
||||||
|
<item>
|
||||||
|
<linkId value="root"/>
|
||||||
|
<item>
|
||||||
|
<linkId value="g1"/>
|
||||||
|
<text value="CLINICAL INFORMATION"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="1.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="1.1"/>
|
||||||
|
<text value="Patient Clinical Information"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="Previous chest X-RAY was suspicious. Heavy smoker, 15 pack years."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="1.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="1.2"/>
|
||||||
|
<text value="Previous Examination (Date and Modality)"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="Chest XR - September 23, 2015"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<linkId value="g2"/>
|
||||||
|
<text value="IMAGING PROCEDURE DESCRIPTION"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="2.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="2.1"/>
|
||||||
|
<text value="Overall Image Quality:"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="2.1a"/>
|
||||||
|
<display value="Adequate"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="2.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="2.2"/>
|
||||||
|
<text value="Intravenous Contrast Used?"/>
|
||||||
|
<answer>
|
||||||
|
<valueBoolean value="false"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="2.3"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="2.3"/>
|
||||||
|
<text value="Additional Comments"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="n/a."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<linkId value="g3"/>
|
||||||
|
<text value="FINDINGS"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="g3.0"/>
|
||||||
|
<text value="T Category"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="g3.1"/>
|
||||||
|
<text value="Location of Main Nodule/Mass (Primary tumor, or Reference tumor)"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.1.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="q3.1.1"/>
|
||||||
|
<text value="Location of main nodule/mass:"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="3.1.1a"/>
|
||||||
|
<display value="Peripheral"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.1.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.1.2"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="Right Upper Lung, Posterior segment."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="g3.2"/>
|
||||||
|
<text value="Size and characteristics of main nodule/mass"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.2.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.2.1"/>
|
||||||
|
<text value="Size of the nodule/mass:"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="3.2.1a"/>
|
||||||
|
<display value="Solid nodule/mass"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
<item><!-- Measurement, image, series, etc for all 3 answer choices goes here. Conditonal. -->
|
||||||
|
<linkId value="g3.2.1"/>
|
||||||
|
<item><!-- Group for answer choice a -->
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen"><!-- Note that this extension is at the group level. -->
|
||||||
|
<extension url="#question">
|
||||||
|
<valueString value="3.2.1"/>
|
||||||
|
</extension>
|
||||||
|
<extension url="#answer">
|
||||||
|
<valueCoding>
|
||||||
|
<code value="3.2.1a"/>
|
||||||
|
</valueCoding>
|
||||||
|
</extension>
|
||||||
|
</extension>
|
||||||
|
<linkId value="g3.2.1a"/>
|
||||||
|
<item>
|
||||||
|
<linkId value="3.2.1a"/>
|
||||||
|
<text value="largest dimension:"/>
|
||||||
|
<answer>
|
||||||
|
<valueInteger value="20"/>
|
||||||
|
</answer>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl">
|
||||||
|
<valueCodeableConcept>
|
||||||
|
<coding>
|
||||||
|
<system value="http://hl7.org/fhir/ValueSet/questionnaire-item-control"/>
|
||||||
|
<code value="unit"/>
|
||||||
|
</coding>
|
||||||
|
</valueCodeableConcept>
|
||||||
|
</extension>
|
||||||
|
<text value="mm"/>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<linkId value="3.2.1a.image"/>
|
||||||
|
<text value="image"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="32"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<linkId value="3.2.1a.series"/>
|
||||||
|
<text value="series"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="3"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.2.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.2.2"/>
|
||||||
|
<text value="Plane in which the mass was measured:"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="3.2.2a"/>
|
||||||
|
<display value="Axial"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.2.3"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.2.3"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="Solid attenuation of mass, margins spiculated."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.3"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="g3.3"/>
|
||||||
|
<text value="Structures directly involved"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.3.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.3.1"/>
|
||||||
|
<text value="State if there is bronchial involvement:"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="3.3.1b"/>
|
||||||
|
<display value="No"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.3.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.3.2"/>
|
||||||
|
<text value="Is there direct involvement of any other anatomical structures?"/>
|
||||||
|
<answer>
|
||||||
|
<valueBoolean value="false"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.3.3"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.3.3"/>
|
||||||
|
<text value="Are there additional suspicious pulmonary nodules?"/>
|
||||||
|
<answer>
|
||||||
|
<valueBoolean value="false"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="3.3.4"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="3.3.4"/>
|
||||||
|
<text value="Other notable intrathoracic findings (eg lymphangitis carcinomatosis):"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="n/a"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="4"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="4.0"/>
|
||||||
|
<text value="N Category"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="4.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="4.1"/>
|
||||||
|
<text value="Are there enlarged lymph nodes?"/>
|
||||||
|
<answer>
|
||||||
|
<valueBoolean value="false"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="4.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="4.2"/>
|
||||||
|
<text value="Other notable findings:"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="Liner / scar atelectasis lingua, anterior segment of right upper lobe and bilateral lower lobes."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="5"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="5.0"/>
|
||||||
|
<text value="M Category (Suspicious Extrathoracic Findings (M1b))"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="5.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="5.1"/>
|
||||||
|
<text value="Are there suspicious extrathoracic findings?"/>
|
||||||
|
<answer>
|
||||||
|
<valueBoolean value="true"/>
|
||||||
|
</answer>
|
||||||
|
<item>
|
||||||
|
<linkId value="g5.1.yes"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen">
|
||||||
|
<extension url="#question">
|
||||||
|
<valueString value="5.1"/>
|
||||||
|
</extension>
|
||||||
|
<extension url="#answer">
|
||||||
|
<valueBoolean value="true"/>
|
||||||
|
</extension>
|
||||||
|
</extension>
|
||||||
|
<linkId value="5.1.yes"/>
|
||||||
|
<text value="Applicable Structures and Descriptions:"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="5.1.yes.d"/>
|
||||||
|
<display value="Other"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen">
|
||||||
|
<extension url="#question">
|
||||||
|
<valueString value="5.1.yes"/>
|
||||||
|
</extension>
|
||||||
|
<extension url="#answer">
|
||||||
|
<valueCoding>
|
||||||
|
<code value="5.1.yes.d"/>
|
||||||
|
</valueCoding>
|
||||||
|
</extension>
|
||||||
|
</extension>
|
||||||
|
<linkId value="5.1.yes.d.description"/>
|
||||||
|
<text value="Description of structures:"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="3 cm calcified thyroid nodule on TUL left."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="6"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="6.0"/>
|
||||||
|
<text value="Additional Findings"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="6.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="6.1"/>
|
||||||
|
<text value="Are there additional findings?"/>
|
||||||
|
<answer>
|
||||||
|
<valueBoolean value="true"/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="6.2"/>
|
||||||
|
</extension>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen">
|
||||||
|
<extension url="#question">
|
||||||
|
<valueString value="6.1"/>
|
||||||
|
</extension>
|
||||||
|
<extension url="#answer">
|
||||||
|
<valueBoolean value="true"/>
|
||||||
|
</extension>
|
||||||
|
</extension>
|
||||||
|
<linkId value="6.2"/>
|
||||||
|
<text value="Findings and Descriptions:"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="Oligemic changes in right upper lobe from possible old pulmonary embolus."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<linkId value="g7"/>
|
||||||
|
<text value="IMPRESSIONS"/>
|
||||||
|
<item>
|
||||||
|
<linkId value="g7.1"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="7.1"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="7.1"/>
|
||||||
|
<text value="Impression/Summary:"/>
|
||||||
|
<answer>
|
||||||
|
<valueString value="Spiculated mass in posterior segment of right upper lobe that has increasing size from 16 to 20 mm."/>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="7.2"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="g7.2"/>
|
||||||
|
<text value="Radiologic Staging (TNM Version – 7th edition)"/>
|
||||||
|
<item>
|
||||||
|
<linkId value="g7.20"/>
|
||||||
|
<text value="If this is a biopsy proven carcinoma, the preliminary radiologic stage is:"/>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="i)"/>
|
||||||
|
</extension>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-questionControl" >
|
||||||
|
<valueCodeableConcept>
|
||||||
|
<coding>
|
||||||
|
<code value="radio-button"/>
|
||||||
|
<display value="Radio Button"/>
|
||||||
|
</coding>
|
||||||
|
</valueCodeableConcept>
|
||||||
|
</extension>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation" >
|
||||||
|
<valueCode value="horizontal"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="7.2i"/>
|
||||||
|
<text value="Primary Tumour (T):"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="T1a"/>
|
||||||
|
<display value="T1a"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="ii)"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="7.2ii"/>
|
||||||
|
<text value="Regional Lymph Nodes (N):"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="N0"/>
|
||||||
|
<display value="N0"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
|
||||||
|
<valueString value="iii)"/>
|
||||||
|
</extension>
|
||||||
|
<linkId value="7.2iii"/>
|
||||||
|
<text value="Distant Metastasis (M):"/>
|
||||||
|
<answer>
|
||||||
|
<valueCoding>
|
||||||
|
<code value="M0"/>
|
||||||
|
<display value="M0"/>
|
||||||
|
</valueCoding>
|
||||||
|
</answer>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</item>
|
||||||
|
</QuestionnaireResponse>
|
Loading…
x
Reference in New Issue
Block a user