Validation fixes for QuestionnaireResponse validation

This commit is contained in:
James Agnew 2017-10-18 11:59:22 -04:00
parent 90ecaef87c
commit a265de8649
9 changed files with 3964 additions and 3836 deletions

View File

@ -180,7 +180,7 @@ public class JpaSystemProviderDstu3 extends BaseJpaSystemProviderDstu2Plus<Bundl
@OperationParam(name = "searchParam", min = 1, max = 1) String theSearchParam,
@OperationParam(name = "text", min = 1, max = 1) String theText
) {
JpaSystemProviderDstu3.validateFulltextSearchEnabled(mySearchDao);
if (isBlank(theContext)) {
throw new InvalidRequestException("Parameter 'context' must be provided");

View File

@ -2105,6 +2105,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
}
private String resolve(String uri, String ref) {
if (isBlank(uri)) {
return ref;
}
String[] up = uri.split("\\/");
String[] rp = ref.split("\\/");
if (context.getResourceNames().contains(up[up.length-2]) && context.getResourceNames().contains(rp[0])) {

View File

@ -884,4 +884,5 @@ public class FhirInstanceValidatorDstu3Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
}

View File

@ -1,17 +1,7 @@
package org.hl7.fhir.dstu3.hapi.validation;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationResult;
@ -20,38 +10,39 @@ import org.hl7.fhir.dstu3.context.IWorkerContext;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.IntegerType;
import org.hl7.fhir.dstu3.model.Questionnaire;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseStatus;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class QuestionnaireResponseValidatorDstu3Test {
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
private static FhirContext ourCtx = FhirContext.forDstu3();
public static final IdType ID_ICC_QUESTIONNAIRE_SETUP = new IdType("Questionnaire/profile");
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(QuestionnaireResponseValidatorDstu3Test.class);
private static final String CODE_ICC_SCHOOLTYPE_PT = "PT";
private static final IdType ID_VS_SCHOOLTYPE = new IdType("ValueSet/schooltype");
private static final String SYSTEMURI_ICC_SCHOOLTYPE = "http://ehealthinnovation/icc/ns/schooltype";
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
private static FhirContext ourCtx = FhirContext.forDstu3();
private FhirInstanceValidator myInstanceVal;
private FhirValidator myVal;
private IValidationSupport myValSupport;
private IWorkerContext myWorkerCtx;
@Before
@ -59,28 +50,30 @@ public class QuestionnaireResponseValidatorDstu3Test {
myValSupport = mock(IValidationSupport.class);
// new DefaultProfileValidationSupport();
myWorkerCtx = new HapiWorkerContext(ourCtx, myValSupport);
myVal = ourCtx.newValidator();
myVal.setValidateAgainstStandardSchema(false);
myVal.setValidateAgainstStandardSchematron(false);
ValidationSupportChain validationSupport = new ValidationSupportChain(myValSupport, myDefaultValidationSupport);
myInstanceVal = new FhirInstanceValidator(validationSupport);
myVal.registerValidatorModule(myInstanceVal);
}
private ValidationResult stripBindingHasNoSourceMessage(ValidationResult theErrors) {
List<SingleValidationMessage> messages = new ArrayList<SingleValidationMessage>(theErrors.getMessages());
for (int i = 0; i < messages.size(); i++) {
if (messages.get(i).getMessage().contains("has no source, so can't")) {
messages.remove(i);
i--;
}
}
}
return new ValidationResult(ourCtx, messages);
}
@Test
public void testAnswerWithWrongType() {
Questionnaire q = new Questionnaire();
@ -179,7 +172,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString("minimum required = 1, but only found 0 - QuestionnaireResponse.item"));
}
@Test
public void testItemWithNoType() {
Questionnaire q = new Questionnaire();
@ -221,6 +214,64 @@ public class QuestionnaireResponseValidatorDstu3Test {
assertThat(errors.toString(), containsString("No response found for required item link0"));
}
@Test
public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() {
/*
* Create valueset
*/
ValueSet iccSchoolTypeVs = new ValueSet();
iccSchoolTypeVs.setId(ID_VS_SCHOOLTYPE);
iccSchoolTypeVs.getCompose().getIncludeFirstRep().setSystem(SYSTEMURI_ICC_SCHOOLTYPE);
iccSchoolTypeVs
.getCompose()
.getIncludeFirstRep()
.addConcept()
.setCode(CODE_ICC_SCHOOLTYPE_PT)
.setDisplay("Part Time");
/*
* Create Questionnaire
*/
Questionnaire questionnaire = new Questionnaire();
{
questionnaire.setId(ID_ICC_QUESTIONNAIRE_SETUP);
Questionnaire.QuestionnaireItemComponent basicGroup = questionnaire.addItem();
basicGroup.setLinkId("basic");
basicGroup.setType(Questionnaire.QuestionnaireItemType.GROUP);
basicGroup
.addItem()
.setLinkId("schoolType")
.setType(Questionnaire.QuestionnaireItemType.CHOICE)
.setOptions(new Reference(ID_VS_SCHOOLTYPE))
.setRequired(true);
}
/*
* Create response
*/
QuestionnaireResponse questionnaireResponse = new QuestionnaireResponse();
questionnaireResponse.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED);
questionnaireResponse.setQuestionnaire(new Reference(ID_ICC_QUESTIONNAIRE_SETUP));
questionnaireResponse.getSubject().setReference("Patient/123");
QuestionnaireResponse.QuestionnaireResponseItemComponent basicGroup = questionnaireResponse
.addItem();
basicGroup.setLinkId("basic");
basicGroup
.addItem()
.setLinkId("schoolType")
.addAnswer()
.setValue(new Coding(SYSTEMURI_ICC_SCHOOLTYPE, CODE_ICC_SCHOOLTYPE_PT, ""));
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireResponse.getQuestionnaire().getReference()))).thenReturn(questionnaire);
when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE.getValue()))).thenReturn(iccSchoolTypeVs);
ValidationResult errors = myVal.validateWithResult(questionnaireResponse);
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString("No issues"));
}
@Test
public void testOpenchoiceAnswer() {
String questionnaireRef = "http://example.com/Questionnaire/q1";
@ -248,7 +299,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(options);
when(myValSupport.validateCode(any(FhirContext.class), eq("http://codesystems.com/system"), eq("code0"), any(String.class))).thenReturn(new CodeValidationResult(new ConceptDefinitionComponent(new CodeType("code0"))));
QuestionnaireResponse qa;
ValidationResult errors;
@ -389,19 +440,19 @@ public class QuestionnaireResponseValidatorDstu3Test {
//@formatter:off
input = input.replaceAll(
"<answer>\n" +
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"2\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>",
"<answer>\n" +
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"GGG\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>");
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"2\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>",
"<answer>\n" +
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"GGG\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>");
assertThat(input, containsString("GGG"));
//@formatter:on

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.r4.validation;
package org.hl7.fhir.r4.validation;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
@ -241,9 +241,9 @@ public class FhirInstanceValidatorR4Test {
myVal.registerValidatorModule(myInstanceVal);
mySupportedCodeSystemsForExpansion = new HashMap<String, ValueSet.ValueSetExpansionComponent>();
mySupportedCodeSystemsForExpansion = new HashMap<>();
myValidConcepts = new ArrayList<String>();
myValidConcepts = new ArrayList<>();
when(myMockSupport.expandValueSet(any(FhirContext.class), any(ConceptSetComponent.class))).thenAnswer(new Answer<ValueSetExpansionComponent>() {
@Override

View File

@ -1,57 +1,52 @@
package ca.uhn.fhir.validation;
package org.hl7.fhir.r4.validation;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.SingleValidationMessage;
import ca.uhn.fhir.validation.ValidationResult;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.r4.context.IWorkerContext;
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.r4.hapi.ctx.ValidationSupportChain;
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent;
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseStatus;
import org.hl7.fhir.r4.model.IdType;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.*;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.dstu3.context.IWorkerContext;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport.CodeValidationResult;
import org.hl7.fhir.dstu3.hapi.validation.ValidationSupportChain;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
import org.hl7.fhir.dstu3.model.CodeType;
import org.hl7.fhir.dstu3.model.Coding;
import org.hl7.fhir.dstu3.model.IntegerType;
import org.hl7.fhir.dstu3.model.Questionnaire;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent;
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseStatus;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.util.TestUtil;
public class QuestionnaireResponseValidatorR4Test {
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
private static FhirContext ourCtx = FhirContext.forDstu3();
public static final IdType ID_ICC_QUESTIONNAIRE_SETUP = new IdType("Questionnaire/profile");
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(QuestionnaireResponseValidatorR4Test.class);
private static final String CODE_ICC_SCHOOLTYPE_PT = "PT";
private static final IdType ID_VS_SCHOOLTYPE = new IdType("ValueSet/schooltype");
private static final String SYSTEMURI_ICC_SCHOOLTYPE = "http://ehealthinnovation/icc/ns/schooltype";
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
private static FhirContext ourCtx = FhirContext.forR4();
private FhirInstanceValidator myInstanceVal;
private FhirValidator myVal;
private IValidationSupport myValSupport;
private IWorkerContext myWorkerCtx;
@Before
@ -59,28 +54,30 @@ public class QuestionnaireResponseValidatorR4Test {
myValSupport = mock(IValidationSupport.class);
// new DefaultProfileValidationSupport();
myWorkerCtx = new HapiWorkerContext(ourCtx, myValSupport);
myVal = ourCtx.newValidator();
myVal.setValidateAgainstStandardSchema(false);
myVal.setValidateAgainstStandardSchematron(false);
ValidationSupportChain validationSupport = new ValidationSupportChain(myValSupport, myDefaultValidationSupport);
myInstanceVal = new FhirInstanceValidator(validationSupport);
myVal.registerValidatorModule(myInstanceVal);
}
private ValidationResult stripBindingHasNoSourceMessage(ValidationResult theErrors) {
List<SingleValidationMessage> messages = new ArrayList<SingleValidationMessage>(theErrors.getMessages());
for (int i = 0; i < messages.size(); i++) {
if (messages.get(i).getMessage().contains("has no source, so can't")) {
messages.remove(i);
i--;
}
}
}
return new ValidationResult(ourCtx, messages);
}
@Test
public void testAnswerWithWrongType() {
Questionnaire q = new Questionnaire();
@ -177,9 +174,9 @@ public class QuestionnaireResponseValidatorR4Test {
ValidationResult errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString("minimum required = 1, but only found 0 - QuestionnaireResponse.item"));
assertThat(errors.toString(), containsString("ERROR - No LinkId, so can't be validated - QuestionnaireResponse"));
}
@Test
public void testItemWithNoType() {
Questionnaire q = new Questionnaire();
@ -248,7 +245,7 @@ public class QuestionnaireResponseValidatorR4Test {
when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(options);
when(myValSupport.validateCode(any(FhirContext.class), eq("http://codesystems.com/system"), eq("code0"), any(String.class))).thenReturn(new CodeValidationResult(new ConceptDefinitionComponent(new CodeType("code0"))));
QuestionnaireResponse qa;
ValidationResult errors;
@ -375,6 +372,64 @@ public class QuestionnaireResponseValidatorR4Test {
assertThat(errors.toString(), containsString("LinkId \"link1\" not found in questionnaire"));
}
@Test
public void testValidateQuestionnaireResponseWithValueSetChoiceAnswer() {
/*
* Create valueset
*/
ValueSet iccSchoolTypeVs = new ValueSet();
iccSchoolTypeVs.setId(ID_VS_SCHOOLTYPE);
iccSchoolTypeVs.getCompose().getIncludeFirstRep().setSystem(SYSTEMURI_ICC_SCHOOLTYPE);
iccSchoolTypeVs
.getCompose()
.getIncludeFirstRep()
.addConcept()
.setCode(CODE_ICC_SCHOOLTYPE_PT)
.setDisplay("Part Time");
/*
* Create Questionnaire
*/
Questionnaire questionnaire = new Questionnaire();
{
questionnaire.setId(ID_ICC_QUESTIONNAIRE_SETUP);
Questionnaire.QuestionnaireItemComponent basicGroup = questionnaire.addItem();
basicGroup.setLinkId("basic");
basicGroup.setType(Questionnaire.QuestionnaireItemType.GROUP);
basicGroup
.addItem()
.setLinkId("schoolType")
.setType(Questionnaire.QuestionnaireItemType.CHOICE)
.setOptions(new Reference(ID_VS_SCHOOLTYPE))
.setRequired(true);
}
/*
* Create response
*/
QuestionnaireResponse questionnaireResponse = new QuestionnaireResponse();
questionnaireResponse.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED);
questionnaireResponse.setQuestionnaire(new Reference(ID_ICC_QUESTIONNAIRE_SETUP));
questionnaireResponse.getSubject().setReference("Patient/123");
QuestionnaireResponse.QuestionnaireResponseItemComponent basicGroup = questionnaireResponse
.addItem();
basicGroup.setLinkId("basic");
basicGroup
.addItem()
.setLinkId("schoolType")
.addAnswer()
.setValue(new Coding(SYSTEMURI_ICC_SCHOOLTYPE, CODE_ICC_SCHOOLTYPE_PT, ""));
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(questionnaireResponse.getQuestionnaire().getReference()))).thenReturn(questionnaire);
when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq(ID_VS_SCHOOLTYPE.getValue()))).thenReturn(iccSchoolTypeVs);
ValidationResult errors = myVal.validateWithResult(questionnaireResponse);
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString("No issues"));
}
// @Test
public void validateHealthConnexExample() throws Exception {
String input = IOUtils.toString(QuestionnaireResponseValidatorR4Test.class.getResourceAsStream("/questionnaireanswers-0f431c50ddbe4fff8e0dd6b7323625fc.xml"));
@ -389,19 +444,19 @@ public class QuestionnaireResponseValidatorR4Test {
//@formatter:off
input = input.replaceAll(
"<answer>\n" +
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"2\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>",
"<answer>\n" +
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"GGG\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>");
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"2\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>",
"<answer>\n" +
" <valueCoding>\n" +
" <system value=\"f69573b8-cb63-4d31-85a4-23ac784735ab\"/>\n" +
" <code value=\"GGG\"/>\n" +
" <display value=\"Once/twice\"/>\n" +
" </valueCoding>\n" +
" </answer>");
assertThat(input, containsString("GGG"));
//@formatter:on
@ -417,4 +472,5 @@ public class QuestionnaireResponseValidatorR4Test {
TestUtil.clearAllStaticFieldsForUnitTest();
}
}

View File

@ -1,9 +1,11 @@
package ca.uhn.fhir.validation;
package org.hl7.fhir.r4.validation;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
import org.junit.AfterClass;
import org.junit.Test;

View File

@ -114,6 +114,12 @@
These were accidentally removed in HAPI FHIR 3.0.0. Thanks to
GitHub user @CarthageKing for reporting!
</action>
<action type="fix">
The resource Profile Validator has been enhanced to not try to validate
bound fields where the binding strength is "example", and a crash was
resolved when validating QuestionnaireResponse answers with a type
of "choice" where the choice was bound to a ValueSet.
</action>
</release>
<release version="3.0.0" date="2017-09-27">
<action type="add">