UNPKG

phylojs

Version:

A simple typescript library for phylogenetic trees

100 lines (99 loc) 3.81 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NeXML = exports.readTreesFromNeXML = exports.readNeXML = void 0; const __1 = require("../../"); const error_1 = require("../../utils/error"); const neXMLNS = 'http://www.nexml.org/2009'; function parse(nexml) { const parser = new DOMParser(); const doc = parser.parseFromString(nexml, 'application/xml'); return doc.getElementsByTagName('tree'); } /** * Reads NeXML string and returns tree. * @param {string} nexml * @returns {Tree} */ function readNeXML(nexml) { const treeElements = parse(nexml); if (treeElements.length === 0) { throw new Error('No tree element found in NeXML.'); } const treeElement = treeElements[0]; const neXML = new NeXML(treeElement); if (!neXML.root) { throw new Error('Failed to parse the NeXML data correctly.'); } return new __1.Tree(neXML.root); } exports.readNeXML = readNeXML; /** * Reads NeXML strings and returns tree array. * @param {string} nexml * @returns {Tree[]} */ function readTreesFromNeXML(nexml) { const trees = []; const treeElements = parse(nexml); for (let i = 0; i < treeElements.length; i++) { const treeElement = treeElements[i]; const neXML = new NeXML(treeElement); if (!neXML.root) { console.log('Skipping NeXML tree: Unrooted tree.'); continue; } trees.push(new __1.Tree(neXML.root)); } return trees; } exports.readTreesFromNeXML = readTreesFromNeXML; class NeXML { constructor(treeElement) { this.thisNodeID = 0; this.processTree(treeElement); } processTree(treeElement) { const nodeElements = treeElement.getElementsByTagNameNS(neXMLNS, 'node'); const edgeElements = treeElement.getElementsByTagNameNS(neXMLNS, 'edge'); let metaElements; let metaEl; const nodesByID = {}; for (let nidx = 0; nidx < nodeElements.length; nidx++) { const nodeEl = nodeElements[nidx]; const node = new __1.Node(this.thisNodeID++); node.label = nodeEl.getAttribute('label') || undefined; nodesByID[nodeEl.getAttribute('id') || ''] = node; if (nodeEl.getAttribute('root') === 'true') this.root = node; metaElements = nodeEl.getElementsByTagNameNS(neXMLNS, 'meta'); for (let midx = 0; midx < metaElements.length; midx++) { metaEl = metaElements[midx]; if (metaEl.hasAttribute('property') && metaEl.hasAttribute('content')) { node.annotation[metaEl.getAttribute('property') || ''] = metaEl.getAttribute('content'); } } } if (!this.root) { throw new error_1.SkipTreeException('Unrooted tree.'); } for (let eidx = 0; eidx < edgeElements.length; eidx++) { const edgeEl = edgeElements[eidx]; const parent = nodesByID[edgeEl.getAttribute('source') || '']; const child = nodesByID[edgeEl.getAttribute('target') || '']; parent.addChild(child); if (edgeEl.hasAttribute('length')) { child.branchLength = parseFloat(edgeEl.getAttribute('length') || '0'); } metaElements = edgeEl.getElementsByTagNameNS(neXMLNS, 'meta'); for (let midx = 0; midx < metaElements.length; midx++) { metaEl = metaElements[midx]; if (metaEl.hasAttribute('property') && metaEl.hasAttribute('content')) { child.annotation[metaEl.getAttribute('property') || ''] = metaEl.getAttribute('content'); } } } } } exports.NeXML = NeXML;