Skip to content
Security
Skill

/parsing-ccda-documents

Parses C-CDA / CCD XML clinical documents to extract human-readable section narrative plus coded entries, keyed by section LOINC codes and templateIds. Use before OpenMed processing when ingesting C-CDA R2.1 documents (CCD, Discharge Summary, H&P, Consultation Note) exported

BOOST
From plugin
openmed
5.7k74 skills
Install
$ npx -y skills add maziyarpanahi/openmed --skill parsing-ccda-documents --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/parsing-ccda-documents

Context preview

The summary Claude sees to decide when to auto-load this skill.

Parses C-CDA / CCD XML clinical documents to extract human-readable section narrative plus coded entries, keyed by section LOINC codes and templateIds. Use before OpenMed processing when ingesting C-CDA R2.1 documents (CCD, Discharge Summary, H&P, Consultation Note) exported

SKILL.md

parsing-ccda-documents.SKILL.md
name: parsing-ccda-documents
description: "Parses C-CDA / CCD XML clinical documents to extract human-readable section narrative plus coded entries, keyed by section LOINC codes and templateIds. Use before OpenMed processing when ingesting C-CDA R2.1 documents (CCD, Discharge Summary, H&P, Consultation Note) exported from an EHR and you need the narrative section text de-identified and analyzed. Hand section narrative to openmed.deidentify and openmed.analyze_text; XML-aware de-identification that preserves CDA markup is available via openmed.interop.cda. Trigger keywords: C-CDA, CCD, CDA, clinical document, templateId, LOINC section, narrative block, discharge summary XML, ClinicalDocument."
license: Apache-2.0
metadata:
  project: OpenMed
  category: data-ingestion
  pairs: before
  version: "1.0"

Parsing C-CDA / CCD Documents for OpenMed

C-CDA (Consolidated Clinical Document Architecture) is the XML document standard behind Meaningful Use / ONC certification — the CCD, Discharge Summary, History & Physical, and Consultation Note you get when an EHR "exports a chart". Each document is a `ClinicalDocument` with a header (patient, authors, encounter) and a `structuredBody` of **sections**. Every section has *two* representations: a human-readable **narrative `<text>` block** and machine-readable **coded entries**. The narrative is what you feed to clinical NLP. This skill extracts it and hands it to OpenMed.

When to use

  • You receive C-CDA R2.1 / CCD documents (Direct messaging, patient portal

export, HIE) and want the free-text section narrative for de-id and NER.

  • You need to pair narrative spans with the section they came from (problems,

meds, allergies, results, plan, H&P narrative).

  • You want XML-safe de-identification that keeps the document parseable.

C-CDA structure in one minute

<ClinicalDocument xmlns="urn:hl7-org:v3">
  <recordTarget><patientRole>
    <id extension="12345" root="..."/>
    <patient><name><given>Jane</given><family>Doe</family></name>
      <birthTime value="19700115"/></patient>
  </patientRole></recordTarget>
  <component><structuredBody>
    <component><section>
      <templateId root="2.16.840.1.113883.10.20.22.2.5.1"/>   <!-- Problems -->
      <code code="11450-4" codeSystem="2.16.840.1.113883.6.1"/> <!-- LOINC -->
      <title>Problems</title>
      <text>Active problems: Type 2 diabetes, hypertension.</text>  <!-- narrative -->
      <entry>...coded SNOMED/ICD entries...</entry>
    </section></component>
  </structuredBody></component>
</ClinicalDocument>

Sections are identified by **`templateId/@root`** and by **section `code`** (LOINC). The CDA namespace is `urn:hl7-org:v3`.

Quick start

Extract section narrative by LOINC code, then hand off to OpenMed:

import openmed
from xml.etree import ElementTree as ET

NS = {"hl7": "urn:hl7-org:v3"}
SECTION_LOINC = {
    "11450-4": "problems", "10160-0": "medications", "48765-2": "allergies",
    "30954-2": "results",  "18776-5": "plan",        "10164-2": "hpi",
    "8648-8": "hospital_course", "11488-4": "consult_note",
}

root = ET.parse("ccd.xml").getroot()
for section in root.findall(".//hl7:section", NS):
    code_el = section.find("hl7:code", NS)
    loinc = code_el.get("code") if code_el is not None else None
    text_el = section.find("hl7:text", NS)
    if text_el is None:
        continue
    narrative = "".join(text_el.itertext()).strip()       # flatten narrative block
    if not narrative:
        continue

    deid = openmed.deidentify(narrative, method="replace", policy="hipaa_safe_harbor")
    result = openmed.analyze_text(deid.text, output_format="dict")
    section_name = SECTION_LOINC.get(loinc, loinc)
    # attach (section_name, result) for downstream consumers

`"".join(text_el.itertext())` flattens the narrative block (which may contain `<paragraph>`, `<list>`, `<table>`, `<content>` markup) into plain text.

XML-aware whole-document de-identification

When you need to redact PHI from the *document* (header ids, names, addresses, dates) while keeping the CDA XML valid and parseable, use the bundled adapter rather than regexing the raw XML:

from openmed.interop.cda import redact_cda, is_cda_document

if is_cda_document("ccd.xml"):
    safe_xml = redact_cda("ccd.xml")     # returns redacted XML string

`redact_cda` applies `DEFAULT_PHI_ELEMENT_MAP` (patient id hashed, name/address/ telecom null-flavored, birthTime and effectiveTime date-shifted) to header elements *and* sweeps section narrative text — operating on text nodes only so surrounding markup stays intact. Pass `text_redactor=` to plug an extra free-text callback (e.g. an `openmed.deidentify` wrapper), `date_shift_days=` for a fixed shift, and `keep_year=True` to preserve years.

Workflow

1. **Confirm it's CDA.** `is_cda_document(...)` checks for a `ClinicalDocument` root. Reject XML with `DOCTYPE`/`ENTITY` declarations (XXE risk) — the adapter does this for you. 2. **Read the header** for context: patient, author, `effectiveTime`, `documentType` (`ClinicalDocument/code` LOINC). Treat all header values as PHI. 3. **Walk sections** by `templateId` or section `code` (LOINC). Map to your section vocabulary. 4. **Flatten narrative** `<text>` with `itertext()`; preserve the section→text association for span attribution. 5. **De-identify → analyze** each narrative with OpenMed. Prefer coded `<entry>` data when it already exists; use NLP to recover what is *only* in narrative.

Hand-off to / from OpenMed

  • **To OpenMed:** flattened section narrative → `openmed.deidentify` →

`openmed.analyze_text`. Keep `(section LOINC, narrative)` so entities trace back to their section.

  • **Adapter:** `openmed.interop.cda` provides `redact_cda`, `is_cda_document`,

`PhiElementRule`, and `DEFAULT_PHI_ELEMENT_MAP` for namespace-aware, markup-preserving de-identification. It also registers an `.xml` document handler with OpenMed's multimodal int

Read more
Ships withopenmed

Local-first healthcare AI: clinical NER and HIPAA PII de-identification on hardware you control. 2,200+ medical models, 35 model-backed PII languages, and Python, MLX, Android and browser runtimes. Apache-2.0 SDK.

Get the whole plugin

Other skills on openmed.