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:
- Fax/Paper (1970s-2000s): Unstructured, manual
- PDF Email (2000s-2010s): Digital but still unstructured
- HL7 v2 MDM (1990s-present): Structured metadata, unstructured content
- CDA (2000-present): Fully structured XML documents
- 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
- Cross-Border Healthcare Directive 2011/24/EU
- GDPR Article 9 (Health Data)
- Medical Devices Regulation (MDR)
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 Note18842-5– Discharge Summary11488-4– Consultation Note28570-0– Procedure Note57133-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.