diff --git a/README.md b/README.md
index 36f142699..94525c8bf 100644
--- a/README.md
+++ b/README.md
@@ -2159,6 +2159,12 @@ faster or more resilient.
#### Reading XLSX[⬆](#contents)
+Options supported when reading CSV files.
+
+| Field | Required | Type |Description |
+| ---------------- | ----------- | ----------- | ----------- |
+| ignoreNodes | N | Array | A list of node names to ignore while loading the XLSX document. Improves performance in some situations.
Available: `sheetPr`, `dimension`, `sheetViews `, `sheetFormatPr`, `cols `, `sheetData`, `autoFilter `, `mergeCells `, `rowBreaks`, `hyperlinks `, `pageMargins`, `dataValidations`, `pageSetup`, `headerFooter `, `printOptions `, `picture`, `drawing`, `sheetProtection`, `tableParts `, `conditionalFormatting`, `extLst`,|
+
```javascript
// read from a file
const workbook = new Excel.Workbook();
@@ -2176,6 +2182,16 @@ await workbook.xlsx.read(stream);
const workbook = new Excel.Workbook();
await workbook.xlsx.load(data);
// ... use workbook
+
+
+// using additional options
+const workbook = new Excel.Workbook();
+await workbook.xlsx.load(data, {
+ ignoreNodes: [
+ 'dataValidations' // ignores the workbook's Data Validations
+ ],
+});
+// ... use workbook
```
#### Writing XLSX[⬆](#contents)
diff --git a/index.d.ts b/index.d.ts
index 03f78a3c8..5979806b6 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -1457,6 +1457,13 @@ export interface JSZipGeneratorOptions {
};
}
+export interface XlsxReadOptions {
+ /**
+ * The list of XML node names to ignore while parsing an XLSX file
+ */
+ ignoreNodes: string[];
+}
+
export interface XlsxWriteOptions extends stream.xlsx.WorkbookWriterOptions {
/**
* The option passed to JsZip#generateAsync(options)
@@ -1468,19 +1475,19 @@ export interface Xlsx {
/**
* read from a file
*/
- readFile(path: string): Promise;
+ readFile(path: string, options?: Partial): Promise;
/**
* read from a stream
* @param stream
*/
- read(stream: import('stream').Stream): Promise;
+ read(stream: import('stream').Stream, options?: Partial): Promise;
/**
* load from an array buffer
* @param buffer
*/
- load(buffer: Buffer): Promise;
+ load(buffer: Buffer, options?: Partial): Promise;
/**
* write to a buffer
diff --git a/lib/xlsx/xform/sheet/worksheet-xform.js b/lib/xlsx/xform/sheet/worksheet-xform.js
index 4b36e37ba..b38930042 100644
--- a/lib/xlsx/xform/sheet/worksheet-xform.js
+++ b/lib/xlsx/xform/sheet/worksheet-xform.js
@@ -92,7 +92,10 @@ class WorkSheetXform extends BaseXform {
constructor(options) {
super();
- const {maxRows, maxCols} = options || {};
+ const {maxRows, maxCols, ignoreNodes} = options || {};
+
+ this.ignoreNodes = ignoreNodes || [];
+
this.map = {
sheetPr: new SheetPropertiesXform(),
dimension: new DimensionXform(),
@@ -221,9 +224,7 @@ class WorkSheetXform extends BaseXform {
});
}
let rIdImage =
- this.preImageId === medium.imageId
- ? drawingRelsHash[medium.imageId]
- : drawingRelsHash[drawing.rels.length];
+ this.preImageId === medium.imageId ? drawingRelsHash[medium.imageId] : drawingRelsHash[drawing.rels.length];
if (!rIdImage) {
rIdImage = nextRid(drawing.rels);
drawingRelsHash[drawing.rels.length] = rIdImage;
@@ -368,8 +369,8 @@ class WorkSheetXform extends BaseXform {
return true;
}
- this.parser = this.map[node.name];
- if (this.parser) {
+ if (this.map[node.name] && !this.ignoreNodes.includes(node.name)) {
+ this.parser = this.map[node.name];
this.parser.parseOpen(node);
}
return true;
@@ -405,11 +406,7 @@ class WorkSheetXform extends BaseXform {
false,
margins: this.map.pageMargins.model,
};
- const pageSetup = Object.assign(
- sheetProperties,
- this.map.pageSetup.model,
- this.map.printOptions.model
- );
+ const pageSetup = Object.assign(sheetProperties, this.map.pageSetup.model, this.map.printOptions.model);
const conditionalFormattings = mergeConditionalFormattings(
this.map.conditionalFormatting.model,
this.map.extLst.model && this.map.extLst.model['x14:conditionalFormattings']
diff --git a/lib/xlsx/xlsx.js b/lib/xlsx/xlsx.js
index 268d1ddb3..ff2d9a117 100644
--- a/lib/xlsx/xlsx.js
+++ b/lib/xlsx/xlsx.js
@@ -22,7 +22,7 @@ const TableXform = require('./xform/table/table-xform');
const CommentsXform = require('./xform/comment/comments-xform');
const VmlNotesXform = require('./xform/comment/vml-notes-xform');
-const theme1Xml = require('./xml/theme1.js');
+const theme1Xml = require('./xml/theme1');
function fsReadFileAsync(filename, options) {
return new Promise((resolve, reject) => {
@@ -285,9 +285,11 @@ class XLSX {
entryName = entryName.substr(1);
}
let stream;
- if (entryName.match(/xl\/media\//) ||
+ if (
+ entryName.match(/xl\/media\//) ||
// themes are not parsed as stream
- entryName.match(/xl\/theme\/([a-zA-Z0-9]+)[.]xml/)) {
+ entryName.match(/xl\/theme\/([a-zA-Z0-9]+)[.]xml/)
+ ) {
stream = new PassThrough();
stream.write(await entry.async('nodebuffer'));
} else {
@@ -597,8 +599,7 @@ class XLSX {
model.created = model.created || new Date();
model.modified = model.modified || new Date();
- model.useSharedStrings =
- options.useSharedStrings !== undefined ? options.useSharedStrings : true;
+ model.useSharedStrings = options.useSharedStrings !== undefined ? options.useSharedStrings : true;
model.useStyles = options.useStyles !== undefined ? options.useStyles : true;
// Manage the shared strings
diff --git a/spec/integration/data/.gitignore b/spec/integration/data/.gitignore
new file mode 100644
index 000000000..9c689962a
--- /dev/null
+++ b/spec/integration/data/.gitignore
@@ -0,0 +1 @@
+!*.xlsx
diff --git a/spec/integration/data/test-issue-1842.xlsx b/spec/integration/data/test-issue-1842.xlsx
new file mode 100644
index 000000000..013639766
Binary files /dev/null and b/spec/integration/data/test-issue-1842.xlsx differ
diff --git a/spec/integration/issues/issue-1842-dataValidations-memory-overload.spec.js b/spec/integration/issues/issue-1842-dataValidations-memory-overload.spec.js
new file mode 100644
index 000000000..2070b2f26
--- /dev/null
+++ b/spec/integration/issues/issue-1842-dataValidations-memory-overload.spec.js
@@ -0,0 +1,32 @@
+const {join} = require('path');
+const {readFileSync} = require('fs');
+
+const ExcelJS = verquire('exceljs');
+
+const fileName = './spec/integration/data/test-issue-1842.xlsx';
+
+describe('github issues', () => {
+ describe('issue 1842 - Memory overload when unnecessary dataValidations apply', () => {
+ it('when using readFile', async () => {
+ const wb = new ExcelJS.Workbook();
+ await wb.xlsx.readFile(fileName, {
+ ignoreNodes: ['dataValidations'],
+ });
+
+ // arriving here is success
+ expect(true).to.equal(true);
+ });
+
+ it('when loading an in memory buffer', async () => {
+ const filePath = join(process.cwd(), fileName);
+ const buffer = readFileSync(filePath);
+ const wb = new ExcelJS.Workbook();
+ await wb.xlsx.load(buffer, {
+ ignoreNodes: ['dataValidations'],
+ });
+
+ // arriving here is success
+ expect(true).to.equal(true);
+ });
+ });
+});