-
Notifications
You must be signed in to change notification settings - Fork 3
/
ofx.js
64 lines (57 loc) · 2.3 KB
/
ofx.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const XmlParser = require('xml2js/lib/parser').Parser;
function sgml2Xml(sgml) {
return sgml
.replace(/>\s+</g, '><') // remove whitespace inbetween tag close/open
.replace(/\s+</g, '<') // remove whitespace before a close tag
.replace(/>\s+/g, '>') // remove whitespace after a close tag
.replace(/<([A-Za-z0-9_]+)>([^<]+)<\/\1>/g, '<\$1>\$2') // remove closing tags if present. Example: <FOO>bar</FOO> becomes <FOO>bar for consistency, fixed in last step below.
.replace(/<([A-Z0-9_]*)+\.+([A-Z0-9_]*)>([^<]+)/g, '<\$1\$2>\$3' )
.replace(/<(\w+?)>([^<]+)/g, '<\$1>\$2</\$1>'); // Add closing tag wherever they seem to be missing: <FOO>bar becomes <FOO>bar</FOO>
}
/**
* Given an XML string, parse it and return it as a JSON-friendly Javascript object
* @param {string} xml The XML to parse
* @returns {Promise} A promise that will resolve to the parsed XML as a JSON-style object
*/
function parseXml(xml) {
const xmlParser = new XmlParser({explicitArray: false});
return new Promise((resolve, reject) => {
xmlParser.parseString(xml, (err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}
/**
* Given a string of OFX data, parse it.
* @param {string} data The OFX data to parse
* @returns {Promise} A promise that will resolve to the parsed data.
*/
function parse(data) {
// firstly, split into the header attributes and the footer sgml
const ofx = data.split('<OFX>', 2);
// firstly, parse the headers
const headerString = ofx[0].split(/\r?\n/);
let header = {};
headerString.forEach(attrs => {
const headAttr = attrs.split(/:/,2);
header[headAttr[0]] = headAttr[1];
});
// make the SGML and the XML
const content = '<OFX>' + ofx[1];
// Parse the XML/SGML portion of the file into an object
// Try as XML first, and if that fails do the SGML->XML mangling
return parseXml(content).catch(() => {
// XML parse failed.
// Do the SGML->XML Manging and try again.
return parseXml(sgml2Xml(content));
}).then(data => {
// Put the headers into the returned data
data.header = header;
return data;
});
}
module.exports.parse = parse;