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