Search in sources :

Example 1 with QStack

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);
}
Also used : UnprocessableEntityException(ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException) Element(org.hl7.fhir.r5.elementmodel.Element) BooleanType(org.hl7.fhir.r5.model.BooleanType) QuestionnaireItemOperator(org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemOperator) DataType(org.hl7.fhir.r5.model.DataType)

Example 2 with QStack

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);
    }
}
Also used : QuestionnaireItemComponent(org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent) HashMap(java.util.HashMap) Element(org.hl7.fhir.r5.elementmodel.Element) ArrayList(java.util.ArrayList) NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack) List(java.util.List) ArrayList(java.util.ArrayList) ElementWithIndex(org.hl7.fhir.validation.instance.type.QuestionnaireValidator.ElementWithIndex)

Example 3 with 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));
        }
    }
}
Also used : Questionnaire(org.hl7.fhir.r5.model.Questionnaire) QuestionnaireWithContext(org.hl7.fhir.validation.instance.type.QuestionnaireValidator.QuestionnaireWithContext) Element(org.hl7.fhir.r5.elementmodel.Element) QStack(org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack)

Example 4 with QStack

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);
}
Also used : ExpressionNode(org.hl7.fhir.r5.model.ExpressionNode) ArrayList(java.util.ArrayList) QuestionnaireItemEnableWhenComponent(org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemEnableWhenComponent)

Example 5 with QStack

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);
            }
        }
    }
}
Also used : NodeStack(org.hl7.fhir.validation.instance.utils.NodeStack) ElementWithIndex(org.hl7.fhir.validation.instance.type.QuestionnaireValidator.ElementWithIndex)

Aggregations

Element (org.hl7.fhir.r5.elementmodel.Element)4 ArrayList (java.util.ArrayList)3 NodeStack (org.hl7.fhir.validation.instance.utils.NodeStack)3 List (java.util.List)2 ElementWithIndex (org.hl7.fhir.validation.instance.type.QuestionnaireValidator.ElementWithIndex)2 UnprocessableEntityException (ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException)1 HashMap (java.util.HashMap)1 BooleanType (org.hl7.fhir.r5.model.BooleanType)1 DataType (org.hl7.fhir.r5.model.DataType)1 ExpressionNode (org.hl7.fhir.r5.model.ExpressionNode)1 Questionnaire (org.hl7.fhir.r5.model.Questionnaire)1 QuestionnaireItemComponent (org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemComponent)1 QuestionnaireItemEnableWhenComponent (org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemEnableWhenComponent)1 QuestionnaireItemOperator (org.hl7.fhir.r5.model.Questionnaire.QuestionnaireItemOperator)1 QStack (org.hl7.fhir.validation.instance.EnableWhenEvaluator.QStack)1 QuestionnaireWithContext (org.hl7.fhir.validation.instance.type.QuestionnaireValidator.QuestionnaireWithContext)1