use of org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack in project org.hl7.fhir.core by hapifhir.
the class EnableWhenEvaluator method evaluateCondition.
protected EnableWhenResult evaluateCondition(QuestionnaireItemEnableWhenComponent enableCondition, QuestionnaireItemComponent qitem, QStack qstack) {
List<Element> answerItems = findQuestionAnswers(qstack, qitem, enableCondition);
QuestionnaireItemOperator operator = enableCondition.getOperator();
if (operator == QuestionnaireItemOperator.EXISTS) {
DataType answer = enableCondition.getAnswer();
if (!(answer instanceof BooleanType)) {
throw new UnprocessableEntityException("Exists-operator requires answerBoolean");
}
return new EnableWhenResult(((BooleanType) answer).booleanValue() != answerItems.isEmpty(), enableCondition);
}
boolean result = false;
for (Element answer : answerItems) {
result = result || evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator());
}
return new EnableWhenResult(result, enableCondition);
}
use of org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack in project org.hl7.fhir.core by hapifhir.
the class QuestionnaireValidator method validateQuestionannaireResponseItems.
private void validateQuestionannaireResponseItems(ValidatorHostContext hostContext, QuestionnaireWithContext qsrc, List<QuestionnaireItemComponent> qItems, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QStack qstack) {
List<Element> items = new ArrayList<Element>();
element.getNamedChildren("item", items);
// now, sort into stacks
Map<String, List<ElementWithIndex>> map = new HashMap<String, List<ElementWithIndex>>();
int lastIndex = -1;
int counter = 0;
for (Element item : items) {
String linkId = item.getNamedChildValue("linkId");
if (rule(errors, IssueType.REQUIRED, item.line(), item.col(), stack.getLiteralPath(), !Utilities.noString(linkId), I18nConstants.QUESTIONNAIRE_QR_ITEM_NOLINKID)) {
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, misplacedItemError(qItem));
NodeStack ns = stack.push(item, counter, null, null);
validateQuestionnaireResponseItem(hostContext, qsrc, qItem, errors, item, ns, inProgress, questionnaireResponseRoot, qstack.push(qItem, item));
} else
rule(errors, IssueType.NOTFOUND, item.line(), item.col(), stack.getLiteralPath(), index > -1, I18nConstants.QUESTIONNAIRE_QR_ITEM_NOTFOUND, linkId);
} else {
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index >= lastIndex, I18nConstants.QUESTIONNAIRE_QR_ITEM_ORDER);
lastIndex = index;
// we'll treat it as not existing for the purposes of enableWhen validation
if (item.hasChildren("answer") || item.hasChildren("item")) {
List<ElementWithIndex> mapItem = map.computeIfAbsent(linkId, key -> new ArrayList<>());
mapItem.add(new ElementWithIndex(item, counter));
}
}
}
counter++;
}
// 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<ElementWithIndex> mapItem = map.get(qItem.getLinkId());
validateQuestionnaireResponseItem(hostContext, qsrc, errors, element, stack, inProgress, questionnaireResponseRoot, qItem, mapItem, qstack);
}
}
use of org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack in project org.hl7.fhir.core by hapifhir.
the class QuestionnaireValidator method validateQuestionannaireResponse.
public void validateQuestionannaireResponse(ValidatorHostContext hostContext, List<ValidationMessage> errors, Element element, NodeStack stack) throws FHIRException {
if (questionnaireMode == QuestionnaireMode.NONE) {
return;
}
Element q = element.getNamedChild("questionnaire");
String questionnaire = null;
if (q != null) {
/*
* q.getValue() is correct for R4 content, but we'll also accept the second
* option just in case we're validating raw STU3 content. Being lenient here
* isn't the end of the world since if someone is actually doing the reference
* wrong in R4 content it'll get flagged elsewhere by the validator too
*/
if (isNotBlank(q.getValue())) {
questionnaire = q.getValue();
} else if (isNotBlank(q.getChildValue("reference"))) {
questionnaire = q.getChildValue("reference");
}
}
boolean ok = questionnaireMode == QuestionnaireMode.REQUIRED ? rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE) : hint(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), questionnaire != null, I18nConstants.QUESTIONNAIRE_QR_Q_NONE);
if (ok) {
QuestionnaireWithContext qsrc = null;
if (questionnaire.startsWith("#")) {
qsrc = QuestionnaireWithContext.fromContainedResource(stack.getLiteralPath(), element, (Questionnaire) loadContainedResource(errors, stack.getLiteralPath(), element, questionnaire.substring(1), Questionnaire.class));
} else {
qsrc = QuestionnaireWithContext.fromQuestionnaire(context.fetchResource(Questionnaire.class, questionnaire));
}
if (questionnaireMode == QuestionnaireMode.REQUIRED) {
ok = rule(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire);
} else if (questionnaire.startsWith("http://example.org")) {
ok = hint(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire);
} else {
ok = warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, I18nConstants.QUESTIONNAIRE_QR_Q_NOTFOUND, questionnaire);
}
if (ok) {
boolean inProgress = "in-progress".equals(element.getNamedChildValue("status"));
validateQuestionannaireResponseItems(hostContext, qsrc, qsrc.q().getItem(), errors, element, stack, inProgress, element, new QStack(qsrc, element));
}
}
}
use of org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack in project org.hl7.fhir.core by hapifhir.
the class EnableWhenEvaluator method isQuestionEnabled.
/**
* the stack contains a set of QR items that represent the tree of the QR being validated, each tagged with the definition of the item from the Q for the QR being validated
* <p>
* the itembeing validated is in the context of the stack. For root items, the stack is empty.
* <p>
* The context Questionnaire and QuestionnaireResponse are always available
*/
public boolean isQuestionEnabled(ValidatorHostContext hostContext, QuestionnaireItemComponent qitem, QStack qstack, FHIRPathEngine engine) {
if (hasExpressionExtension(qitem)) {
String expr = getExpression(qitem);
ExpressionNode node = engine.parse(expr);
return engine.evaluateToBoolean(hostContext, qstack.a, qstack.a, qstack.a, node);
}
if (!qitem.hasEnableWhen()) {
return true;
}
List<EnableWhenResult> evaluationResults = new ArrayList<>();
for (QuestionnaireItemEnableWhenComponent enableCondition : qitem.getEnableWhen()) {
evaluationResults.add(evaluateCondition(enableCondition, qitem, qstack));
}
return checkConditionResults(evaluationResults, qitem);
}
use of org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack in project org.hl7.fhir.core by hapifhir.
the class QuestionnaireValidator method validateQuestionnaireResponseItem.
public void validateQuestionnaireResponseItem(ValidatorHostContext hostContext, QuestionnaireWithContext qsrc, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot, QuestionnaireItemComponent qItem, List<ElementWithIndex> mapItem, QStack qstack) {
boolean enabled = myEnableWhenEvaluator.isQuestionEnabled(hostContext, qItem, qstack, fpe);
if (mapItem != null) {
if (!enabled) {
for (ElementWithIndex e : mapItem) {
NodeStack ns = stack.push(e.getElement(), e.getElement().getIndex(), e.getElement().getProperty().getDefinition(), e.getElement().getProperty().getDefinition());
rule(errors, IssueType.INVALID, e.getElement().line(), e.getElement().col(), ns.getLiteralPath(), enabled, I18nConstants.QUESTIONNAIRE_QR_ITEM_NOTENABLED2, qItem.getLinkId());
}
}
// Recursively validate child items
validateQuestionnaireResponseItem(hostContext, qsrc, qItem, errors, mapItem, stack, inProgress, questionnaireResponseRoot, qstack);
} else {
// item is missing, is the question enabled?
if (enabled && qItem.getRequired()) {
String message = context.formatMessage(I18nConstants.QUESTIONNAIRE_QR_ITEM_MISSING, qItem.getLinkId());
if (inProgress) {
warning(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, message);
} else {
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, message);
}
}
}
}
Aggregations