Skip to content

Use Liquid templates for CDA parser / interop engine #88

@jenniferjiangkells

Description

@jenniferjiangkells

Description

CDA sections are currently hard-coded dictionaries inside functions, we could look into using Jinja Liquid to load templates in - would make it more configurable too.

Configure through yaml to make it more user-friendly

Possible Implementation

healthchain/
├── interop/
│   ├── __init__.py
│   ├── engine.py              # Main interop engine
│   ├── config/
│   │   ├── __init__.py
│   │   ├── base.yaml         # Base configuration
│   │   ├── hl7v2/           # HL7v2 configs
│   │   │   ├── ADT.yaml
│   │   │   └── ORU.yaml
│   │   └── cda/             # CDA configs
│   │       ├── problem.yaml
│   │       └── medication.yaml
│   ├── templates/
│   │   ├── __init__.py
│   │   ├── hl7v2/
│   │   │   ├── ADT.liquid
│   │   │   └── ORU.liquid
│   │   └── cda/
│   │       ├── problem.liquid
│   │       └── medication.liquid
│   ├── extractors/
│   │   ├── __init__.py
│   │   ├── base.py          # Base extractor class
│   │   ├── hl7v2.py        # HL7v2 extractors
│   │   └── cda.py          # CDA extractors
│   └── connectors/          # Updated connectors using interop engine
│       ├── __init__.py
│       ├── base.py
│       ├── hl7v2.py
│       └── cda.py
from jinja2 import Environment, FileSystemLoader
import xmltodict
from pydantic import BaseModel
from typing import List, Dict

class ProblemConcept(BaseModel):
    code: str
    display_name: str
    # other fields...

class CdaAnnotator:
    def __init__(self, template_dir: str):
        self.env = Environment(loader=FileSystemLoader(template_dir))
        self.template = self.env.get_template('cda_template.xml')
        self.data = {
            'problems': [],
            'medications': [],
            'allergies': []
        }

    @classmethod
    def from_xml(cls, xml_string: str, template_dir: str):
        annotator = cls(template_dir)
        parsed_data = xmltodict.parse(xml_string)
        # Use Pydantic to validate and convert parsed data
        annotator.data = ClinicalDocument(**parsed_data['ClinicalDocument'])
        return annotator

    def add_problem(self, problem: ProblemConcept):
        # Pydantic model ensures data validity
        self.data['problems'].append(problem.model_dump())

    def export(self) -> str:
        # Render the template with the current data
        rendered_xml = self.template.render(self.data)
        # Parse the rendered XML to ensure it's valid
        parsed_xml = xmltodict.parse(rendered_xml)
        # Validate the entire structure using Pydantic if needed
        ClinicalDocument(**parsed_xml['ClinicalDocument'])
        # Convert back to XML string
        return xmltodict.unparse(parsed_xml, pretty=True)

# Usage
annotator = CdaAnnotator('path/to/templates')
problem = ProblemConcept(code='123', display_name='Hypertension')
annotator.add_problem(problem)
xml_output = annotator.export()

Metadata

Metadata

Labels

Component: Interop EngineIssue/PR that relate to the interop engine component (CDA/HL7v2/FHIR)coreIssues that build core functionality & contribute to V1.0 release

Type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions