officeparser 2.3.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/officeParser.js CHANGED
@@ -1,583 +1,568 @@
1
- const decompress = require('decompress');
2
- const xml2js = require('xml2js')
3
- const fs = require('fs')
4
- const util = require('util');
5
- const rimraf = require('rimraf');
6
-
7
- // #region textFetchFromWord
8
-
9
- var myTextWord = [];
10
- var decompressLocation = "officeDist";
11
- var outputToConsoleWhenRequired = true; // Default is set to true to let the user identify source of an error in node terminal
12
-
13
- async function scanForTextWord(result) {
14
- if (Array.isArray(result)) {
15
- for (var i = 0; i < result.length; i++) {
16
- if (typeof(result[i]) == "string" && result[i] != "") {
17
- await myTextWord.push(result[i]);
18
- }
19
- else {
20
- await scanForTextWord(result[i]);
21
- }
22
- }
23
- return;
24
- }
25
- else if (typeof(result) == "object") {
26
- for (var property in result) {
27
- if (result.hasOwnProperty(property)) {
28
- if (typeof(result[property]) == "string") {
29
- if ((property == "w:t" || property == "_") && result[property] != "") {
30
- await myTextWord.push(result[property]);
31
- }
32
- }
33
- else {
34
- await scanForTextWord(result[property]);
35
- }
36
- }
37
- }
38
- return;
39
- }
40
- }
41
-
42
- var parseWord = async function (filename, callback, deleteOfficeDist = true) {
43
- if (validateFileExtension(filename, ["docx"])) {
44
- try {
45
- decompress(filename, decompressLocation).then(files => {
46
- myTextWord = [];
47
- if (fs.existsSync(decompressLocation + "/word/document.xml")) {
48
- fs.readFile(decompressLocation + '/word/document.xml', 'utf8', function (err,data) {
49
- if (err) {
50
- if (outputToConsoleWhenRequired) console.log(err);
51
- return callback(undefined, err);
52
- }
53
- xml2js.parseString(data, async function (err, result) {
54
- await scanForTextWord(result);
55
-
56
- callback(myTextWord.join(" "), undefined);
57
- if (deleteOfficeDist == true) {
58
- rimraf(decompressLocation, function () {});
59
- }
60
- });
61
- });
62
- }
63
- else {
64
- if (deleteOfficeDist == true) {
65
- rimraf(decompressLocation, function () {});
66
- }
67
- }
68
- })
69
- .catch(function (err) {
70
- if (outputToConsoleWhenRequired) console.log(err);
71
- return callback(undefined, err);
72
- });
73
- }
74
- catch(err) {
75
- if (outputToConsoleWhenRequired) console.log(err);
76
- return callback(undefined, err);
77
- }
78
- }
79
- }
80
-
81
- // #endregion textFetchFromWord
82
-
83
-
84
-
85
- // #region textFetchFromPowerPoint
86
-
87
- var myTextPowerPoint = [];
88
-
89
- async function scanForTextPowerPoint(result) {
90
- if (Array.isArray(result)) {
91
- for (var i = 0; i < result.length; i++) {
92
- if (typeof(result[i]) == "string" && result[i] != "") {
93
- await myTextPowerPoint.push(result[i]);
94
- }
95
- else {
96
- await scanForTextPowerPoint(result[i]);
97
- }
98
- }
99
- return;
100
- }
101
- else if (typeof(result) == "object") {
102
- for (var property in result) {
103
- if (result.hasOwnProperty(property)) {
104
- if (typeof(result[property]) == "string") {
105
- if ((property == "a:t" || property == "_") && result[property] != "") {
106
- await myTextPowerPoint.push(result[property]);
107
- }
108
- }
109
- else if (typeof(result[property][0]) == "string") {
110
- if ((property == "a:t" || property == "_") && result[property] != "") {
111
- await myTextPowerPoint.push(result[property]);
112
- }
113
- }
114
- else {
115
- await scanForTextPowerPoint(result[property]);
116
- }
117
- }
118
- }
119
- return;
120
- }
121
- }
122
-
123
- var parsePowerPoint = function (filename, callback, deleteOfficeDist = true) {
124
- if (validateFileExtension(filename, ["pptx"])) {
125
- try {
126
- decompress(filename, decompressLocation).then(async files => {
127
- myTextPowerPoint = [];
128
-
129
- if (fs.existsSync(decompressLocation + '/ppt/slides')) {
130
- var slidesNum = await fs.readdirSync(decompressLocation + '/ppt/slides').length;
131
-
132
- for (var i = 0; i < slidesNum - 1; i++) {
133
- var parser = new xml2js.Parser();
134
-
135
- var myData = await util.promisify(fs.readFile)(`${decompressLocation}/ppt/slides/slide${i + 1}.xml`, 'utf8');
136
- var result = await util.promisify(parser.parseString.bind(parser))(myData);
137
- await scanForTextPowerPoint(result);
138
- }
139
-
140
- if (fs.existsSync(decompressLocation + '/ppt/notesSlides')) {
141
- var notesSlidesNum = await fs.readdirSync(decompressLocation + '/ppt/notesSlides').length;
142
- for (var i = 0; i < notesSlidesNum - 1; i++) {
143
- var parser = new xml2js.Parser();
144
-
145
- var myData = await util.promisify(fs.readFile)(`${decompressLocation}/ppt/notesSlides/notesSlide${i + 1}.xml`, 'utf8');
146
- var result = await util.promisify(parser.parseString.bind(parser))(myData);
147
- await scanForTextPowerPoint(result);
148
- }
149
- }
150
-
151
- callback(myTextPowerPoint.join(" "), undefined);
152
-
153
- if (deleteOfficeDist == true) {
154
- rimraf(decompressLocation, function () {});
155
- }
156
- }
157
- else {
158
- if (deleteOfficeDist == true) {
159
- rimraf(decompressLocation, function () {});
160
- }
161
- }
162
- })
163
- .catch(function (err) {
164
- if (outputToConsoleWhenRequired) console.log(err);
165
- return callback(undefined, err);
166
- });
167
- }
168
- catch (err) {
169
- if (outputToConsoleWhenRequired) console.log(err);
170
- return callback(undefined, err);
171
- }
172
- }
173
- }
174
-
175
- // #endregion textFetchFromPowerPoint
176
-
177
-
178
- // #region textFetchFromExcel
179
-
180
- var myTextExcel = [];
181
-
182
- async function scanForTextExcelDrawing(result) {
183
- if (Array.isArray(result)) {
184
- for (var i = 0; i < result.length; i++) {
185
- if (typeof(result[i]) == "string" && result[i] != "") {
186
- await myTextExcel.push(result[i]);
187
- }
188
- else {
189
- await scanForTextExcelDrawing(result[i]);
190
- }
191
- }
192
- return;
193
- }
194
- else if (typeof(result) == "object") {
195
- for (var property in result) {
196
- if (result.hasOwnProperty(property)) {
197
- if (typeof(result[property]) == "string") {
198
- if ((property == "a:t" || property == "_") && result[property] != "") {
199
- await myTextExcel.push(result[property]);
200
- }
201
- }
202
- else if (typeof(result[property][0]) == "string") {
203
- if ((property == "a:t" || property == "_") && result[property] != "") {
204
- await myTextExcel.push(result[property]);
205
- }
206
- }
207
- else {
208
- await scanForTextExcelDrawing(result[property]);
209
- }
210
- }
211
- }
212
- return;
213
- }
214
- }
215
-
216
-
217
- async function scanForTextExcelSharedStrings(result) {
218
- if (Array.isArray(result)) {
219
- for (var i = 0; i < result.length; i++) {
220
- if (typeof(result[i]) == "string" && result[i] != "") {
221
- await myTextExcel.push(result[i]);
222
- }
223
- else {
224
- await scanForTextExcelSharedStrings(result[i]);
225
- }
226
- }
227
- return;
228
- }
229
- else if(typeof(result) == "object") {
230
- for (var property in result) {
231
- if (result.hasOwnProperty(property)) {
232
- if (typeof(result[property]) == "string") {
233
- if ((property == "t" || property == "_") && result[property] != "") {
234
- await myTextExcel.push(result[property]);
235
- }
236
- }
237
- else if (typeof(result[property][0]) == "string") {
238
- if ((property == "t" || property == "_") && result[property] != "") {
239
- await myTextExcel.push(result[property]);
240
- }
241
- }
242
- else {
243
- await scanForTextExcelSharedStrings(result[property]);
244
- }
245
- }
246
- }
247
- return;
248
- }
249
- }
250
-
251
- async function scanForTextExcelWorkSheet(result) {
252
- if (Array.isArray(result)) {
253
- for (var i = 0; i < result.length; i++) {
254
- if (result[i]["v"]) {
255
- if ((result[i]["$"]["t"] != "s")) {
256
- await myTextExcel.push(result[i]["v"][0]);
257
- }
258
- }
259
- else {
260
- await scanForTextExcelWorkSheet(result[i]);
261
- }
262
- }
263
- return;
264
- }
265
- else if(typeof(result) == "object") {
266
- for (var property in result) {
267
- if (result.hasOwnProperty(property)) {
268
- if (result[property]["v"]) {
269
- if ((result[property]["$"]["t"] == "s")) {
270
- await myTextExcel.push(result[property]["v"][0]);
271
- }
272
- }
273
- else {
274
- await scanForTextExcelWorkSheet(result[property]);
275
- }
276
- }
277
- }
278
- return;
279
- }
280
- }
281
-
282
- var parseExcel = function (filename, callback, deleteOfficeDist = true) {
283
- if (validateFileExtension(filename, ["xlsx"])) {
284
- try {
285
- decompress(filename, decompressLocation).then(async files => {
286
- myTextExcel = [];
287
-
288
-
289
- if (fs.existsSync(decompressLocation + '/xl/worksheets')) {
290
- var workSheetsNum = await fs.readdirSync(decompressLocation + '/xl/worksheets').length;
291
- for (var i = 0; i < workSheetsNum - 1; i++) {
292
- var parser = new xml2js.Parser();
293
-
294
- var myData = await util.promisify(fs.readFile)(`${decompressLocation}/xl/worksheets/sheet${i + 1}.xml`, 'utf8');
295
- var result = await util.promisify(parser.parseString.bind(parser))(myData);
296
- await scanForTextExcelWorkSheet(result);
297
- }
298
-
299
- if (fs.existsSync(decompressLocation + '/xl/sharedStrings.xml')) {
300
- var parser = new xml2js.Parser();
301
-
302
- var myData = await util.promisify(fs.readFile)(`${decompressLocation}/xl/sharedStrings.xml`, 'utf8');
303
- var result = await util.promisify(parser.parseString.bind(parser))(myData);
304
- await scanForTextExcelSharedStrings(result);
305
- }
306
-
307
- if (fs.existsSync(decompressLocation + '/xl/drawings')) {
308
- var drawingsNum = await fs.readdirSync(decompressLocation + '/xl/drawings').length;
309
-
310
- for (var i = 0; i < drawingsNum; i++) {
311
- var parser = new xml2js.Parser();
312
-
313
- var myData = await util.promisify(fs.readFile)(`${decompressLocation}/xl/drawings/drawing${i + 1}.xml`, 'utf8');
314
- var result = await util.promisify(parser.parseString.bind(parser))(myData);
315
- await scanForTextExcelDrawing(result);
316
- }
317
- }
318
-
319
- callback(myTextExcel.join(" "), undefined);
320
-
321
- if (deleteOfficeDist == true) {
322
- rimraf(decompressLocation, function () {});
323
- }
324
- }
325
- else {
326
- if (deleteOfficeDist == true) {
327
- rimraf(decompressLocation, function () {});
328
- }
329
- }
330
- })
331
- .catch(function (err) {
332
- if (outputToConsoleWhenRequired) console.log(err);
333
- return callback(undefined, err);
334
- });
335
- }
336
- catch (err) {
337
- if (outputToConsoleWhenRequired) console.log(err);
338
- return callback(undefined, err);
339
- }
340
- }
341
- }
342
-
343
- // #endregion textFetchFromExcel
344
-
345
-
346
-
347
- // #region textFetchFromOpenOffice
348
-
349
- var myTextOpenOffice = [];
350
-
351
- async function scanForTextOpenOffice(result) {
352
- if (Array.isArray(result)) {
353
- for (var i = 0; i < result.length; i++) {
354
- if (typeof(result[i]) == "string" && result[i] != "") {
355
- await myTextOpenOffice.push(result[i]);
356
- }
357
- else {
358
- await scanForTextOpenOffice(result[i]);
359
- }
360
- }
361
- return;
362
- }
363
- else if (typeof(result) == "object") {
364
- for (var property in result) {
365
- if (result.hasOwnProperty(property)) {
366
- if (typeof(result[property]) == "string") {
367
- if (result[property] != "") {
368
- await myTextOpenOffice.push(result[property]);
369
- }
370
- }
371
- else {
372
- await scanForTextOpenOffice(result[property]);
373
- }
374
-
375
- }
376
- }
377
- return;
378
- }
379
- }
380
-
381
- var parseOpenOffice = async function (filename, callback, deleteOfficeDist = true) {
382
- if (validateFileExtension(filename, ["odt", "odp", "ods"])) {
383
- try {
384
- decompress(filename, decompressLocation).then(files => {
385
- myTextOpenOffice = [];
386
- if (fs.existsSync(decompressLocation + "/content.xml")) {
387
- fs.readFile(decompressLocation + '/content.xml', 'utf8', function (err,data) {
388
- if (err) {
389
- if (outputToConsoleWhenRequired) console.log(err);
390
- return callback(undefined, err);
391
- }
392
-
393
- xml2js.parseString(data, {"ignoreAttrs": true}, async function (err, result) {
394
- await scanForTextOpenOffice(result);
395
-
396
- callback(myTextOpenOffice.join(" "), undefined);
397
- if (deleteOfficeDist == true) {
398
- rimraf(decompressLocation, function () {});
399
- }
400
- });
401
- });
402
- }
403
- else {
404
- if (deleteOfficeDist == true) {
405
- rimraf(decompressLocation, function () {});
406
- }
407
- }
408
- })
409
- .catch(function (err) {
410
- if (outputToConsoleWhenRequired) console.log(err);
411
- return callback(undefined, err);
412
- });
413
- }
414
- catch (err) {
415
- if (outputToConsoleWhenRequired) console.log(err);
416
- return callback(undefined, err);
417
- }
418
- }
419
- }
420
-
421
- // #endregion textFetchFromOpenOffice
422
-
423
-
424
-
425
-
426
- // #region validate file names
427
-
428
- /**
429
- * Legacy method to check whether file functions called are indeed applicable with files provided
430
- * @param {*} filename file path
431
- * @param {*} extension extensions of supported files
432
- */
433
- function validateFileExtension(filename, extension) {
434
- for (var extensionIterator = 0; extensionIterator < extension.length; extensionIterator++) {
435
- if (extension[extensionIterator] == filename.split(".").pop().toLowerCase()) {
436
- return true;
437
- }
438
- }
439
- console.log(`[OfficeParser]: Sorry, we currently support docx, pptx, xlsx, odt, odp, ods files only. Make sure you pass appropriate file with the parsing functions.`);
440
- return false;
441
- }
442
-
443
- // #endregion validate file names
444
-
445
- // #region parse office
446
-
447
- function parseOffice(filename, callback, deleteOfficeDist = true) {
448
- var extension = filename.split(".").pop().toLowerCase();
449
-
450
- if (extension == "docx") {
451
- parseWord(filename, function (data) {
452
- callback(data);
453
- }, deleteOfficeDist);
454
- }
455
- else if (extension == "pptx") {
456
- parsePowerPoint(filename, function (data) {
457
- callback(data);
458
- }, deleteOfficeDist);
459
- }
460
- else if (extension == "xlsx") {
461
- parseExcel(filename, function (data) {
462
- callback(data);
463
- }, deleteOfficeDist);
464
- }
465
- else if (extension == "odt" || extension == "odp" || extension == "ods") {
466
- parseOpenOffice(filename, function (data) {
467
- callback(data);
468
- }, deleteOfficeDist);
469
- }
470
- else {
471
- var errMessage = `[OfficeParser]: Sorry, we currently support docx, pptx, xlsx, odt, odp, ods files only. Create a ticket in Issues on github to add support for ${extension} files. Stay tuned for further updates.`;
472
- if (outputToConsoleWhenRequired) console.log(errMessage);
473
- return callback(undefined, errMessage);
474
- }
475
-
476
- }
477
-
478
- // #endregion parse office
479
-
480
-
481
- // #region setDecompressionLocation
482
- function setDecompressionLocation(newLocation) {
483
- if (newLocation != undefined) {
484
- decompressLocation = newLocation + "/officeDist";
485
- }
486
- else {
487
- decompressLocation = "officeDist";
488
- }
489
- }
490
-
491
- // #endregion setDecompressionLocation
492
-
493
- // #region setConsoleOutput
494
- function enableConsoleOutput() {
495
- outputToConsoleWhenRequired = true;
496
- }
497
-
498
- function disableConsoleOutput() {
499
- outputToConsoleWhenRequired = false;
500
- }
501
-
502
- // #endregion setConsoleOutput
503
-
504
- // #region Async Versions
505
- var parseWordAsync = function (filename, deleteOfficeDist = true) {
506
- return new Promise((resolve, reject) => {
507
- try {
508
- parseWord(filename, function (data, err) {
509
- if (err) return reject(err);
510
- return resolve(data);
511
- },deleteOfficeDist);
512
- } catch (error) {
513
- return reject(error);
514
- }
515
- })
516
- }
517
-
518
- var parsePowerPointAsync = function (filename, deleteOfficeDist = true) {
519
- return new Promise((resolve, reject) => {
520
- try {
521
- parsePowerPoint(filename, function (data, err) {
522
- if (err) return reject(err);
523
- return resolve(data);
524
- },deleteOfficeDist);
525
- } catch (error) {
526
- return reject(error);
527
- }
528
- })
529
- }
530
-
531
- var parseExcelAsync = function (filename, deleteOfficeDist = true) {
532
- return new Promise((resolve, reject) => {
533
- try {
534
- parseExcel(filename, function (data, err) {
535
- if (err) return reject(err);
536
- return resolve(data);
537
- },deleteOfficeDist);
538
- } catch (error) {
539
- return reject(error);
540
- }
541
- })
542
- }
543
-
544
- var parseOpenOfficeAsync = function (filename, deleteOfficeDist = true) {
545
- return new Promise((resolve, reject) => {
546
- try {
547
- parseOpenOffice(filename, function (data, err) {
548
- if (err) return reject(err);
549
- return resolve(data);
550
- },deleteOfficeDist);
551
- } catch (error) {
552
- return reject(error);
553
- }
554
- })
555
- }
556
-
557
- var parseOfficeAsync = function (filename, deleteOfficeDist = true) {
558
- return new Promise((resolve, reject) => {
559
- try {
560
- parseOffice(filename, function (data, err) {
561
- if (err) return reject(err);
562
- return resolve(data);
563
- },deleteOfficeDist);
564
- } catch (error) {
565
- return reject(error);
566
- }
567
- })
568
- }
569
- // #endregion Async Versions
570
-
571
- module.exports.parseWord = parseWord;
572
- module.exports.parsePowerPoint = parsePowerPoint;
573
- module.exports.parseExcel = parseExcel;
574
- module.exports.parseOpenOffice = parseOpenOffice;
575
- module.exports.parseOffice = parseOffice;
576
- module.exports.parseWordAsync = parseWordAsync;
577
- module.exports.parsePowerPointAsync = parsePowerPointAsync;
578
- module.exports.parseExcelAsync = parseExcelAsync;
579
- module.exports.parseOpenOfficeAsync = parseOpenOfficeAsync;
580
- module.exports.parseOfficeAsync = parseOfficeAsync;
581
- module.exports.setDecompressionLocation = setDecompressionLocation;
582
- module.exports.enableConsoleOutput = enableConsoleOutput;
583
- module.exports.disableConsoleOutput = disableConsoleOutput;
1
+ const decompress = require('decompress');
2
+ const xml2js = require('xml2js')
3
+ const fs = require('fs')
4
+ const rimraf = require('rimraf');
5
+
6
+ /** Header for error messages */
7
+ const ERRORHEADER = "[OfficeParser]: ";
8
+ /** Error messages */
9
+ const ERRORMSG = {
10
+ extensionUnsupported: (ext) => `${ERRORHEADER}Sorry, OfficeParser currently support docx, pptx, xlsx, odt, odp, ods files only. Create a ticket in Issues on github to add support for ${ext} files. Stay tuned for further updates.`,
11
+ fileCorrupted: (filename) => `${ERRORHEADER}Your file ${filename} seems to be corrupted. If you are sure it is fine, please create a ticket in Issues on github with the file to reproduce error.`,
12
+ fileDoesNotExist: (filename) => `${ERRORHEADER}File ${filename} could not be found! Check if the file exists or verify if the relative path to the file is correct from your terminal's location.`,
13
+ locationNotFound: (location) => `${ERRORHEADER}Entered location ${location} is not valid! Check relative paths and reenter. OfficeParser will use root directory as decompress location.`,
14
+ improperArguments: `${ERRORHEADER}Improper arguments`
15
+ }
16
+ /** Default sublocation for decompressing files under the current directory. */
17
+ const DEFAULTDECOMPRESSSUBLOCATION = "officeDist";
18
+ /** Location for decompressing files. Default is "officeDist" */
19
+ let decompressSubLocation = DEFAULTDECOMPRESSSUBLOCATION;
20
+ /** Flag to output errors to console other than normal error handling. Default is false as we anyway push the message for error handling. */
21
+ let outputErrorToConsole = false;
22
+
23
+ /** Console error if allowed */
24
+ function consoleError(errorMessage) {
25
+ if (outputErrorToConsole)
26
+ console.error(errorMessage);
27
+ }
28
+
29
+ /** Custom parseString promise as the native has bugs */
30
+ const parseStringPromise = (xml, ignoreAttrs = true) => new Promise((resolve, reject) => {
31
+ xml2js.parseString(xml, { "ignoreAttrs": ignoreAttrs }, (err, result) => {
32
+ if (err)
33
+ reject(err);
34
+ resolve(result);
35
+ });
36
+ });
37
+
38
+
39
+
40
+
41
+ /** Main function for parsing text from word files */
42
+ function parseWord(filename, callback, deleteOfficeDist = true) {
43
+ if (!fs.existsSync(filename)) {
44
+ consoleError(ERRORMSG.fileDoesNotExist(filename));
45
+ return callback(undefined, ERRORMSG.fileDoesNotExist(filename));
46
+ }
47
+ const ext = filename.split(".").pop().toLowerCase();
48
+ if (ext != 'docx') {
49
+ consoleError(ERRORMSG.extensionUnsupported(extension));
50
+ return callback(undefined, ERRORMSG.extensionUnsupported(ext));
51
+ }
52
+
53
+ /** Store all the text content to respond */
54
+ let responseText = [];
55
+
56
+ /** Extracting text from Word files xml objects converted to js */
57
+ function extractTextFromWordXmlObjects(xmlObjects) {
58
+ // specifically for Arrays
59
+ if (Array.isArray(xmlObjects)) {
60
+ xmlObjects.forEach(item =>
61
+ (typeof item == "string") && (item != "")
62
+ ? responseText.push(item)
63
+ : extractTextFromWordXmlObjects(item))
64
+ }
65
+ // for other JS Object
66
+ else if (typeof xmlObjects == "object") {
67
+ for (const [key, value] of Object.entries(xmlObjects)) {
68
+ (typeof value == "string") || (typeof value[0] == "string")
69
+ ? (key == "w:t" || key == "_") && value != ""
70
+ ? responseText.push(value)
71
+ : undefined
72
+ : extractTextFromWordXmlObjects(value);
73
+ }
74
+ }
75
+ }
76
+
77
+ const contentFile = 'word/document.xml';
78
+ decompress(filename,
79
+ decompressSubLocation,
80
+ { filter: x => x.path == contentFile }
81
+ )
82
+ .then(files => {
83
+ if (files.length != 1) {
84
+ consoleError(ERRORMSG.fileCorrupted(filename));
85
+ return callback(undefined, ERRORMSG.fileCorrupted(filename));
86
+ }
87
+
88
+ return fs.readFileSync(`${decompressSubLocation}/${contentFile}`, 'utf8');
89
+ })
90
+ .then(xmlContent => parseStringPromise(xmlContent))
91
+ .then(xmlObjects => {
92
+ extractTextFromWordXmlObjects(xmlObjects);
93
+ const returnCallbackPromise = new Promise((res, rej) => {
94
+ if (deleteOfficeDist)
95
+ rimraf(decompressSubLocation, err => {
96
+ if (err)
97
+ consoleError(err);
98
+ res();
99
+ });
100
+ else
101
+ res();
102
+ });
103
+
104
+ returnCallbackPromise
105
+ .then(() => callback(responseText.join(" "), undefined));
106
+
107
+ })
108
+ .catch(error => {
109
+ consoleError(error)
110
+ return callback(undefined, error);
111
+ });
112
+ }
113
+
114
+ /** Main function for parsing text from PowerPoint files */
115
+ function parsePowerPoint(filename, callback, deleteOfficeDist = true) {
116
+ if (!fs.existsSync(filename)) {
117
+ consoleError(ERRORMSG.fileDoesNotExist(filename));
118
+ return callback(undefined, ERRORMSG.fileDoesNotExist(filename));
119
+ }
120
+ const ext = filename.split(".").pop().toLowerCase();
121
+ if (ext != 'pptx') {
122
+ consoleError(ERRORMSG.extensionUnsupported(extension));
123
+ return callback(undefined, ERRORMSG.extensionUnsupported(ext));
124
+ }
125
+
126
+ /** Store all the text content to respond */
127
+ let responseText = [];
128
+
129
+ /** Extracting text from powerpoint files xml objects converted to js */
130
+ function extractTextFromPowerPointXmlObjects(xmlObjects) {
131
+ // specifically for Arrays
132
+ if (Array.isArray(xmlObjects)) {
133
+ xmlObjects.forEach(item =>
134
+ (typeof item == "string") && (item != "")
135
+ ? responseText.push(item)
136
+ : extractTextFromPowerPointXmlObjects(item))
137
+ }
138
+ // for other JS Object
139
+ else if (typeof xmlObjects == "object") {
140
+ for (const [key, value] of Object.entries(xmlObjects)) {
141
+ (typeof value == "string") || (typeof value[0] == "string")
142
+ ? (key == "a:t" || key == "_") && value != ""
143
+ ? responseText.push(value)
144
+ : undefined
145
+ : extractTextFromPowerPointXmlObjects(value);
146
+ }
147
+ }
148
+ }
149
+
150
+ // Files regex that hold our content of interest
151
+ const contentFiles = [
152
+ /ppt\/slides\/slide\d+.xml/g,
153
+ /ppt\/notesSlides\/notesSlide\d+.xml/g
154
+ ]
155
+
156
+ decompress(filename,
157
+ decompressSubLocation,
158
+ { filter: x => contentFiles.findIndex(fileRegex => x.path.match(fileRegex)) > -1 }
159
+ )
160
+ .then(files => {
161
+ // Sort files according to previous order of taking text out of ppt/slides followed by ppt/notesSlides
162
+ files.sort((a,b) => contentFiles.findIndex(fileRegex => a.path.match(fileRegex)) - contentFiles.findIndex(fileRegex => b.path.match(fileRegex)))
163
+
164
+ if (files.length == 0) {
165
+ consoleError(ERRORMSG.fileCorrupted(filename));
166
+ return callback(undefined, ERRORMSG.fileCorrupted(filename));
167
+ }
168
+
169
+ // Returning an array of all the xml contents read using fs.readFileSync
170
+ return files.map(file => fs.readFileSync(`${decompressSubLocation}/${file.path}`, 'utf8'))
171
+ })
172
+ .then(xmlContentArray => Promise.all(xmlContentArray.map(xmlContent => parseStringPromise(xmlContent)))) // Returning an array of all parseStringPromise responses
173
+ .then(xmlObjectsArray => {
174
+ xmlObjectsArray.forEach(xmlObjects => extractTextFromPowerPointXmlObjects(xmlObjects)); // Extracting text from all xml js objects with our conditions
175
+
176
+ const returnCallbackPromise = new Promise((res, rej) => {
177
+ if (deleteOfficeDist)
178
+ rimraf(decompressSubLocation, err => {
179
+ if (err)
180
+ consoleError(err);
181
+ res();
182
+ });
183
+ else
184
+ res();
185
+ });
186
+
187
+ returnCallbackPromise
188
+ .then(() => callback(responseText.join(" "), undefined));
189
+
190
+ })
191
+ .catch(error => {
192
+ consoleError(error)
193
+ return callback(undefined, error);
194
+ });
195
+ }
196
+
197
+ /** Main function for parsing text from Excel files */
198
+ function parseExcel(filename, callback, deleteOfficeDist = true) {
199
+ if (!fs.existsSync(filename)) {
200
+ consoleError(ERRORMSG.fileDoesNotExist(filename));
201
+ return callback(undefined, ERRORMSG.fileDoesNotExist(filename));
202
+ }
203
+ const ext = filename.split(".").pop().toLowerCase();
204
+ if (ext != 'xlsx') {
205
+ consoleError(ERRORMSG.extensionUnsupported(extension));
206
+ return callback(undefined, ERRORMSG.extensionUnsupported(ext));
207
+ }
208
+
209
+ /** Store all the text content to respond */
210
+ let responseText = [];
211
+
212
+ function extractTextFromExcelXmlObjects2dArray(xmlObjects2dArray) {
213
+ xmlObjects2dArray[0].map(xmlObjects => extractTextFromExcelXmlObjects(xmlObjects, 0));
214
+ xmlObjects2dArray[1].map(xmlObjects => extractTextFromExcelXmlObjects(xmlObjects, 1));
215
+ xmlObjects2dArray[2].map(xmlObjects => extractTextFromExcelXmlObjects(xmlObjects, 2));
216
+ }
217
+
218
+ /** Extracting text from Excel files xml objects converted to js */
219
+ function extractTextFromExcelXmlObjects(xmlObjects, contentFilesIndex) {
220
+ switch(contentFilesIndex) {
221
+ case 0: { // worksheet
222
+ // specifically for Arrays
223
+ if (Array.isArray(xmlObjects)) {
224
+ xmlObjects.forEach(item =>
225
+ item["v"]
226
+ ? ((item["$"]["t"] != "s"))
227
+ ? responseText.push(item["v"][0])
228
+ : undefined
229
+ : extractTextFromExcelXmlObjects(item, contentFilesIndex))
230
+ }
231
+ // for other JS Object
232
+ else if (typeof xmlObjects == "object") {
233
+ for (const [key, value] of Object.entries(xmlObjects)) {
234
+ value["v"]
235
+ ? ((value["$"]["t"] == "s"))
236
+ ? responseText.push(value["v"][0])
237
+ : undefined
238
+ : extractTextFromExcelXmlObjects(value, contentFilesIndex);
239
+ }
240
+ }
241
+ break;
242
+ }
243
+ case 1: { // sharedStrings
244
+ // specifically for Arrays
245
+ if (Array.isArray(xmlObjects)) {
246
+ xmlObjects.forEach(item =>
247
+ (typeof item == "string") && (item != "")
248
+ ? responseText.push(item)
249
+ : extractTextFromExcelXmlObjects(item, contentFilesIndex))
250
+ }
251
+ // for other JS Object
252
+ else if (typeof xmlObjects == "object") {
253
+ for (const [key, value] of Object.entries(xmlObjects)) {
254
+ (typeof value == "string") || (typeof value[0] == "string")
255
+ ? (key == "t" || key == "_") && (value != "")
256
+ ? responseText.push(value)
257
+ : undefined
258
+ : extractTextFromExcelXmlObjects(value, contentFilesIndex);
259
+ }
260
+ }
261
+ break;
262
+ }
263
+ case 2: { // drawings
264
+ // specifically for Arrays
265
+ if (Array.isArray(xmlObjects)) {
266
+ xmlObjects.forEach(item =>
267
+ (typeof item == "string") && (item != "")
268
+ ? responseText.push(item)
269
+ : extractTextFromExcelXmlObjects(item, contentFilesIndex))
270
+ }
271
+ // for other JS Object
272
+ else if (typeof xmlObjects == "object") {
273
+ for (const [key, value] of Object.entries(xmlObjects)) {
274
+ (typeof value == "string") || (typeof value[0] == "string")
275
+ ? (key == "a:t" || key == "_") && (value != "")
276
+ ? responseText.push(value)
277
+ : undefined
278
+ : extractTextFromExcelXmlObjects(value, contentFilesIndex);
279
+ }
280
+ }
281
+ break;
282
+ }
283
+ }
284
+ }
285
+
286
+ // Files regex that hold our content of interest
287
+ const contentFiles = [
288
+ /xl\/worksheets\/sheet\d+.xml/g,
289
+ /xl\/sharedStrings.xml/g,
290
+ /xl\/drawings\/drawing\d+.xml/g,
291
+ ]
292
+
293
+ decompress(filename,
294
+ decompressSubLocation,
295
+ { filter: x => contentFiles.findIndex(fileRegex => x.path.match(fileRegex)) > -1 }
296
+ )
297
+ .then(files => {
298
+ // arrange files into 2d array of files organized in contentFiles order, separated by array elements
299
+ const files2dArray = [];
300
+ contentFiles.forEach(fileRegex => files2dArray.push(files.filter(file => file.path.match(fileRegex))))
301
+
302
+ if (files.length == 0) {
303
+ consoleError(ERRORMSG.fileCorrupted(filename));
304
+ return callback(undefined, ERRORMSG.fileCorrupted(filename));
305
+ }
306
+
307
+ // Returning a 2dArray of all the xml contents read using fs.readFileSync and separated by array elements
308
+ return files2dArray.map(files => files.map(file => fs.readFileSync(`${decompressSubLocation}/${file.path}`, 'utf8')))
309
+ })
310
+ .then(xmlContent2dArray => Promise.all(xmlContent2dArray.map(xmlContentArray => Promise.all(xmlContentArray.map(xmlContent => parseStringPromise(xmlContent, false)))))) // Returning a 2dArray of all parseStringPromise responses
311
+ .then(xmlObjects2dArray => {
312
+ extractTextFromExcelXmlObjects2dArray(xmlObjects2dArray); // Extracting text from all xml js objects with our conditions
313
+
314
+ const returnCallbackPromise = new Promise((res, rej) => {
315
+ if (deleteOfficeDist)
316
+ rimraf(decompressSubLocation, err => {
317
+ if (err)
318
+ consoleError(err);
319
+ res();
320
+ });
321
+ else
322
+ res();
323
+ });
324
+
325
+ returnCallbackPromise
326
+ .then(() => callback(responseText.join(" "), undefined));
327
+
328
+ })
329
+ .catch(error => {
330
+ consoleError(error)
331
+ return callback(undefined, error);
332
+ });
333
+ }
334
+
335
+
336
+ /** Main function for parsing text from open office files */
337
+ function parseOpenOffice(filename, callback, deleteOfficeDist = true) {
338
+ if (!fs.existsSync(filename)) {
339
+ consoleError(ERRORMSG.fileDoesNotExist(filename));
340
+ return callback(undefined, ERRORMSG.fileDoesNotExist(filename));
341
+ }
342
+ const ext = filename.split(".").pop().toLowerCase();
343
+ if (!["odt", "odp", "ods"].includes(ext)) {
344
+ consoleError(ERRORMSG.extensionUnsupported(extension));
345
+ return callback(undefined, ERRORMSG.extensionUnsupported(ext));
346
+ }
347
+
348
+ /** Store all the text content to respond */
349
+ let responseText = [];
350
+ /** Extracting text from Open Office files xml objects converted to js */
351
+ function extractTextFromOpenOfficeXmlObjects(xmlObjects) {
352
+ // specifically for Arrays
353
+ if (Array.isArray(xmlObjects)) {
354
+ xmlObjects.forEach(item =>
355
+ (typeof item == "string") && (item != "")
356
+ ? responseText.push(item)
357
+ : extractTextFromOpenOfficeXmlObjects(item))
358
+ }
359
+ // for other JS Object
360
+ else if (typeof xmlObjects == "object") {
361
+ for (const [key, value] of Object.entries(xmlObjects)) {
362
+ typeof value == "string"
363
+ ? value != ""
364
+ ? responseText.push(value)
365
+ : undefined
366
+ : extractTextFromOpenOfficeXmlObjects(value);
367
+ }
368
+ }
369
+ }
370
+
371
+ const contentFile = 'content.xml';
372
+ decompress(filename,
373
+ decompressSubLocation,
374
+ { filter: x => x.path == contentFile }
375
+ )
376
+ .then(files => {
377
+ if (files.length != 1) {
378
+ consoleError(ERRORMSG.fileCorrupted(filename));
379
+ return callback(undefined, ERRORMSG.fileCorrupted(filename));
380
+ }
381
+
382
+ return fs.readFileSync(`${decompressSubLocation}/${contentFile}`, 'utf8');
383
+ })
384
+ .then(xmlContent => parseStringPromise(xmlContent))
385
+ .then(xmlObjects => {
386
+ extractTextFromOpenOfficeXmlObjects(xmlObjects);
387
+ const returnCallbackPromise = new Promise((res, rej) => {
388
+ if (deleteOfficeDist)
389
+ rimraf(decompressSubLocation, err => {
390
+ if (err)
391
+ consoleError(err);
392
+ res();
393
+ });
394
+ else
395
+ res();
396
+ });
397
+
398
+ returnCallbackPromise
399
+ .then(() => callback(responseText.join(" "), undefined));
400
+
401
+ })
402
+ .catch(error => {
403
+ consoleError(error)
404
+ return callback(undefined, error);
405
+ });
406
+ }
407
+
408
+
409
+ /** Main async function with callback to execute parseOffice for supported files */
410
+ function parseOffice(filename, callback, deleteOfficeDist = true) {
411
+ if (!fs.existsSync(filename)) {
412
+ consoleError(ERRORMSG.fileDoesNotExist(filename));
413
+ return callback(undefined, ERRORMSG.fileDoesNotExist(filename));
414
+ }
415
+ var extension = filename.split(".").pop().toLowerCase();
416
+
417
+ switch(extension)
418
+ {
419
+ case "docx":
420
+ parseWord(filename, (data, err) => callback(data, err), deleteOfficeDist);
421
+ return;
422
+ case "pptx":
423
+ parsePowerPoint(filename, (data, err) => callback(data, err), deleteOfficeDist);
424
+ return;
425
+ case "xlsx":
426
+ parseExcel(filename, (data, err) => callback(data, err), deleteOfficeDist);
427
+ return;
428
+ case "odt":
429
+ case "odp":
430
+ case "ods":
431
+ parseOpenOffice(filename, (data, err) => callback(data, err), deleteOfficeDist);
432
+ return;
433
+
434
+ default:
435
+ consoleError(ERRORMSG.extensionUnsupported(extension));
436
+ callback(undefined, ERRORMSG.extensionUnsupported(extension));
437
+ }
438
+ }
439
+
440
+ /**
441
+ * Set decompression directory. The final decompressed data will be put inside officeDist folder within your directory
442
+ * @param {string} newLocation Relative path to the directory that will contain officeDist folder with decompressed data
443
+ */
444
+ function setDecompressionLocation(newLocation) {
445
+ if (newLocation != undefined) {
446
+ newLocation = `${newLocation}${newLocation.endsWith('/') ? '' : '/'}${DEFAULTDECOMPRESSSUBLOCATION}`
447
+
448
+ if (fs.existsSync(newLocation))
449
+ decompressSubLocation = newLocation;
450
+ return;
451
+ }
452
+ consoleError(ERRORMSG.locationNotFound(newLocation));
453
+ decompressSubLocation = DEFAULTDECOMPRESSSUBLOCATION;
454
+ }
455
+
456
+ /** Enable console output */
457
+ function enableConsoleOutput() {
458
+ outputErrorToConsole = true;
459
+ }
460
+
461
+ /** Disabled console output */
462
+ function disableConsoleOutput() {
463
+ outputErrorToConsole = false;
464
+ }
465
+
466
+
467
+ // #region Promise versions of above functions
468
+ var parseWordAsync = function (filename, deleteOfficeDist = true) {
469
+ return new Promise((resolve, reject) => {
470
+ try {
471
+ parseWord(filename, function (data, error) {
472
+ if (error)
473
+ return reject(error);
474
+ return resolve(data);
475
+ }, deleteOfficeDist);
476
+ }
477
+ catch (error) {
478
+ return reject(error);
479
+ }
480
+ })
481
+ }
482
+
483
+ var parsePowerPointAsync = function (filename, deleteOfficeDist = true) {
484
+ return new Promise((resolve, reject) => {
485
+ try {
486
+ parsePowerPoint(filename, function (data, err) {
487
+ if (err)
488
+ return reject(err);
489
+ return resolve(data);
490
+ },deleteOfficeDist);
491
+ }
492
+ catch (error) {
493
+ return reject(error);
494
+ }
495
+ })
496
+ }
497
+
498
+ var parseExcelAsync = function (filename, deleteOfficeDist = true) {
499
+ return new Promise((resolve, reject) => {
500
+ try {
501
+ parseExcel(filename, function (data, err) {
502
+ if (err)
503
+ return reject(err);
504
+ return resolve(data);
505
+ },deleteOfficeDist);
506
+ }
507
+ catch (error) {
508
+ return reject(error);
509
+ }
510
+ })
511
+ }
512
+
513
+ var parseOpenOfficeAsync = function (filename, deleteOfficeDist = true) {
514
+ return new Promise((resolve, reject) => {
515
+ try {
516
+ parseOpenOffice(filename, function (data, err) {
517
+ if (err)
518
+ return reject(err);
519
+ return resolve(data);
520
+ },deleteOfficeDist);
521
+ }
522
+ catch (error) {
523
+ return reject(error);
524
+ }
525
+ })
526
+ }
527
+
528
+ var parseOfficeAsync = function (filename, deleteOfficeDist = true) {
529
+ return new Promise((resolve, reject) => {
530
+ try {
531
+ parseOffice(filename, function (data, err) {
532
+ if (err)
533
+ return reject(err);
534
+ return resolve(data);
535
+ },deleteOfficeDist);
536
+ }
537
+ catch (error) {
538
+ return reject(error);
539
+ }
540
+ })
541
+ }
542
+ // #endregion Async Versions
543
+
544
+ module.exports.parseWord = parseWord;
545
+ module.exports.parsePowerPoint = parsePowerPoint;
546
+ module.exports.parseExcel = parseExcel;
547
+ module.exports.parseOpenOffice = parseOpenOffice;
548
+ module.exports.parseOffice = parseOffice;
549
+ module.exports.parseWordAsync = parseWordAsync;
550
+ module.exports.parsePowerPointAsync = parsePowerPointAsync;
551
+ module.exports.parseExcelAsync = parseExcelAsync;
552
+ module.exports.parseOpenOfficeAsync = parseOpenOfficeAsync;
553
+ module.exports.parseOfficeAsync = parseOfficeAsync;
554
+ module.exports.setDecompressionLocation = setDecompressionLocation;
555
+ module.exports.enableConsoleOutput = enableConsoleOutput;
556
+ module.exports.disableConsoleOutput = disableConsoleOutput;
557
+
558
+ if ((process.argv[0].split('/').pop() == "node" || process.argv[0].split('/').pop() == "npx") && (process.argv[1].split('/').pop() == "officeParser.js" || process.argv[1].split('/').pop() == "officeparser")) {
559
+ if (process.argv.length == 2) {
560
+ // continue
561
+ }
562
+ else if (process.argv.length == 3)
563
+ parseOfficeAsync(process.argv[2])
564
+ .then(text => console.log(text))
565
+ .catch(error => console.error(error))
566
+ else
567
+ console.error(ERRORMSG.improperArguments)
568
+ }