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.
- 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
- 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
- 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
- Python 3.8 or higher
- tkinter (usually included with Python)
# Clone the repository
git clone https://github.com/ThomasNap/Fhir-testscript-generator.git
cd Fhir-testscript-generator
# Install dependencies
pip install -r requirements.txtSimply double-click start_gui.bat to launch the application.
python -m src.guiThe GUI allows you to:
- Select a resource directory containing FHIR XML files
- Configure common settings (resource path, version, bc-Child inclusion)
- Configure XIS (Serve) TestScript metadata (ID, name, description, output path)
- Configure PHR (Retrieve) TestScript metadata (ID, name, description, output path)
- Generate both TestScripts with one click
- Edit ID dropdowns via YAML configuration
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)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
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
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)
Low-level XML extraction utilities for pulling specific values from FHIR resources.
Data models representing parsed FHIR resources with all relevant metadata.
High-level orchestration that ties together parsing, selector generation, and rendering.
generate_testscript(): Creates Serve (XIS) TestScriptgenerate_retrieve_testscript(): Creates Retrieve (PHR) TestScript
Tkinter-based graphical interface for user-friendly TestScript generation.
Discriminators are FHIRPath expressions that uniquely identify a specific resource instance. Examples:
code.where(coding.where(code='118185001'))- Identifies by SNOMED codevalue.where(value='2700')- Identifies by quantity valueeffectiveDateTime.where(value='${DATE, T, D, -280}')- Identifies by date
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
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]),
...)
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
The header_choices.yaml file contains configuration for TestScript IDs:
xis_id: List of IDs for Serve (XIS/server-side) TestScriptsphr_id: List of IDs for Retrieve (PHR/client-side) TestScriptsversion: 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.0You can extend the generator by:
- Adding new discriminator types in
selector.py→resolve_discriminator() - Adding special handling for new resource types in
selector.py→generate_selectors() - Modifying rendering logic in
renderer.py
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>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 < Patient[1].id, iif(Observation[0].subject.reference.contains(Patient[0].id), Observation[0], Observation[1]), ...)"
nts:in-targets="CheckContent">
</nts:contentAsserts>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
- FHIR STU3 Only: Currently only supports FHIR STU3 (not R4/R5)
- XML Only: Does not support JSON FHIR resources
- Dutch Use Case: Optimized for Nictiz/Geboortezorg profiles
- No Validation: Does not validate generated TestScripts (use external validator)
- Ensure resources have distinguishing fields (code, value, datetime)
- Check if resources are truly identical (may need IIF selector)
- This is expected for twin scenarios
- Validators may struggle with nested IIF expressions
- Consider simplifying data if possible
- Ensure FHIR XML is well-formed
- Check namespace declarations
- Verify all required elements are present
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes with clear commit messages
- Add tests if applicable
- Submit a pull request
Apache License 2.0
See the LICENSE file for details.
- Thomas Nap - Initial development