CDA (Clinical Document Architecture): The XML Standard for Medical Documents

Executive Summary

Clinical Document Architecture (CDA) is an XML-based HL7 standard for exchanging structured clinical documents like discharge summaries, referral letters, and lab reports. Despite FHIR’s rise, CDA remains critical for EU healthcare document exchange, including Ireland’s eHealth infrastructure and the EU eHealth Network.

This guide covers CDA R2 structure, C-CDA profiles, .NET XML processing, and practical integration patterns for Irish healthcare systems.

What is CDA and Why It Matters

The Document Problem

Healthcare generates millions of clinical documents daily:

  • Discharge summaries (hospital → GP)
  • Referral letters (GP → specialist)
  • Lab reports (lab → ordering physician)
  • Operative notes (surgeon → medical record)
  • Medication lists (pharmacy → patient)

Challenge: How to exchange these documents in a structured, computable way?

Evolution of Solutions:

  1. Fax/Paper (1970s-2000s): Unstructured, manual
  2. PDF Email (2000s-2010s): Digital but still unstructured
  3. HL7 v2 MDM (1990s-present): Structured metadata, unstructured content
  4. CDA (2000-present): Fully structured XML documents
  5. FHIR Documents (2020s-future): JSON/XML with REST APIs

CDA’s Role Today

Still Mandatory For:

  • EU Cross-Border Healthcare (eHDSI)
  • Irish hospital discharge summaries
  • Electronic health cards (many EU countries)
  • Long-term document archival
  • Regulatory compliance (FDA, EMA)

Being Replaced By:

  • FHIR Document bundles (new projects)
  • Direct FHIR resource exchange
  • Cloud-based patient portals

CDA Document Structure

%%{init: {'theme':'base', 'themeVariables': {'primaryColor':'#E8F4F8','secondaryColor':'#F3E5F5','tertiaryColor':'#E8F5E9','primaryTextColor':'#2C3E50','fontSize':'14px'}}}%%
graph TB
    A[CDA Document]
    
    subgraph "Header contextConductionInd=true"
        B[Document Metadata]
        C[Patient]
        D[Author Physician]
        E[Custodian Hospital]
        F[Legal Authenticator]
    end
    
    subgraph "Body Structured/Narrative"
        G[Section 1
Chief Complaint] H[Section 2
History] I[Section 3
Medications] J[Section 4
Allergies] K[Section 5
Assessment] end subgraph "Each Section" L[Code LOINC] M[Title] N[Text Narrative HTML] O[Entries Coded Data] end A --> B A --> C A --> D A --> E A --> F A --> G A --> H A --> I A --> J A --> K G --> L G --> M G --> N G --> O style A fill:#B2DFDB,stroke:#4DB6AC,stroke-width:3px,color:#00695C style B fill:#E3F2FD,stroke:#90CAF9,stroke-width:2px,color:#1565C0 style C fill:#F3E5F5,stroke:#CE93D8,stroke-width:2px,color:#6A1B9A style D fill:#E8F5E9,stroke:#A5D6A7,stroke-width:2px,color:#2E7D32 style E fill:#FCE4EC,stroke:#F8BBD0,stroke-width:2px,color:#AD1457 style F fill:#FFF3E0,stroke:#FFCC80,stroke-width:2px,color:#E65100 style G fill:#E1F5FE,stroke:#81D4FA,stroke-width:2px,color:#0277BD style H fill:#E1F5FE,stroke:#81D4FA,stroke-width:2px,color:#0277BD style I fill:#E1F5FE,stroke:#81D4FA,stroke-width:2px,color:#0277BD style J fill:#E1F5FE,stroke:#81D4FA,stroke-width:2px,color:#0277BD style K fill:#E1F5FE,stroke:#81D4FA,stroke-width:2px,color:#0277BD style L fill:#DCEDC8,stroke:#AED581,stroke-width:2px,color:#558B2F style M fill:#DCEDC8,stroke:#AED581,stroke-width:2px,color:#558B2F style N fill:#DCEDC8,stroke:#AED581,stroke-width:2px,color:#558B2F style O fill:#DCEDC8,stroke:#AED581,stroke-width:2px,color:#558B2F

Sample CDA Document Structure

