phylojs
Version:
A simple typescript library for phylogenetic trees
100 lines (99 loc) • 3.81 kB
JavaScript
;
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;