UNPKG

excel4node

Version:

Library to create Formatted Excel Files.

432 lines (380 loc) 11.3 kB
var WorkSheet = require('./WorkSheet.js'), style = require('./Style.js'), xml = require('xmlbuilder'), jszip = require('jszip'), xml = require('xmlbuilder'); fs = require('fs'); var xmlOutVars = {}; var xmlDebugVars = { pretty: true, indent: ' ',newline: '\n' }; var WorkBook = function(){ var opts = opts?opts:{}; this.opts = {}; this.opts.jszip = {}; this.opts.jszip.compression = 'DEFLATE'; if(opts.jszip){ Object.keys(opts.jszip).forEach(function(k){ this.opts.jszip[k] = opts.jszip.compression; }); }; this.defaults={ colWidth:opts.colWidth?opts.colWidth:15 }; this.styleData={ numFmts:[], fonts:[], fills:[], borders:[], cellXfs:[] }; this.worksheets=[]; this.workbook = { WorkSheets:[], workbook:{ '@xmlns:r':'http://schemas.openxmlformats.org/officeDocument/2006/relationships', '@xmlns':'http://schemas.openxmlformats.org/spreadsheetml/2006/main', bookViews:[ { workbookView:{ '@tabRatio':'600', '@windowHeight':'14980', '@windowWidth':'25600', '@xWindow':'0', '@yWindow':'1080' } } ], sheets:[] }, strings : { sst:[ { '@count':0, '@uniqueCount':0, '@xmlns':'http://schemas.openxmlformats.org/spreadsheetml/2006/main' } ] }, workbook_xml_rels:{ Relationships:[ { '@xmlns':'http://schemas.openxmlformats.org/package/2006/relationships' }, { Relationship:{ '@Id':generateRId(), '@Target':'sharedStrings.xml', '@Type':'http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings' } }, { Relationship:{ '@Id':generateRId(), '@Target':'styles.xml', '@Type':'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles' } } ] }, global_rels:{ Relationships:[ { '@xmlns':'http://schemas.openxmlformats.org/package/2006/relationships' }, { Relationship:{ '@Id':generateRId(), '@Target':'xl/workbook.xml', '@Type':'http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' } } ] }, Content_Types:{ Types:[ { '@xmlns':'http://schemas.openxmlformats.org/package/2006/content-types' }, { Default:{ '@ContentType':'application/xml', '@Extension':'xml' } }, { Default:{ '@ContentType':'application/vnd.openxmlformats-package.relationships+xml', '@Extension':'rels' } }, { Override:{ '@ContentType': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml', '@PartName':'/xl/workbook.xml' } }, { Override:{ '@ContentType':'application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml', '@PartName':'/xl/styles.xml' } }, { Override:{ '@ContentType':'application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml', '@PartName':'/xl/sharedStrings.xml' } } ] }, sharedStrings:[], debug:false } // Generate default style this.Style(); return this } WorkBook.prototype.WorkSheet = function(name, opts){ var thisWS = new WorkSheet(this); thisWS.setName(name); thisWS.setWSOpts(opts); thisWS.sheetId = this.worksheets.length + 1; this.worksheets.push(thisWS); return thisWS; } WorkBook.prototype.getStringIndex = function(val){ if(this.workbook.sharedStrings.indexOf(val) < 0){ this.workbook.sharedStrings.push(val) }; return this.workbook.sharedStrings.indexOf(val); } WorkBook.prototype.getStringFromIndex = function(val){ return this.workbook.sharedStrings[val]; } WorkBook.prototype.write = function(fileName, response){ var buffer = this.writeToBuffer(); // If `response` is an object (a node response object) if(typeof response === "object"){ response.writeHead(200,{ 'Content-Length':buffer.length, 'Content-Type':'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'Content-Disposition':'attachment; filename='+fileName, }); response.end(buffer); } // Else if `response` is a function, use it as a callback else if(typeof response === "function"){ fs.writeFile(fileName, buffer, function(err) { response(err); }); } // Else response wasn't specified else { fs.writeFile(fileName, buffer, function(err) { if (err) throw err; }); } } WorkBook.prototype.createStyleSheetXML = function(){ var thisWB = this; var data={ styleSheet:{ '@xmlns':'http://schemas.openxmlformats.org/spreadsheetml/2006/main', '@mc:Ignorable':'x14ac', '@xmlns:mc':'http://schemas.openxmlformats.org/markup-compatibility/2006', '@xmlns:x14ac':'http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac', numFmts:[], fonts:[], fills:[], borders:[], cellXfs:[] } } var items = [ 'numFmts', 'fonts', 'fills', 'borders', 'cellXfs' ]; items.forEach(function(i){ data.styleSheet[i].push({'@count':thisWB.styleData[i].length}); thisWB.styleData[i].forEach(function(d){ data.styleSheet[i].push(d.generateXMLObj()); }); }); var styleXML = xml.create(data); return styleXML.end(xmlOutVars); } WorkBook.prototype.writeToBuffer = function(){ var xlsx = new jszip(); var that = this; var wbOut = JSON.parse(JSON.stringify(this.workbook)); this.worksheets.forEach(function(sheet, i){ var sheetCount = i+1; var thisRId = generateRId(); var sheetExists = false; wbOut.workbook.sheets.forEach(function(s){ if(s.sheet['@sheetId'] == sheetCount){ sheetExists = true; } }); if(!sheetExists){ wbOut.workbook_xml_rels.Relationships.push({ Relationship:{ '@Id':thisRId, '@Target':'worksheets/sheet'+sheetCount+'.xml', '@Type':'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet' } }) wbOut.workbook.sheets.push({ sheet:{ '@name':sheet.name, '@sheetId':sheetCount, '@r:id':thisRId } }); wbOut.Content_Types.Types.push({ Override:{ '@ContentType': 'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml', '@PartName':'/xl/worksheets/sheet'+sheetCount+'.xml' } }); if(that.debug){ console.log("\n\r###### Sheet XML XML #####\n\r"); //console.log(xmlStr.end(xmlDebugVars)) }; } if(sheet.drawings){ if(that.debug){ console.log("\n\r######## Drawings found ########\n\r") } var drawingRelsXML = xml.create(sheet.drawings.rels); if(that.debug){ console.log("\n\r###### Drawings Rels XML #####\n\r"); console.log(drawingRelsXML.end(xmlDebugVars)) }; xlsx.folder("xl").folder("drawings").folder("_rels").file("drawing"+sheet.sheetId+".xml.rels",drawingRelsXML.end(xmlOutVars)); sheet.drawings.drawings.forEach(function(d){ sheet.drawings.xml['xdr:wsDr'].push(d.xml); xlsx.folder("xl").folder("media").file('image'+d.props.imageId+'.'+d.props.extension,fs.readFileSync(d.props.image)); if(that.debug){ console.log("\n\r###### Drawing image data #####\n\r"); console.log(fs.statSync(d.props.image)) }; }); var drawingXML = xml.create(sheet.drawings.xml); xlsx.folder("xl").folder("drawings").file("drawing"+sheet.sheetId+".xml",drawingXML.end(xmlOutVars)); if(that.debug){ console.log("\n\r###### Drawings XML #####\n\r"); console.log(drawingXML.end(xmlDebugVars)) }; wbOut.Content_Types.Types.push({ Override:{ '@ContentType': 'application/vnd.openxmlformats-officedocument.drawing+xml', '@PartName':'/xl/drawings/drawing'+sheet.sheetId+'.xml' } }); } if (sheet.hyperlinks) { wbOut.Content_Types.Types.push({ Override:{ '@ContentType': 'application/vnd.openxmlformats-package.relationships+xml', '@PartName':'/xl/worksheets/_rels/sheet'+sheet.sheetId+'.xml.rels' } }); if(!sheet.rels){ sheet.rels = { 'Relationships':[ { '@xmlns':'http://schemas.openxmlformats.org/package/2006/relationships' } ] } } sheet.hyperlinks.forEach(function(cr, i){ var found = false; sheet.rels.Relationships.forEach(function(r){ if(r.Relationship && r.Relationship['@Id'] == 'rId' + cr.id){ found = true; } }); if(!found){ sheet.rels.Relationships.push({ 'Relationship':{ '@Id': 'rId' + cr.id, '@Type': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink', '@Target': cr.url, '@TargetMode': 'External' } }); } }); } if(sheet.rels){ var sheetRelsXML = xml.create(sheet.rels); if(that.debug){console.log(sheetRelsXML.end(xmlDebugVars))}; xlsx.folder("xl").folder("worksheets").folder("_rels").file("sheet"+sheet.sheetId+".xml.rels",sheetRelsXML.end(xmlOutVars)); } //var wsObj = {'worksheet':JSON.parse(JSON.stringify(sheet.sheet))}; //var xmlStr = xml.create(wsObj); var xmlStr = sheet.toXML(); xlsx.folder("xl").folder("worksheets").file('sheet'+sheetCount+'.xml',xmlStr); if(that.debug){ console.log("\n\r###### SHEET "+sheetCount+" XML #####\n\r"); console.log(xmlStr) }; }); wbOut.sharedStrings.forEach(function(s){ wbOut.strings.sst.push({'si':{'t':s}}); }); wbOut.strings.sst[0]['@uniqueCount']=wbOut.sharedStrings.length; var wbXML = xml.create({workbook:JSON.parse(JSON.stringify(wbOut.workbook))}); if(this.debug){ console.log("\n\r###### WorkBook XML #####\n\r"); console.log(wbXML.end(xmlDebugVars)); }; //var styleXML = xml.create(JSON.parse(JSON.stringify(wbOut.styles))); var styleXMLStr = this.createStyleSheetXML(); //console.log(styleXMLStr); if(this.debug){ console.log("\n\r###### Style XML #####\n\r"); console.log(styleXMLStr); }; var relsXML = xml.create(wbOut.workbook_xml_rels); if(this.debug){ console.log("\n\r###### WorkBook Rels XML #####\n\r"); console.log(relsXML.end(xmlDebugVars)) }; var Content_TypesXML = xml.create(wbOut.Content_Types); if(this.debug){ console.log("\n\r###### Content Types XML #####\n\r"); console.log(Content_TypesXML.end(xmlDebugVars)) }; var globalRelsXML = xml.create(wbOut.global_rels); if(this.debug){ console.log("\n\r###### Globals Rels XML #####\n\r"); console.log(globalRelsXML.end(xmlDebugVars)) }; var stringsXML = xml.create(wbOut.strings); if(this.debug){ console.log("\n\r###### Shared Strings XML #####\n\r"); console.log(stringsXML.end(xmlDebugVars)) }; xlsx.file("[Content_Types].xml",Content_TypesXML.end(xmlOutVars)); xlsx.folder("_rels").file(".rels",globalRelsXML.end(xmlOutVars)); xlsx.folder("xl").file("sharedStrings.xml",stringsXML.end(xmlOutVars)); xlsx.folder("xl").file("styles.xml",styleXMLStr); xlsx.folder("xl").file("workbook.xml",wbXML.end(xmlOutVars)); xlsx.folder("xl").folder("_rels").file("workbook.xml.rels",relsXML.end(xmlOutVars)); delete wbOut; return xlsx.generate({type:"nodebuffer",compression:this.opts.jszip.compression}); } WorkBook.prototype.Style = style.Style; exports.WorkBook = WorkBook; function generateRId(){ var text = "R"; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; for( var i=0; i < 16; i++ ) text += possible.charAt(Math.floor(Math.random() * possible.length)); return text; }