<?xml version="1.0" encoding="UTF-8"?>
<ClinicalDocument xmlns="urn:hl7-org:v3">
  <!-- Header -->
  <typeId root="2.16.840.1.113883.1.3" extension="POCD_HD000040"/>
  <templateId root="2.16.840.1.113883.10.20.22.1.1"/> <!-- C-CDA -->
  <id root="1.2.3.4.5.6.7.8.9.1"/>
  <code code="34133-9" displayName="Summary of Episode Note"
        codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
  <title>Hospital Discharge Summary</title>
  <effectiveTime value="20250310120000+0000"/>
  <confidentialityCode code="N" codeSystem="2.16.840.1.113883.5.25"/>
  
  <!-- Patient -->
  <recordTarget>
    <patientRole>
      <id extension="123456789012" root="2.16.372.1.2.9.1" <!-- IHI -->
          assigningAuthorityName="HSE IHI"/>
      <addr use="HP">
        <streetAddressLine>123 Main Street</streetAddressLine>
        <city>Dublin</city>
        <postalCode>D01 F5P2</postalCode>
        <country>IRL</country>
      </addr>
      <patient>
        <name>
          <given>John</given>
          <family>Doe</family>
        </name>
        <administrativeGenderCode code="M" codeSystem="2.16.840.1.113883.5.1"/>
        <birthTime value="19800115"/>
      </patient>
    </patientRole>
  </recordTarget>
  
  <!-- Author (Doctor) -->
  <author>
    <time value="20250310120000+0000"/>
    <assignedAuthor>
      <id extension="MC12345" root="2.16.372.1.2.1.1" <!-- Medical Council -->
          assigningAuthorityName="Medical Council of Ireland"/>
      <assignedPerson>
        <name>
          <prefix>Dr.</prefix>
          <given>Sarah</given>
          <family>Murphy</family>
        </name>
      </assignedPerson>
    </assignedAuthor>
  </author>
  
  <!-- Body -->
  <component>
    <structuredBody>
      <!-- Medications Section -->
      <component>
        <section>
          <templateId root="2.16.840.1.113883.10.20.22.2.1.1"/>
          <code code="10160-0" displayName="History of Medication use"
                codeSystem="2.16.840.1.113883.6.1" codeSystemName="LOINC"/>
          <title>Medications</title>
          <text>
            <table>
              <thead><tr><th>Medication</th><th>Dose</th><th>Route</th></tr></thead>
              <tbody>
                <tr><td>Aspirin</td><td>75mg</td><td>Oral</td></tr>
                <tr><td>Atorvastatin</td><td>20mg</td><td>Oral</td></tr>
              </tbody>
            </table>
          </text>
          <!-- Coded Entries -->
          <entry>
            <substanceAdministration classCode="SBADM" moodCode="EVN">
              <consumable>
                <manufacturedProduct>
                  <manufacturedMaterial>
                    <code code="R03AC02" <!-- WHO ATC -->
                          displayName="Salbutamol"
                          codeSystem="2.16.840.1.113883.6.73"/>
                  </manufacturedMaterial>
                </manufacturedProduct>
              </consumable>
            </substanceAdministration>
          </entry>
        </section>
      </component>
    </structuredBody>
  </component>
</ClinicalDocument>

.NET CDA Parsing Implementation

Using System.Xml.Linq for CDA Processing

using System.Xml.Linq;
using System.Xml.XPath;

public class CdaParser
{
    private readonly XNamespace _cdaNs = "urn:hl7-org:v3";

    public ClinicalDocument ParseCdaDocument(string xmlContent)
    {
        var doc = XDocument.Parse(xmlContent);
        var root = doc.Root;

        return new ClinicalDocument
        {
            DocumentId = ExtractDocumentId(root),
            Title = root.Element(_cdaNs + "title")?.Value,
            EffectiveTime = ExtractEffectiveTime(root),
            ConfidentialityCode = ExtractConfidentialityCode(root),
            Patient = ExtractPatient(root),
            Author = ExtractAuthor(root),
            Sections = ExtractSections(root)
        };
    }

    private string ExtractDocumentId(XElement root)
    {
        var idElement = root.Element(_cdaNs + "id");
        return $"{idElement?.Attribute("root")?.Value}.{idElement?.Attribute("extension")?.Value}";
    }

