Skip to content

ThomasNap/Fhir-testscript-generator

Repository files navigation

FHIR TestScript Generator

A sophisticated Python tool for automatically generating FHIR STU3 TestScript resources from collections of FHIR XML files. Designed specifically for Geboortezorg (Maternity Care) use cases, with advanced support for twin pregnancies, related resources, and complex discriminators.

Features

🎯 Core Capabilities

  • Dual TestScript Generation: Automatically generates both Serve (XIS/server-side) and Retrieve (PHR/client-side) TestScripts
  • Smart Resource Grouping: Groups resources by type and code, generating appropriate count assertions
  • Intelligent Discriminators: Automatically generates unique discriminators for resources of the same type
  • Advanced Selectors: Creates dynamic FHIRPath selectors for complex scenarios (twins, related resources)
  • GUI Application: User-friendly interface with separate configuration for XIS and PHR TestScripts

🔬 Advanced Features

  • Twin Pregnancy Support: Handles multiple children/subjects with dynamic Patient-based matching
  • Relational Selectors: Uses resource relationships (partOf, patient references) for dynamic selection
  • Date-based Sorting: Sorts resources by clinical dates (effectiveDateTime, performedPeriod) for predictable ordering
  • XML Entity Escaping: Properly escapes special characters in FHIRPath expressions
  • Multiple Discriminator Types: Supports code, value, datetime, reference-based discrimination

📋 Supported Resource Types

  • Clinical: Observation, Condition, Procedure, DiagnosticReport, ClinicalImpression
  • Administrative: Patient, EpisodeOfCare, Encounter, Organization, Practitioner
  • Care Management: CareTeam, Consent, ReferralRequest, AllergyIntolerance
  • Relationships: RelatedPerson (with role-based discrimination)
  • Maternity-Specific: Birth procedures, maternal/child observations, pregnancy conditions

Installation

Requirements

  • Python 3.8 or higher
  • tkinter (usually included with Python)

Setup

# Clone the repository
git clone https://github.com/ThomasNap/Fhir-testscript-generator.git
cd Fhir-testscript-generator

# Install dependencies
pip install -r requirements.txt

Usage

Quick Start (Windows)

Simply double-click start_gui.bat to launch the application.

GUI Mode

python -m src.gui

The GUI allows you to:

  1. Select a resource directory containing FHIR XML files
  2. Configure common settings (resource path, version, bc-Child inclusion)
  3. Configure XIS (Serve) TestScript metadata (ID, name, description, output path)
  4. Configure PHR (Retrieve) TestScript metadata (ID, name, description, output path)
  5. Generate both TestScripts with one click
  6. Edit ID dropdowns via YAML configuration

Command Line Mode

from src.generator import generate_testscript

xml = generate_testscript(
    resources_dir="path/to/resources",
    testscript_id="my-testscript-id",
    testscript_name="My TestScript Name",
    testscript_description="Description of what this tests",
    patient_id="PATIENT-ID"
)

with open("output.xml", "w", encoding="utf-8") as f:
    f.write(xml)

Architecture

Module Overview

src/parser.py

Scans directories and parses FHIR XML resources into structured Python objects.

  • Extracts resource types, IDs, codes, dates, references
  • Handles all FHIR temporal elements (effectiveDateTime, performedPeriod, etc.)
  • Parses profiles, categories, and resource relationships

src/selector.py

Generates discriminators and selectors for distinguishing between similar resources.

  • Discriminators: FHIRPath expressions that uniquely identify resources (e.g., code.where(coding.where(code='123')))
  • IIF Selectors: Complex conditional selectors for twins and related resources
  • Dynamic Matching: Uses Patient references and Birth procedures for relationship-based selection

src/renderer.py

Renders the final TestScript XML from parsed resources and generated selectors.

  • Groups resources by type and code
  • Generates count assertions
  • Creates contentAsserts with discriminators or selectors
  • Handles special cases (twins, related observations)
  • Converts Serve to Retrieve format (client-side, no content asserts)

src/extractors.py

Low-level XML extraction utilities for pulling specific values from FHIR resources.

src/model.py

Data models representing parsed FHIR resources with all relevant metadata.

src/generator.py

High-level orchestration that ties together parsing, selector generation, and rendering.

  • generate_testscript(): Creates Serve (XIS) TestScript
  • generate_retrieve_testscript(): Creates Retrieve (PHR) TestScript

src/gui.py

Tkinter-based graphical interface for user-friendly TestScript generation.

Key Concepts

Discriminators

Discriminators are FHIRPath expressions that uniquely identify a specific resource instance. Examples:

  • code.where(coding.where(code='118185001')) - Identifies by SNOMED code
  • value.where(value='2700') - Identifies by quantity value
  • effectiveDateTime.where(value='${DATE, T, D, -280}') - Identifies by date

IIF Selectors

For identical resources (e.g., twin observations), IIF selectors use relational matching:

