Skip to main content
Glama
xml.ts3.56 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { XMLBuilder, XMLParser } from 'fast-xml-parser'; import { XSI_URL } from './systems'; import type { Ccda } from './types'; const ARRAY_PATHS = [ 'ClinicalDocument.participant', 'ClinicalDocument.recordTarget', // Always arrays '.id', '.templateId', '.name', '.addr', '.telecom', '.streetAddressLine', '.author', '.effectiveTime', // Name 'name.given', 'name.suffix', 'name.prefix', // Patient 'patient.raceCode', 'patient.sdtc:raceCode', 'patient.ethnicGroupCode', 'patient.languageCommunication', // Document structure arrays 'component.structuredBody.component', 'component.structuredBody.component.section', 'component.section', 'component.observation', 'component.act', 'code.translation', 'value.translation', 'section.entry', 'entry.act', 'entry.organizer', 'entry.substanceAdministration', 'entry.observation', 'entry.encounter', 'entry.procedure', 'encounter.performer', 'encounter.participant', 'encounter.entryRelationship', 'entryRelationship.observation', 'entryRelationship.substanceAdministration', 'entryRelationship.act', 'organizer.component', 'substanceAdministration.consumable.manufacturedProduct', 'substanceAdministration.entryRelationship', 'substanceAdministration.performer', // Act paths 'act.entryRelationship', 'act.performer', // Observation paths 'observation.participant', 'observation.entryRelationship', 'observation.referenceRange', 'consumable.manufacturedProduct', 'manufacturedProduct.manufacturedMaterial', 'manufacturedProduct.manufacturerOrganization', 'manufacturedProduct.manufacturedLabeledDrug', 'manufacturedMaterial.code', 'manufacturedMaterial.lotNumberText', ]; export function convertXmlToCcda(xml: string): Ccda { const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_', parseAttributeValue: false, parseTagValue: false, isArray: (_tagName, jPath, _isLeafNode, _isAttribute) => ARRAY_PATHS.some((p) => jPath.endsWith(p)), }); const parsedData = parser.parse(xml); return parsedData.ClinicalDocument; } export function convertCcdaToXml(ccda: Ccda): string { const builder = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: true, suppressBooleanAttributes: false, suppressEmptyNode: true, }); return builder.build({ '?xml': { '@_version': '1.0', '@_encoding': 'UTF-8' }, '?xml-stylesheet': { '@_type': 'text/xsl', '@_href': 'CDA.xsl' }, ClinicalDocument: { '@_xmlns': 'urn:hl7-org:v3', '@_xmlns:xsi': XSI_URL, '@_xmlns:voc': 'urn:hl7-org:v3/voc', '@_xmlns:sdtc': 'urn:hl7-org:sdtc', ...ccda, }, }); } export function parseXml(xml: string): any { const parser = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: '@_', parseAttributeValue: false, parseTagValue: false, }); return parser.parse(xml); } export function convertToCompactXml(obj: any): string { if (!obj) { return ''; } if (typeof obj === 'string') { return obj; } const builder = new XMLBuilder({ ignoreAttributes: false, attributeNamePrefix: '@_', format: false, suppressBooleanAttributes: false, suppressEmptyNode: true, }); const xml = builder.build(obj) as string; return xml .split('\n') .map((line: string) => line.trim()) .join(''); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server