    private PatientInfo ExtractPatient(XElement root)
    {
        var recordTarget = root.Element(_cdaNs + "recordTarget");
        var patientRole = recordTarget?.Element(_cdaNs + "patientRole");
        var patient = patientRole?.Element(_cdaNs + "patient");
        var name = patient?.Element(_cdaNs + "name");

        // Extract IHI
        var idElement = patientRole?.Elements(_cdaNs + "id")
            .FirstOrDefault(e => e.Attribute("root")?.Value == "2.16.372.1.2.9.1");

        return new PatientInfo
        {
            IHI = idElement?.Attribute("extension")?.Value,
            GivenName = name?.Element(_cdaNs + "given")?.Value,
            FamilyName = name?.Element(_cdaNs + "family")?.Value,
            DateOfBirth = patient?.Element(_cdaNs + "birthTime")?.Attribute("value")?.Value,
            Gender = patient?.Element(_cdaNs + "administrativeGenderCode")?.Attribute("code")?.Value,
            Address = ExtractAddress(patientRole)
        };
    }

    private List<CdaSection> ExtractSections(XElement root)
    {
        var sections = new List<CdaSection>();
        var body = root.XPathSelectElement("//*[local-name()='structuredBody']");
        
        if (body == null) return sections;

        foreach (var component in body.Elements(_cdaNs + "component"))
        {
            var section = component.Element(_cdaNs + "section");
            if (section == null) continue;

            sections.Add(new CdaSection
            {
                TemplateId = section.Element(_cdaNs + "templateId")?.Attribute("root")?.Value,
                Code = section.Element(_cdaNs + "code")?.Attribute("code")?.Value,
                Title = section.Element(_cdaNs + "title")?.Value,
                NarrativeText = section.Element(_cdaNs + "text")?.ToString(),
                Entries = ExtractEntries(section)
            });
        }

        return sections;
    }
}

public record ClinicalDocument
{
    public string DocumentId { get; init; }
    public string Title { get; init; }
    public DateTime EffectiveTime { get; init; }
    public string ConfidentialityCode { get; init; }
    public PatientInfo Patient { get; init; }
    public AuthorInfo Author { get; init; }
    public List<CdaSection> Sections { get; init; }
}

CDA Document Generation

Creating Discharge Summary CDA

public class CdaGenerator
{
    private readonly XNamespace _ns = "urn:hl7-org:v3";

    public XDocument GenerateDischargeSummary(
        PatientInfo patient,
        AuthorInfo author,
        DischargeSummaryData data
    )
    {
        var doc = new XDocument(
            new XDeclaration("1.0", "UTF-8", null),
            new XElement(_ns + "ClinicalDocument",
                new XAttribute("xmlns", _ns),
                new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"),
                
                // Header
                CreateTypeId(),
                CreateTemplateId("2.16.840.1.113883.10.20.22.1.2"), // Discharge Summary
                CreateDocumentId(),
                CreateCode("18842-5", "Discharge Summary", "LOINC"),
                new XElement(_ns + "title", "Hospital Discharge Summary"),
                CreateEffectiveTime(DateTime.Now),
                CreateConfidentialityCode("N"),
                
                // Patient
                CreateRecordTarget(patient),
                
                // Author
                CreateAuthor(author),
                
                // Custodian (Hospital)
                CreateCustodian("Mater Misericordiae University Hospital", "Dublin"),
                
                // Body
                CreateStructuredBody(data)
            )
        );

        return doc;
    }

    private XElement CreateRecordTarget(PatientInfo patient)
    {
        return new XElement(_ns + "recordTarget",
            new XElement(_ns + "patientRole",
                // IHI Identifier
                new XElement(_ns + "id",
                    new XAttribute("extension", patient.IHI),
                    new XAttribute("root", "2.16.372.1.2.9.1"),
                    new XAttribute("assigningAuthorityName", "HSE IHI")
                ),
                // Address
                new XElement(_ns + "addr",
                    new XAttribute("use", "HP"),
                    new XElement(_ns + "streetAddressLine", patient.Address.Street),
                    new XElement(_ns + "city", patient.Address.City),
                    new XElement(_ns + "postalCode", patient.Address.Eircode),
                    new XElement(_ns + "country", "IRL")
                ),
                // Patient Demographics
                new XElement(_ns + "patient",
                    new XElement(_ns + "name",
                        new XElement(_ns + "given", patient.GivenName),
                        new XElement(_ns + "family", patient.FamilyName)
                    ),
                    new XElement(_ns + "administrativeGenderCode",
                        new XAttribute("code", patient.Gender),
                        new XAttribute("codeSystem", "2.16.840.1.113883.5.1")
                    ),
                    new XElement(_ns + "birthTime",
                        new XAttribute("value", patient.DateOfBirth.ToString("yyyyMMdd"))
                    )
                )
            )
        );
    }