iif(Patient[0].id < Patient[1].id, 
    iif(Observation[0].subject.reference.contains(Patient[0].id), 
        Observation[0], 
        Observation[1]),
    iif(Observation[0].subject.reference.contains(Patient[1].id), 
        Observation[1], 
        Observation[0]))

This ensures:

  • Deterministic ordering: Patients sorted by ID
  • Dynamic matching: Observations matched to correct Patient via subject.reference
  • No hardcoded values: Works with any bundle composition

Birth Procedure Matching

For child-specific procedures (e.g., Vitamin K administration), matching uses Birth procedures:

iif(Birth[0].id < Birth[1].id,
    iif(Procedure[0].partOf.reference.contains(Birth[0].id),
        Procedure[0],
        Procedure[1]),
    ...)

Serve vs Retrieve TestScripts

The generator creates two complementary TestScripts:

Serve (XIS) - Server-side:

  • Scenario: server
  • Test names: #-Serve[ResourceType]
  • Includes: medmij/test.xis.successfulSearch
  • Contains <nts:contentAsserts> with discriminators/selectors

Retrieve (PHR) - Client-side:

  • Scenario: client
  • Test names: #-Retrieve[ResourceType]
  • Includes: medmij/test.phr.successfulsearch
  • No content asserts (only count assertions and code checks)
  • Same test order as Serve for consistency

Configuration

Header Templates

The header_choices.yaml file contains configuration for TestScript IDs:

  • xis_id: List of IDs for Serve (XIS/server-side) TestScripts
  • phr_id: List of IDs for Retrieve (PHR/client-side) TestScripts
  • version: FHIR version identifiers (e.g., stu3-3.0)

Example:

xis_id:
- gbz-fhir3-0-2-ikz-xis-4-1
- gbz-fhir3-0-2-ikz-xis-4-2
phr_id:
- gbz-fhir3-0-2-ikz-phr-4-1
- gbz-fhir3-0-2-ikz-phr-4-2
version:
- stu3-3.0

Customization

You can extend the generator by:

  1. Adding new discriminator types in selector.pyresolve_discriminator()
  2. Adding special handling for new resource types in selector.pygenerate_selectors()
  3. Modifying rendering logic in renderer.py

Examples

Example 1: Simple Condition Test

Input: Single Condition resource with code 118185001 (Pregnancy)

Output:

<test id="Condition">
  <name value="Condition"/>
  <description value="Test Server query operation for Condition"/>
  <nts:include value="medmij/test.xis.successfulSearch" scope="common">
    <nts:with-parameter name="resource" value="Condition"/>
  </nts:include>
  <nts:include value="assert.response.numResources" scope="common">
    <nts:with-parameter name="resource" value="Condition"/>
    <nts:with-parameter name="count" value="1"/>
  </nts:include>
  <nts:contentAsserts href="zib-Pregnancy-118185001.xml" nts:in-targets="CheckContent">
    <nts:discriminator>code.where(coding.where(code=118185001))</nts:discriminator>
  </nts:contentAsserts>
</test>

Example 2: Twin Observations

Input: Two birth weight observations for twins

Output uses IIF selector based on Patient references:

<nts:contentAsserts href="child1-weight.xml" 
  selector="iif(Patient[0].id &lt; Patient[1].id, iif(Observation[0].subject.reference.contains(Patient[0].id), Observation[0], Observation[1]), ...)"
  nts:in-targets="CheckContent">
</nts:contentAsserts>

Development

Project Structure

fhir-testscript-generator/
├── src/
│   ├── __init__.py
│   ├── analyzer.py      # Resource analysis utilities
│   ├── extractors.py    # XML extraction functions
│   ├── generator.py     # Main orchestration
│   ├── gui.py          # Tkinter GUI
│   ├── model.py        # Data models
│   ├── parser.py       # FHIR XML parsing
│   ├── renderer.py     # TestScript XML rendering
│   └── selector.py     # Discriminator/selector generation
├── header_choices.yaml # TestScript header templates
├── requirements.txt    # Python dependencies
├── README.md          # This file
└── pyproject.toml    # Project metadata

Known Limitations

  1. FHIR STU3 Only: Currently only supports FHIR STU3 (not R4/R5)
  2. XML Only: Does not support JSON FHIR resources
  3. Dutch Use Case: Optimized for Nictiz/Geboortezorg profiles
  4. No Validation: Does not validate generated TestScripts (use external validator)

Troubleshooting

"No discriminator found"

  • Ensure resources have distinguishing fields (code, value, datetime)
  • Check if resources are truly identical (may need IIF selector)

"Selector too complex"

  • This is expected for twin scenarios
  • Validators may struggle with nested IIF expressions
  • Consider simplifying data if possible

"XML parsing errors"

  • Ensure FHIR XML is well-formed
  • Check namespace declarations
  • Verify all required elements are present

Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes with clear commit messages
  4. Add tests if applicable
  5. Submit a pull request

License

Apache License 2.0

See the LICENSE file for details.

Authors

  • Thomas Nap - Initial development

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published