ART-DECOR® Questionnaires
0.5.0 - ci-build

ART-DECOR® Questionnaires - Local Development build (v0.5.0) built by the FHIR (HL7® FHIR® Standard) Build Tools. See the Directory of published versions

Calculations

FHIR SDC supports automatic score and value calculation directly within a Questionnaire resource using FHIRPath expressions. This page describes the approach used in this implementation guide, illustrated by the Apgar score questionnaires.

Reference: SDC – Calculations


Overview: Extension stack for a calculated item

A calculated item (e.g., a total score) requires the following building blocks on the score item (type = #decimal):

Role Extension Purpose
Intermediate variable variable Extracts the weight of a selected answer option into a named FHIRPath variable
Computed value calculatedExpression (SDC) Sums the variables and populates the item answer
Unit label questionnaire-unit Attaches a UCUM unit (e.g. score) to the item

And on each answer option of a choice item contributing to the score:

Role Extension Purpose
Item weight itemWeight Numeric value assigned to the option, used in score computation

Step 1 – Assign weights to answer options

Each answer option of a #choice item receives an itemWeight extension with its numeric score value:

{
  "answerOption": [
    {
      "valueCoding": {
        "system": "http://loinc.org",
        "code": "LA6716-0",
        "display": "No heart rate"
      },
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/itemWeight",
          "valueDecimal": 0
        }
      ]
    },
    {
      "valueCoding": {
        "system": "http://loinc.org",
        "code": "LA6717-8",
        "display": "Under 100 beats per minute"
      },
      "extension": [
        {
          "url": "http://hl7.org/fhir/StructureDefinition/itemWeight",
          "valueDecimal": 1
        }
      ]
    }
  ]
}

Step 2 – Extract weights into variables

On the score item, one variable extension is added per contributing choice item. Use the helper function .answer.weight() to read the itemWeight value of the selected answer:

{
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "a",
        "language": "text/fhirpath",
        "expression": "%resource.item.where(linkId = '32406-1').answer.weight()"
      }
    }
  ]
}

Pattern: For each contributing item with linkId = 'X', define a variable that resolves to the weight of the currently selected answer (using %resource.item.where(linkId='X').answer.weight()), or {} (empty) if no answer has been selected yet.

Tip: Use short single-letter variable names (%a, %b, …) when there are many items to keep expressions readable.


Step 3 – Calculate the total

The calculatedExpression extension computes the final score. Simply sum the variables:

{
  "extension": [
    {
      "url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression",
      "valueExpression": {
        "description": "Total score (only when all 5 answered)",
        "language": "text/fhirpath",
        "expression": "%a + %b + %c + %d + %e"
      }
    }
  ]
}
Why does the empty semantics work automatically?

If any variable is empty ({}), the entire sum returns {} (empty). This means the score field automatically stays empty until all contributing items have been answered — no explicit iif needed.

Singleton rule (important for multi-answer items)

Arithmetic operators in FHIRPath (+, -, *, /) expect each operand to evaluate to at most one value (0..1) (or {}). If an expression returns multiple values (e.g., because an item allows repeats or uses a checkbox-style answer), the calculation may fail or behave unexpectedly because FHIRPath does not implicitly aggregate.

Recommendation: Ensure each variable resolves to a singleton. For multi-answer items, aggregate explicitly, e.g. ...answer.weight().sum(), or select a single value intentionally, e.g. ...first().


Step 4 – Mark the score item as readOnly

Because the score is calculated automatically, the item must be marked readOnly = true. This prevents the user from manually overwriting the computed value and signals to the renderer that no input control should be shown:

{
  "linkId": "9272-6",
  "text": "1-Min Apgar Total Score",
  "type": "decimal",
  "readOnly": true,
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": { "..." : "..." }
    }
  ]
}

Step 5 – Attach a unit

{
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/questionnaire-unit",
      "valueCoding": {
        "system": "http://unitsofmeasure.org",
        "code": "1",
        "display": "score"
      }
    }
  ]
}

Use a UCUM code to describe the unit of the calculated value. For dimensionless scores the code 1 is used with a human-readable display "score".


Complete example

See the Apgar score questionnaires for a full working implementation:


Using Weights via ValueSet Expansion

Instead of placing itemWeight extensions directly on each answerOption, weights can be declared centrally in a ValueSet expansion. This separates the scoring logic from the Questionnaire and enables reuse across multiple items or questionnaires.

This approach uses two FHIR 5.0 backport extensions:

Extension URL Purpose
extension-ValueSet.expansion.property http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.property Declares itemWeight as a named property on the expansion
extension-ValueSet.expansion.contains.property http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property Assigns the weight value to each concept in the expansion

Structure

1. Declare the property on the expansion:

{
  "expansion": {
    "extension": [
      {
        "url": "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.property",
        "extension": [
          {
            "url": "code",
            "valueCode": "itemWeight"
          },
          {
            "url": "uri",
            "valueUri": "http://hl7.org/fhir/concept-properties#itemWeight"
          }
        ]
      }
    ]
  }
}

2. Assign a weight to each concept:

{
  "expansion": {
    "contains": [
      {
        "system": "http://loinc.org",
        "code": "LA6716-0",
        "display": "No heart rate",
        "extension": [
          {
            "url": "http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property",
            "extension": [
              {
                "url": "code",
                "valueCode": "itemWeight"
              },
              {
                "url": "value",
                "valueDecimal": 0
              }
            ]
          }
        ]
      }
    ]
  }
}

Using .answer.weight() with a bound ValueSet

When a #choice item is bound to a ValueSet that carries weights in its expansion, the .answer.weight() FHIRPath function resolves the weight from the expansion automatically — no itemWeight on the answerOption is needed:

Choice item bound to the ValueSet:

{
  "linkId": "32406-1",
  "type": "choice",
  "answerValueSet": "http://loinc.org/vs/LL385-6"
}

On the score item:

{
  "extension": [
    {
      "url": "http://hl7.org/fhir/StructureDefinition/variable",
      "valueExpression": {
        "name": "a",
        "language": "text/fhirpath",
        "expression": "%resource.item.where(linkId = '32406-1').answer.weight()"
      }
    }
  ]
}

Example

See Apgar Pulse ValueSet (LL385-6) for a working example with weights embedded in the expansion.


Relevant Extensions

Extension URL Scope
variable http://hl7.org/fhir/StructureDefinition/variable item
calculatedExpression http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-calculatedExpression item
questionnaire-unit http://hl7.org/fhir/StructureDefinition/questionnaire-unit item
itemWeight http://hl7.org/fhir/StructureDefinition/itemWeight answerOption
extension-ValueSet.expansion.property http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.property ValueSet.expansion
extension-ValueSet.expansion.contains.property http://hl7.org/fhir/5.0/StructureDefinition/extension-ValueSet.expansion.contains.property ValueSet.expansion.contains