private List<org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent>
      findAnswersByLinkId(
          List<org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent> theQuestion,
          String theLinkId) {
    Validate.notBlank(theLinkId, "theLinkId must not be blank");

    ArrayList<org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent> retVal =
        new ArrayList<QuestionnaireResponse.QuestionComponent>();
    for (org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent next : theQuestion) {
      if (theLinkId.equals(next.getLinkId())) {
        retVal.add(next);
      }
    }
    return retVal;
  }
  private void validateGroup(
      List<ValidationMessage> theErrors,
      GroupComponent theQuestGroup,
      org.hl7.fhir.instance.model.QuestionnaireResponse.GroupComponent theAnsGroup,
      LinkedList<String> thePathStack,
      QuestionnaireResponse theAnswers,
      boolean theValidateRequired) {

    for (org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent next :
        theAnsGroup.getQuestion()) {
      rule(
          theErrors,
          IssueType.INVALID,
          thePathStack,
          isNotBlank(next.getLinkId()),
          "Question found with no linkId");
    }

    Set<String> allowedQuestions = new HashSet<String>();
    for (QuestionComponent nextQuestion : theQuestGroup.getQuestion()) {
      allowedQuestions.add(nextQuestion.getLinkId());
    }

    for (int i = 0; i < theQuestGroup.getQuestion().size(); i++) {
      QuestionComponent nextQuestion = theQuestGroup.getQuestion().get(i);
      validateQuestion(
          theErrors, nextQuestion, theAnsGroup, thePathStack, theAnswers, theValidateRequired);
    }

    // Check that there are no extra answers
    for (int i = 0; i < theAnsGroup.getQuestion().size(); i++) {
      org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent nextQuestion =
          theAnsGroup.getQuestion().get(i);
      thePathStack.add("question[" + i + "]");
      rule(
          theErrors,
          IssueType.BUSINESSRULE,
          thePathStack,
          allowedQuestions.contains(nextQuestion.getLinkId()),
          "Found answer with linkId[{0}] but this ID is not allowed at this position",
          nextQuestion.getLinkId());
      thePathStack.remove();
    }

    validateGroupGroups(
        theErrors, theQuestGroup, theAnsGroup, thePathStack, theAnswers, theValidateRequired);
  }
 private void validateQuestionGroups(
     List<ValidationMessage> theErrors,
     QuestionComponent theQuestion,
     org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent theAnswerQuestion,
     LinkedList<String> thePathSpec,
     QuestionnaireResponse theAnswers,
     boolean theValidateRequired) {
   for (QuestionAnswerComponent nextAnswer : theAnswerQuestion.getAnswer()) {
     validateGroups(
         theErrors,
         theQuestion.getGroup(),
         nextAnswer.getGroup(),
         thePathSpec,
         theAnswers,
         theValidateRequired);
   }
 }
  private void validateQuestionAnswers(
      List<ValidationMessage> theErrors,
      QuestionComponent theQuestion,
      LinkedList<String> thePathStack,
      AnswerFormat type,
      org.hl7.fhir.instance.model.QuestionnaireResponse.QuestionComponent answerQuestion,
      QuestionnaireResponse theAnswers,
      boolean theValidateRequired) {

    String linkId = theQuestion.getLinkId();
    Set<Class<? extends Type>> allowedAnswerTypes = determineAllowedAnswerTypes(type);
    if (allowedAnswerTypes.isEmpty()) {
      for (QuestionAnswerComponent nextAnswer : answerQuestion.getAnswer()) {
        rule(
            theErrors,
            IssueType.BUSINESSRULE,
            thePathStack,
            ElementUtil.isEmpty(nextAnswer.getValue()),
            "Question with linkId[{0}] has no answer type but an answer was provided",
            linkId);
      }
    } else {
      rule(
          theErrors,
          IssueType.BUSINESSRULE,
          thePathStack,
          !(answerQuestion.getAnswer().size() > 1 && !theQuestion.getRepeats()),
          "Multiple answers to non repeating question with linkId[{0}]",
          linkId);
      if (theValidateRequired) {
        rule(
            theErrors,
            IssueType.BUSINESSRULE,
            thePathStack,
            !(theQuestion.getRequired() && answerQuestion.getAnswer().isEmpty()),
            "Missing answer to required question with linkId[{0}]",
            linkId);
      } else {
        hint(
            theErrors,
            IssueType.BUSINESSRULE,
            thePathStack,
            !(theQuestion.getRequired() && answerQuestion.getAnswer().isEmpty()),
            "Missing answer to required question with linkId[{0}]",
            linkId);
      }
    }

    int answerIdx = -1;
    for (QuestionAnswerComponent nextAnswer : answerQuestion.getAnswer()) {
      answerIdx++;
      try {
        thePathStack.add("answer[" + answerIdx + "]");
        Type nextValue = nextAnswer.getValue();
        if (nextValue == null) {
          continue;
        }
        if (!allowedAnswerTypes.contains(nextValue.getClass())) {
          rule(
              theErrors,
              IssueType.BUSINESSRULE,
              thePathStack,
              false,
              "Answer to question with linkId[{0}] found of type [{1}] but this is invalid for question of type [{2}]",
              linkId,
              nextValue.getClass().getSimpleName(),
              type.toCode());
          continue;
        }

        // Validate choice answers
        if (type == AnswerFormat.CHOICE || type == AnswerFormat.OPENCHOICE) {
          if (nextAnswer.getValue() instanceof StringType) {
            StringType answer = (StringType) nextAnswer.getValue();
            if (answer == null || isBlank(answer.getValueAsString())) {
              rule(
                  theErrors,
                  IssueType.BUSINESSRULE,
                  thePathStack,
                  false,
                  "Answer to question with linkId[{0}] is required but answer does not have a value",
                  linkId);
              continue;
            }
          } else {
            Coding coding = (Coding) nextAnswer.getValue();
            if (isBlank(coding.getCode())) {
              rule(
                  theErrors,
                  IssueType.BUSINESSRULE,
                  thePathStack,
                  false,
                  "Answer to question with linkId[{0}] is of type {1} but coding answer does not have a code",
                  linkId,
                  type.name());
              continue;
            }
            if (isBlank(coding.getSystem())) {
              rule(
                  theErrors,
                  IssueType.BUSINESSRULE,
                  thePathStack,
                  false,
                  "Answer to question with linkId[{0}] is of type {1} but coding answer does not have a system",
                  linkId,
                  type.name());
              continue;
            }

            String optionsRef = theQuestion.getOptions().getReference();
            if (isNotBlank(optionsRef)) {
              ValueSet valueSet = getValueSet(theAnswers, theQuestion.getOptions());
              if (valueSet == null) {
                rule(
                    theErrors,
                    IssueType.BUSINESSRULE,
                    thePathStack,
                    false,
                    "Question with linkId[{0}] has options ValueSet[{1}] but this ValueSet can not be found",
                    linkId,
                    optionsRef);
                continue;
              }

              boolean found = false;
              if (coding.getSystem().equals(valueSet.getCodeSystem().getSystem())) {
                for (ConceptDefinitionComponent next : valueSet.getCodeSystem().getConcept()) {
                  if (coding.getCode().equals(next.getCode())) {
                    found = true;
                    break;
                  }
                }
              }
              if (!found) {
                for (ConceptSetComponent nextCompose : valueSet.getCompose().getInclude()) {
                  if (coding.getSystem().equals(nextCompose.getSystem())) {
                    for (ConceptReferenceComponent next : nextCompose.getConcept()) {
                      if (coding.getCode().equals(next.getCode())) {
                        found = true;
                        break;
                      }
                    }
                  }
                  if (found) {
                    break;
                  }
                }
              }

              rule(
                  theErrors,
                  IssueType.BUSINESSRULE,
                  thePathStack,
                  found,
                  "Question with linkId[{0}] has answer with system[{1}] and code[{2}] but this is not a valid answer for ValueSet[{3}]",
                  linkId,
                  coding.getSystem(),
                  coding.getCode(),
                  optionsRef);
            }
          }
        }

      } finally {
        thePathStack.removeLast();
      }
    } // for answers
  }