UNPKG

@stringsync/vexml

Version:

MusicXML to Vexflow

48 lines (47 loc) 1.74 kB
import JSZip from 'jszip'; import { Container } from './container'; import { NamedElement } from '../util'; const META_PATH = 'META-INF/container.xml'; const MUSICXML_MIME_TYPES = [ 'text/xml', 'application/xml', 'application/x-xml', 'application/vnd.recordare.musicxml+xml', ]; /** Represents the manifest for a compressed MusicXML file. */ export class MXL { blob; constructor(blob) { this.blob = blob; } /** * Returns the MusicXML string. * @throws {Error} when the blob cannot be handled like a MXL file. */ async getMusicXML() { const zip = await JSZip.loadAsync(this.blob); const xml = await zip.file(META_PATH)?.async('string'); if (typeof xml === 'undefined') { throw new Error(`could not extract manifest from: ${META_PATH}`); } const parser = new DOMParser(); const doc = parser.parseFromString(xml, 'application/xml'); const node = doc.getElementsByTagName('container').item(0); if (!node) { throw new Error('could not locate a <container> element'); } const container = new Container(NamedElement.of(node)); const path = container .getRootfiles() .find((rootfile) => MUSICXML_MIME_TYPES.includes(rootfile.getMediaType())) ?.getFullPath(); if (typeof path === 'undefined') { throw new Error(`could not find a <rootfile> with type: ${MUSICXML_MIME_TYPES.join(',')}`); } const musicXML = await zip.file(path)?.async('string'); if (typeof musicXML !== 'string') { throw new Error(`could not find file with path: ${path}`); } return musicXML; } }