    private XElement CreateStructuredBody(DischargeSummaryData data)
    {
        return new XElement(_ns + "component",
            new XElement(_ns + "structuredBody",
                // Chief Complaint Section
                CreateSection(
                    "10154-3",
                    "Chief Complaint",
                    data.ChiefComplaint,
                    "2.16.840.1.113883.10.20.22.2.13"
                ),
                // History of Present Illness
                CreateSection(
                    "10164-2",
                    "History of Present Illness",
                    data.PresentIllnessHistory,
                    "2.16.840.1.113883.10.20.22.2.33"
                ),
                // Medications Section
                CreateMedicationsSection(data.Medications),
                // Discharge Diagnosis
                CreateDiagnosesSection(data.Diagnoses),
                // Discharge Instructions
                CreateSection(
                    "8653-8",
                    "Hospital Discharge Instructions",
                    data.DischargeInstructions,
                    "2.16.840.1.113883.10.20.22.2.41"
                )
            )
        );
    }
}

Common CDA Sections (C-CDA)

Standard Section Templates

Section LOINC Code Template ID Use Case
Allergies 48765-2 2.16.840.1.113883.10.20.22.2.6.1 Drug/food allergies
Medications 10160-0 2.16.840.1.113883.10.20.22.2.1.1 Current medications
Problems 11450-4 2.16.840.1.113883.10.20.22.2.5.1 Problem list
Procedures 47519-4 2.16.840.1.113883.10.20.22.2.7.1 Surgical history
Results 30954-2 2.16.840.1.113883.10.20.22.2.3.1 Lab results
Vital Signs 8716-3 2.16.840.1.113883.10.20.22.2.4.1 BP, HR, temp
Immunizations 11369-6 2.16.840.1.113883.10.20.22.2.2.1 Vaccination history
Social History 29762-2 2.16.840.1.113883.10.20.22.2.17 Smoking, alcohol
Plan of Care 18776-5 2.16.840.1.113883.10.20.22.2.10 Treatment plan

CDA vs FHIR Documents

Technical Comparison

Feature CDA (XML) FHIR Document (JSON)
Format XML only JSON, XML
Size Verbose (large) Compact
Readability Low (XML tags) High (JSON)
Validation XSD Schema FHIR Profiles
Narrative XHTML in <text> Markdown/XHTML
Coded Data CDA Entries FHIR Resources
Extensibility Limited FHIR Extensions
Transport File exchange REST API
Mobile Support Poor Excellent
Adoption Declining Growing

When to Use CDA

Use CDA when:

  • EU Cross-Border: eHDSI mandates CDA
  • Legacy Systems: Existing CDA infrastructure
  • Long-Term Archive: 30-year document retention
  • Regulatory: FDA/EMA submissions
  • Interoperability: GP-Hospital in Ireland (current)

Avoid CDA for:

  • New mobile apps (use FHIR)
  • Real-time APIs (use FHIR REST)
  • Patient portals (use FHIR)
  • Cloud-native systems (use FHIR)

Standards and References

Global Standards Organizations

HL7 International

LOINC (Logical Observation Identifiers Names and Codes)

SNOMED CT

WHO ATC Classification

Irish Healthcare Standards

Health Service Executive (HSE)

Medical Council of Ireland

Healthlink Ireland

EU Healthcare Standards

EU eHealth Network

EU Directives

ISO Standards

Code Systems

OID Registry (HL7 assigned)

  • Ireland IHI Root: 2.16.372.1.2.9.1
  • Medical Council Ireland: 2.16.372.1.2.1.1
  • HSE Organization: 2.16.372.1.2.3.1

LOINC Common Document Codes

  • 34133-9 – Summary of Episode Note
  • 18842-5 – Discharge Summary
  • 11488-4 – Consultation Note
  • 28570-0 – Procedure Note
  • 57133-1 – Referral Note

Technical Implementation

.NET Libraries

Validation Tools

Irish Healthcare IT Resources

Related Articles in This Series

Conclusion

CDA remains essential for EU healthcare document exchange despite FHIR’s growth. Understanding CDA structure, XML processing, and EU profiles is crucial for architects working in Irish and European healthcare systems.


Discover more from C4: Container, Code, Cloud & Context

Subscribe to get the latest posts sent to your email.

Leave a comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.