UNPKG

@wmfs/xml-flatten2csv

Version:
131 lines (101 loc) 3.26 kB
const path = require('path') const fs = require('fs') const { mkdirp } = require('mkdirp') const eol = '\n' const pexists = path => new Promise(resolve => fs.access(path, err => resolve(!err))) const stringType = 'string' const xmlTransformToCsv = require('./xml-transform-to-csv') function error (message, code, path) { const err = new Error(message) if (code) err.code = code if (path) err.path = path return err } // error function selectPaths (headerMap) { if (!headerMap || headerMap.length === 0) { throw error('headerMap must not be empty') } return headerMap.map(fields => fields[0]) } // selectPaths function selectHeaders (headerMap) { return headerMap.map(fields => fields[1]) } // selectHeaders function selectTypes (headerMap) { return headerMap.map(fields => fields[2]) } // selectTypes function selectRequired (headerMap) { return headerMap .filter(fields => fields[3] === 'required') .map(fields => fields[0]) } // selectRequired async function openInputStream (xmlPath) { if (!xmlPath) throw error('xmlPath must be set') if (!await pexists(xmlPath)) { throw error(`File ${xmlPath} not found`, 'ENOENT', xmlPath) } const source = fs.createReadStream(xmlPath) return source } // openInputStream async function createOutputStream (csvPath) { if (!csvPath) throw error('csvPath must be set') const outputDir = path.dirname(csvPath) await mkdirp(outputDir) return fs.createWriteStream(csvPath) } // createOutputStream function closeOutputStream (outputStream) { return new Promise((resolve, reject) => outputStream.end(err => { if (err) { return reject(err) } resolve() }) ) } // closeOutputStream function writeField (outputStream, field, type) { if (!field) return const quote = (type === stringType) ? '"' : '' outputStream.write(`${quote}${field}${quote}`) } // writeField function writeHeaderLine (outputStream, headers) { const types = headers.map(() => stringType) writeLine(outputStream, headers, types) } // writeHeaderLine function writeLine (outputStream, fields, types) { outputStream.cork() const last = types.length - 1 for (let i = 0; i !== types.length; ++i) { const separator = (i !== last) ? ',' : eol writeField(outputStream, fields[i], types[i]) outputStream.write(separator) } outputStream.uncork() } // writeLine async function xmlFlatten2Csv (options) { const selectors = selectPaths(options.headerMap) const headers = selectHeaders(options.headerMap) const types = selectTypes(options.headerMap) const required = selectRequired(options.headerMap) const inputStream = await openInputStream(options.xmlPath) const outputStream = await createOutputStream(options.csvPath) writeHeaderLine(outputStream, headers) try { await xmlTransformToCsv( inputStream, options.rootXMLElement, options.pivotPath, selectors, required, { namespace: options.namespace, xmllang: options.xmllang, transform: options.transform } ) .each(fields => writeLine(outputStream, fields, types)) } finally { await closeOutputStream(outputStream) } } // xmlFlatten2csv module.exports = xmlFlatten2Csv