@cj-tech-master/excelts 4.2.2 → 4.2.3

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.
Files changed (27) hide show
  1. package/dist/browser/modules/excel/utils/parse-sax.d.ts +3 -0
  2. package/dist/browser/modules/excel/utils/parse-sax.js +32 -13
  3. package/dist/browser/modules/excel/xlsx/xform/core/app-xform.js +3 -3
  4. package/dist/browser/modules/excel/xlsx/xform/core/core-xform.js +56 -68
  5. package/dist/browser/modules/excel/xlsx/xform/list-xform.js +8 -10
  6. package/dist/browser/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
  7. package/dist/browser/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
  8. package/dist/browser/modules/excel/xlsx/xlsx.browser.js +8 -4
  9. package/dist/cjs/modules/excel/utils/parse-sax.js +32 -13
  10. package/dist/cjs/modules/excel/xlsx/xform/core/app-xform.js +3 -3
  11. package/dist/cjs/modules/excel/xlsx/xform/core/core-xform.js +56 -68
  12. package/dist/cjs/modules/excel/xlsx/xform/list-xform.js +8 -10
  13. package/dist/cjs/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
  14. package/dist/cjs/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
  15. package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +8 -4
  16. package/dist/esm/modules/excel/utils/parse-sax.js +32 -13
  17. package/dist/esm/modules/excel/xlsx/xform/core/app-xform.js +3 -3
  18. package/dist/esm/modules/excel/xlsx/xform/core/core-xform.js +56 -68
  19. package/dist/esm/modules/excel/xlsx/xform/list-xform.js +8 -10
  20. package/dist/esm/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
  21. package/dist/esm/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
  22. package/dist/esm/modules/excel/xlsx/xlsx.browser.js +8 -4
  23. package/dist/iife/excelts.iife.js +100 -100
  24. package/dist/iife/excelts.iife.js.map +1 -1
  25. package/dist/iife/excelts.iife.min.js +24 -24
  26. package/dist/types/modules/excel/utils/parse-sax.d.ts +3 -0
  27. package/package.json +1 -1
@@ -6,31 +6,50 @@ const base_xform_1 = require("../base-xform.js");
6
6
  const date_xform_1 = require("../simple/date-xform.js");
7
7
  const string_xform_1 = require("../simple/string-xform.js");
8
8
  const integer_xform_1 = require("../simple/integer-xform.js");
9
+ // Rendering uses namespace prefixes, parsing uses unqualified names (SAX strips prefixes)
10
+ const PROPS = {
11
+ creator: "dc:creator",
12
+ title: "dc:title",
13
+ subject: "dc:subject",
14
+ description: "dc:description",
15
+ identifier: "dc:identifier",
16
+ language: "dc:language",
17
+ keywords: "cp:keywords",
18
+ category: "cp:category",
19
+ lastModifiedBy: "cp:lastModifiedBy",
20
+ lastPrinted: "cp:lastPrinted",
21
+ revision: "cp:revision",
22
+ version: "cp:version",
23
+ contentStatus: "cp:contentStatus",
24
+ contentType: "cp:contentType",
25
+ created: "dcterms:created",
26
+ modified: "dcterms:modified"
27
+ };
9
28
  class CoreXform extends base_xform_1.BaseXform {
10
29
  constructor() {
11
30
  super();
12
31
  this.map = {
13
- "dc:creator": new string_xform_1.StringXform({ tag: "dc:creator" }),
14
- "dc:title": new string_xform_1.StringXform({ tag: "dc:title" }),
15
- "dc:subject": new string_xform_1.StringXform({ tag: "dc:subject" }),
16
- "dc:description": new string_xform_1.StringXform({ tag: "dc:description" }),
17
- "dc:identifier": new string_xform_1.StringXform({ tag: "dc:identifier" }),
18
- "dc:language": new string_xform_1.StringXform({ tag: "dc:language" }),
19
- "cp:keywords": new string_xform_1.StringXform({ tag: "cp:keywords" }),
20
- "cp:category": new string_xform_1.StringXform({ tag: "cp:category" }),
21
- "cp:lastModifiedBy": new string_xform_1.StringXform({ tag: "cp:lastModifiedBy" }),
22
- "cp:lastPrinted": new date_xform_1.DateXform({ tag: "cp:lastPrinted", format: CoreXform.DateFormat }),
23
- "cp:revision": new integer_xform_1.IntegerXform({ tag: "cp:revision" }),
24
- "cp:version": new string_xform_1.StringXform({ tag: "cp:version" }),
25
- "cp:contentStatus": new string_xform_1.StringXform({ tag: "cp:contentStatus" }),
26
- "cp:contentType": new string_xform_1.StringXform({ tag: "cp:contentType" }),
27
- "dcterms:created": new date_xform_1.DateXform({
28
- tag: "dcterms:created",
32
+ creator: new string_xform_1.StringXform({ tag: PROPS.creator }),
33
+ title: new string_xform_1.StringXform({ tag: PROPS.title }),
34
+ subject: new string_xform_1.StringXform({ tag: PROPS.subject }),
35
+ description: new string_xform_1.StringXform({ tag: PROPS.description }),
36
+ identifier: new string_xform_1.StringXform({ tag: PROPS.identifier }),
37
+ language: new string_xform_1.StringXform({ tag: PROPS.language }),
38
+ keywords: new string_xform_1.StringXform({ tag: PROPS.keywords }),
39
+ category: new string_xform_1.StringXform({ tag: PROPS.category }),
40
+ lastModifiedBy: new string_xform_1.StringXform({ tag: PROPS.lastModifiedBy }),
41
+ lastPrinted: new date_xform_1.DateXform({ tag: PROPS.lastPrinted, format: CoreXform.DateFormat }),
42
+ revision: new integer_xform_1.IntegerXform({ tag: PROPS.revision }),
43
+ version: new string_xform_1.StringXform({ tag: PROPS.version }),
44
+ contentStatus: new string_xform_1.StringXform({ tag: PROPS.contentStatus }),
45
+ contentType: new string_xform_1.StringXform({ tag: PROPS.contentType }),
46
+ created: new date_xform_1.DateXform({
47
+ tag: PROPS.created,
29
48
  attrs: CoreXform.DateAttrs,
30
49
  format: CoreXform.DateFormat
31
50
  }),
32
- "dcterms:modified": new date_xform_1.DateXform({
33
- tag: "dcterms:modified",
51
+ modified: new date_xform_1.DateXform({
52
+ tag: PROPS.modified,
34
53
  attrs: CoreXform.DateAttrs,
35
54
  format: CoreXform.DateFormat
36
55
  })
@@ -39,22 +58,9 @@ class CoreXform extends base_xform_1.BaseXform {
39
58
  render(xmlStream, model) {
40
59
  xmlStream.openXml(xml_stream_1.XmlStream.StdDocAttributes);
41
60
  xmlStream.openNode("cp:coreProperties", CoreXform.CORE_PROPERTY_ATTRIBUTES);
42
- this.map["dc:creator"].render(xmlStream, model.creator);
43
- this.map["dc:title"].render(xmlStream, model.title);
44
- this.map["dc:subject"].render(xmlStream, model.subject);
45
- this.map["dc:description"].render(xmlStream, model.description);
46
- this.map["dc:identifier"].render(xmlStream, model.identifier);
47
- this.map["dc:language"].render(xmlStream, model.language);
48
- this.map["cp:keywords"].render(xmlStream, model.keywords);
49
- this.map["cp:category"].render(xmlStream, model.category);
50
- this.map["cp:lastModifiedBy"].render(xmlStream, model.lastModifiedBy);
51
- this.map["cp:lastPrinted"].render(xmlStream, model.lastPrinted);
52
- this.map["cp:revision"].render(xmlStream, model.revision);
53
- this.map["cp:version"].render(xmlStream, model.version);
54
- this.map["cp:contentStatus"].render(xmlStream, model.contentStatus);
55
- this.map["cp:contentType"].render(xmlStream, model.contentType);
56
- this.map["dcterms:created"].render(xmlStream, model.created);
57
- this.map["dcterms:modified"].render(xmlStream, model.modified);
61
+ for (const key of Object.keys(PROPS)) {
62
+ this.map[key].render(xmlStream, model[key]);
63
+ }
58
64
  xmlStream.closeNode();
59
65
  }
60
66
  parseOpen(node) {
@@ -62,18 +68,13 @@ class CoreXform extends base_xform_1.BaseXform {
62
68
  this.parser.parseOpen(node);
63
69
  return true;
64
70
  }
65
- switch (node.name) {
66
- case "cp:coreProperties":
67
- case "coreProperties":
68
- return true;
69
- default:
70
- this.parser = this.map[node.name];
71
- if (this.parser) {
72
- this.parser.parseOpen(node);
73
- return true;
74
- }
75
- throw new Error(`Unexpected xml node in parseOpen: ${JSON.stringify(node)}`);
71
+ if (node.name !== "coreProperties") {
72
+ this.parser = this.map[node.name];
73
+ if (this.parser) {
74
+ this.parser.parseOpen(node);
75
+ }
76
76
  }
77
+ return true;
77
78
  }
78
79
  parseText(text) {
79
80
  if (this.parser) {
@@ -87,30 +88,17 @@ class CoreXform extends base_xform_1.BaseXform {
87
88
  }
88
89
  return true;
89
90
  }
90
- switch (name) {
91
- case "cp:coreProperties":
92
- case "coreProperties":
93
- this.model = {
94
- creator: this.map["dc:creator"].model,
95
- title: this.map["dc:title"].model,
96
- subject: this.map["dc:subject"].model,
97
- description: this.map["dc:description"].model,
98
- identifier: this.map["dc:identifier"].model,
99
- language: this.map["dc:language"].model,
100
- keywords: this.map["cp:keywords"].model,
101
- category: this.map["cp:category"].model,
102
- lastModifiedBy: this.map["cp:lastModifiedBy"].model,
103
- lastPrinted: this.map["cp:lastPrinted"].model,
104
- revision: this.map["cp:revision"].model,
105
- contentStatus: this.map["cp:contentStatus"].model,
106
- contentType: this.map["cp:contentType"].model,
107
- created: this.map["dcterms:created"].model,
108
- modified: this.map["dcterms:modified"].model
109
- };
110
- return false;
111
- default:
112
- throw new Error(`Unexpected xml node in parseClose: ${name}`);
91
+ if (name === "coreProperties") {
92
+ this.model = {};
93
+ for (const key of Object.keys(PROPS)) {
94
+ const val = this.map[key].model;
95
+ if (val !== undefined && val !== "") {
96
+ this.model[key] = val;
97
+ }
98
+ }
99
+ return false;
113
100
  }
101
+ return true;
114
102
  }
115
103
  }
116
104
  exports.CoreXform = CoreXform;
@@ -44,17 +44,15 @@ class ListXform extends base_xform_1.BaseXform {
44
44
  this.parser.parseOpen(node);
45
45
  return true;
46
46
  }
47
- switch (node.name) {
48
- case this.tag:
49
- this.model = [];
50
- return true;
51
- default:
52
- if (this.childXform.parseOpen(node)) {
53
- this.parser = this.childXform;
54
- return true;
55
- }
56
- return false;
47
+ if (node.name === this.tag) {
48
+ this.model = [];
49
+ return true;
57
50
  }
51
+ if (this.childXform.parseOpen(node)) {
52
+ this.parser = this.childXform;
53
+ return true;
54
+ }
55
+ return false;
58
56
  }
59
57
  parseText(text) {
60
58
  if (this.parser) {
@@ -39,16 +39,15 @@ class SharedStringXform extends base_xform_1.BaseXform {
39
39
  xmlStream.closeNode();
40
40
  }
41
41
  parseOpen(node) {
42
- const { name } = node;
43
42
  if (this.parser) {
44
43
  this.parser.parseOpen(node);
45
44
  return true;
46
45
  }
47
- if (name === this.tag) {
46
+ if (node.name === this.tag) {
48
47
  this.model = {};
49
48
  return true;
50
49
  }
51
- this.parser = this.map[name];
50
+ this.parser = this.map[node.name];
52
51
  if (this.parser) {
53
52
  this.parser.parseOpen(node);
54
53
  return true;
@@ -16,14 +16,12 @@ class TextXform extends base_xform_1.BaseXform {
16
16
  xmlStream.closeNode();
17
17
  }
18
18
  parseOpen(node) {
19
- switch (node.name) {
20
- case "t":
21
- this._text = [];
22
- this.model = ""; // Initialize model to empty string
23
- return true;
24
- default:
25
- return false;
19
+ if (node.name === "t") {
20
+ this._text = [];
21
+ this.model = "";
22
+ return true;
26
23
  }
24
+ return false;
27
25
  }
28
26
  parseText(text) {
29
27
  this._text.push(text);
@@ -367,8 +367,10 @@ class XLSX {
367
367
  case ooxml_paths_1.OOXML_PATHS.docPropsApp: {
368
368
  const appXform = new app_xform_1.AppXform();
369
369
  const appProperties = await appXform.parseStream(stream);
370
- model.company = appProperties.company;
371
- model.manager = appProperties.manager;
370
+ if (appProperties) {
371
+ model.company = appProperties.company;
372
+ model.manager = appProperties.manager;
373
+ }
372
374
  break;
373
375
  }
374
376
  case ooxml_paths_1.OOXML_PATHS.docPropsCore: {
@@ -830,8 +832,10 @@ class XLSX {
830
832
  case ooxml_paths_1.OOXML_PATHS.docPropsApp: {
831
833
  const appXform = new app_xform_1.AppXform();
832
834
  const appProperties = await appXform.parseStream(stream);
833
- model.company = appProperties.company;
834
- model.manager = appProperties.manager;
835
+ if (appProperties) {
836
+ model.company = appProperties.company;
837
+ model.manager = appProperties.manager;
838
+ }
835
839
  break;
836
840
  }
837
841
  case ooxml_paths_1.OOXML_PATHS.docPropsCore: {
@@ -142,6 +142,12 @@ const XML_ENTITIES = {
142
142
  quot: '"',
143
143
  apos: "'"
144
144
  };
145
+ // HAN CELL namespace prefix normalization
146
+ // HAN CELL uses non-standard namespace prefixes (ep:, cp:, dc:, etc.)
147
+ // The x: prefix for spreadsheetml is detected dynamically from xmlns declarations
148
+ // See: https://github.com/exceljs/exceljs/issues/3014
149
+ const HAN_CELL_PREFIXES = /^(ep|cp|dc|dcterms|dcmitype|vt):/;
150
+ const SPREADSHEETML_NS = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
145
151
  // ============================================================================
146
152
  // Parser States
147
153
  // ============================================================================
@@ -202,6 +208,8 @@ export class SaxesParser {
202
208
  this.chunkPosition = 0;
203
209
  // Entity storage
204
210
  this.ENTITIES = { ...XML_ENTITIES };
211
+ // HAN CELL compatibility: spreadsheetml namespace prefix (e.g., "x")
212
+ this.nsPrefix = null;
205
213
  this.trackPosition = opt?.position !== false;
206
214
  this.fileName = opt?.fileName;
207
215
  this.fragment = opt?.fragment ?? false;
@@ -236,6 +244,14 @@ export class SaxesParser {
236
244
  this.chunk = "";
237
245
  this.i = 0;
238
246
  this.prevI = 0;
247
+ this.nsPrefix = null;
248
+ }
249
+ // Strip HAN CELL namespace prefixes from element names
250
+ stripNsPrefix(name) {
251
+ const n = name.replace(HAN_CELL_PREFIXES, "");
252
+ return this.nsPrefix && n.startsWith(this.nsPrefix + ":")
253
+ ? n.slice(this.nsPrefix.length + 1)
254
+ : n;
239
255
  }
240
256
  on(name, handler) {
241
257
  switch (name) {
@@ -651,9 +667,8 @@ export class SaxesParser {
651
667
  this.name += charFromCode(c);
652
668
  return;
653
669
  }
654
- // Tag name complete
655
670
  this.tag = {
656
- name: this.name,
671
+ name: this.stripNsPrefix(this.name),
657
672
  attributes: Object.create(null),
658
673
  isSelfClosing: false
659
674
  };
@@ -1092,11 +1107,7 @@ export class SaxesParser {
1092
1107
  openTag() {
1093
1108
  const tag = this.tag;
1094
1109
  tag.isSelfClosing = false;
1095
- // Copy attributes from list to object
1096
- for (const { name, value } of this.attribList) {
1097
- tag.attributes[name] = value;
1098
- }
1099
- this.attribList = [];
1110
+ this.processAttributes(tag);
1100
1111
  this.openTagHandler?.(tag);
1101
1112
  this.tags.push(tag);
1102
1113
  this.name = "";
@@ -1105,11 +1116,7 @@ export class SaxesParser {
1105
1116
  openSelfClosingTag() {
1106
1117
  const tag = this.tag;
1107
1118
  tag.isSelfClosing = true;
1108
- // Copy attributes from list to object
1109
- for (const { name, value } of this.attribList) {
1110
- tag.attributes[name] = value;
1111
- }
1112
- this.attribList = [];
1119
+ this.processAttributes(tag);
1113
1120
  this.openTagHandler?.(tag);
1114
1121
  this.closeTagHandler?.(tag);
1115
1122
  if (this.tags.length === 0) {
@@ -1118,8 +1125,20 @@ export class SaxesParser {
1118
1125
  this.name = "";
1119
1126
  this.state = S_TEXT;
1120
1127
  }
1128
+ // Process attributes and detect spreadsheetml namespace prefix
1129
+ processAttributes(tag) {
1130
+ for (const { name, value } of this.attribList) {
1131
+ tag.attributes[name] = value;
1132
+ if (name.startsWith("xmlns:") && value === SPREADSHEETML_NS) {
1133
+ this.nsPrefix = name.slice(6);
1134
+ tag.name = this.stripNsPrefix(tag.name);
1135
+ }
1136
+ }
1137
+ this.attribList = [];
1138
+ }
1121
1139
  closeTag() {
1122
- const { tags, name } = this;
1140
+ const { tags } = this;
1141
+ const name = this.stripNsPrefix(this.name);
1123
1142
  this.state = S_TEXT;
1124
1143
  this.name = "";
1125
1144
  if (name === "") {
@@ -10,7 +10,7 @@ class AppXform extends BaseXform {
10
10
  Company: new StringXform({ tag: "Company" }),
11
11
  Manager: new StringXform({ tag: "Manager" }),
12
12
  HeadingPairs: new AppHeadingPairsXform(),
13
- TitleOfParts: new AppTitlesOfPartsXform()
13
+ TitlesOfParts: new AppTitlesOfPartsXform()
14
14
  };
15
15
  }
16
16
  render(xmlStream, model) {
@@ -20,7 +20,7 @@ class AppXform extends BaseXform {
20
20
  xmlStream.leafNode("DocSecurity", undefined, "0");
21
21
  xmlStream.leafNode("ScaleCrop", undefined, "false");
22
22
  this.map.HeadingPairs.render(xmlStream, model.worksheets);
23
- this.map.TitleOfParts.render(xmlStream, model.worksheets);
23
+ this.map.TitlesOfParts.render(xmlStream, model.worksheets);
24
24
  this.map.Company.render(xmlStream, model.company || "");
25
25
  this.map.Manager.render(xmlStream, model.manager);
26
26
  xmlStream.leafNode("LinksUpToDate", undefined, "false");
@@ -62,7 +62,7 @@ class AppXform extends BaseXform {
62
62
  switch (name) {
63
63
  case "Properties":
64
64
  this.model = {
65
- worksheets: this.map.TitleOfParts.model,
65
+ worksheets: this.map.TitlesOfParts.model,
66
66
  company: this.map.Company.model,
67
67
  manager: this.map.Manager.model
68
68
  };
@@ -3,31 +3,50 @@ import { BaseXform } from "../base-xform.js";
3
3
  import { DateXform } from "../simple/date-xform.js";
4
4
  import { StringXform } from "../simple/string-xform.js";
5
5
  import { IntegerXform } from "../simple/integer-xform.js";
6
+ // Rendering uses namespace prefixes, parsing uses unqualified names (SAX strips prefixes)
7
+ const PROPS = {
8
+ creator: "dc:creator",
9
+ title: "dc:title",
10
+ subject: "dc:subject",
11
+ description: "dc:description",
12
+ identifier: "dc:identifier",
13
+ language: "dc:language",
14
+ keywords: "cp:keywords",
15
+ category: "cp:category",
16
+ lastModifiedBy: "cp:lastModifiedBy",
17
+ lastPrinted: "cp:lastPrinted",
18
+ revision: "cp:revision",
19
+ version: "cp:version",
20
+ contentStatus: "cp:contentStatus",
21
+ contentType: "cp:contentType",
22
+ created: "dcterms:created",
23
+ modified: "dcterms:modified"
24
+ };
6
25
  class CoreXform extends BaseXform {
7
26
  constructor() {
8
27
  super();
9
28
  this.map = {
10
- "dc:creator": new StringXform({ tag: "dc:creator" }),
11
- "dc:title": new StringXform({ tag: "dc:title" }),
12
- "dc:subject": new StringXform({ tag: "dc:subject" }),
13
- "dc:description": new StringXform({ tag: "dc:description" }),
14
- "dc:identifier": new StringXform({ tag: "dc:identifier" }),
15
- "dc:language": new StringXform({ tag: "dc:language" }),
16
- "cp:keywords": new StringXform({ tag: "cp:keywords" }),
17
- "cp:category": new StringXform({ tag: "cp:category" }),
18
- "cp:lastModifiedBy": new StringXform({ tag: "cp:lastModifiedBy" }),
19
- "cp:lastPrinted": new DateXform({ tag: "cp:lastPrinted", format: CoreXform.DateFormat }),
20
- "cp:revision": new IntegerXform({ tag: "cp:revision" }),
21
- "cp:version": new StringXform({ tag: "cp:version" }),
22
- "cp:contentStatus": new StringXform({ tag: "cp:contentStatus" }),
23
- "cp:contentType": new StringXform({ tag: "cp:contentType" }),
24
- "dcterms:created": new DateXform({
25
- tag: "dcterms:created",
29
+ creator: new StringXform({ tag: PROPS.creator }),
30
+ title: new StringXform({ tag: PROPS.title }),
31
+ subject: new StringXform({ tag: PROPS.subject }),
32
+ description: new StringXform({ tag: PROPS.description }),
33
+ identifier: new StringXform({ tag: PROPS.identifier }),
34
+ language: new StringXform({ tag: PROPS.language }),
35
+ keywords: new StringXform({ tag: PROPS.keywords }),
36
+ category: new StringXform({ tag: PROPS.category }),
37
+ lastModifiedBy: new StringXform({ tag: PROPS.lastModifiedBy }),
38
+ lastPrinted: new DateXform({ tag: PROPS.lastPrinted, format: CoreXform.DateFormat }),
39
+ revision: new IntegerXform({ tag: PROPS.revision }),
40
+ version: new StringXform({ tag: PROPS.version }),
41
+ contentStatus: new StringXform({ tag: PROPS.contentStatus }),
42
+ contentType: new StringXform({ tag: PROPS.contentType }),
43
+ created: new DateXform({
44
+ tag: PROPS.created,
26
45
  attrs: CoreXform.DateAttrs,
27
46
  format: CoreXform.DateFormat
28
47
  }),
29
- "dcterms:modified": new DateXform({
30
- tag: "dcterms:modified",
48
+ modified: new DateXform({
49
+ tag: PROPS.modified,
31
50
  attrs: CoreXform.DateAttrs,
32
51
  format: CoreXform.DateFormat
33
52
  })
@@ -36,22 +55,9 @@ class CoreXform extends BaseXform {
36
55
  render(xmlStream, model) {
37
56
  xmlStream.openXml(XmlStream.StdDocAttributes);
38
57
  xmlStream.openNode("cp:coreProperties", CoreXform.CORE_PROPERTY_ATTRIBUTES);
39
- this.map["dc:creator"].render(xmlStream, model.creator);
40
- this.map["dc:title"].render(xmlStream, model.title);
41
- this.map["dc:subject"].render(xmlStream, model.subject);
42
- this.map["dc:description"].render(xmlStream, model.description);
43
- this.map["dc:identifier"].render(xmlStream, model.identifier);
44
- this.map["dc:language"].render(xmlStream, model.language);
45
- this.map["cp:keywords"].render(xmlStream, model.keywords);
46
- this.map["cp:category"].render(xmlStream, model.category);
47
- this.map["cp:lastModifiedBy"].render(xmlStream, model.lastModifiedBy);
48
- this.map["cp:lastPrinted"].render(xmlStream, model.lastPrinted);
49
- this.map["cp:revision"].render(xmlStream, model.revision);
50
- this.map["cp:version"].render(xmlStream, model.version);
51
- this.map["cp:contentStatus"].render(xmlStream, model.contentStatus);
52
- this.map["cp:contentType"].render(xmlStream, model.contentType);
53
- this.map["dcterms:created"].render(xmlStream, model.created);
54
- this.map["dcterms:modified"].render(xmlStream, model.modified);
58
+ for (const key of Object.keys(PROPS)) {
59
+ this.map[key].render(xmlStream, model[key]);
60
+ }
55
61
  xmlStream.closeNode();
56
62
  }
57
63
  parseOpen(node) {
@@ -59,18 +65,13 @@ class CoreXform extends BaseXform {
59
65
  this.parser.parseOpen(node);
60
66
  return true;
61
67
  }
62
- switch (node.name) {
63
- case "cp:coreProperties":
64
- case "coreProperties":
65
- return true;
66
- default:
67
- this.parser = this.map[node.name];
68
- if (this.parser) {
69
- this.parser.parseOpen(node);
70
- return true;
71
- }
72
- throw new Error(`Unexpected xml node in parseOpen: ${JSON.stringify(node)}`);
68
+ if (node.name !== "coreProperties") {
69
+ this.parser = this.map[node.name];
70
+ if (this.parser) {
71
+ this.parser.parseOpen(node);
72
+ }
73
73
  }
74
+ return true;
74
75
  }
75
76
  parseText(text) {
76
77
  if (this.parser) {
@@ -84,30 +85,17 @@ class CoreXform extends BaseXform {
84
85
  }
85
86
  return true;
86
87
  }
87
- switch (name) {
88
- case "cp:coreProperties":
89
- case "coreProperties":
90
- this.model = {
91
- creator: this.map["dc:creator"].model,
92
- title: this.map["dc:title"].model,
93
- subject: this.map["dc:subject"].model,
94
- description: this.map["dc:description"].model,
95
- identifier: this.map["dc:identifier"].model,
96
- language: this.map["dc:language"].model,
97
- keywords: this.map["cp:keywords"].model,
98
- category: this.map["cp:category"].model,
99
- lastModifiedBy: this.map["cp:lastModifiedBy"].model,
100
- lastPrinted: this.map["cp:lastPrinted"].model,
101
- revision: this.map["cp:revision"].model,
102
- contentStatus: this.map["cp:contentStatus"].model,
103
- contentType: this.map["cp:contentType"].model,
104
- created: this.map["dcterms:created"].model,
105
- modified: this.map["dcterms:modified"].model
106
- };
107
- return false;
108
- default:
109
- throw new Error(`Unexpected xml node in parseClose: ${name}`);
88
+ if (name === "coreProperties") {
89
+ this.model = {};
90
+ for (const key of Object.keys(PROPS)) {
91
+ const val = this.map[key].model;
92
+ if (val !== undefined && val !== "") {
93
+ this.model[key] = val;
94
+ }
95
+ }
96
+ return false;
110
97
  }
98
+ return true;
111
99
  }
112
100
  }
113
101
  CoreXform.DateFormat = function (dt) {
@@ -41,17 +41,15 @@ class ListXform extends BaseXform {
41
41
  this.parser.parseOpen(node);
42
42
  return true;
43
43
  }
44
- switch (node.name) {
45
- case this.tag:
46
- this.model = [];
47
- return true;
48
- default:
49
- if (this.childXform.parseOpen(node)) {
50
- this.parser = this.childXform;
51
- return true;
52
- }
53
- return false;
44
+ if (node.name === this.tag) {
45
+ this.model = [];
46
+ return true;
54
47
  }
48
+ if (this.childXform.parseOpen(node)) {
49
+ this.parser = this.childXform;
50
+ return true;
51
+ }
52
+ return false;
55
53
  }
56
54
  parseText(text) {
57
55
  if (this.parser) {
@@ -36,16 +36,15 @@ class SharedStringXform extends BaseXform {
36
36
  xmlStream.closeNode();
37
37
  }
38
38
  parseOpen(node) {
39
- const { name } = node;
40
39
  if (this.parser) {
41
40
  this.parser.parseOpen(node);
42
41
  return true;
43
42
  }
44
- if (name === this.tag) {
43
+ if (node.name === this.tag) {
45
44
  this.model = {};
46
45
  return true;
47
46
  }
48
- this.parser = this.map[name];
47
+ this.parser = this.map[node.name];
49
48
  if (this.parser) {
50
49
  this.parser.parseOpen(node);
51
50
  return true;
@@ -13,14 +13,12 @@ class TextXform extends BaseXform {
13
13
  xmlStream.closeNode();
14
14
  }
15
15
  parseOpen(node) {
16
- switch (node.name) {
17
- case "t":
18
- this._text = [];
19
- this.model = ""; // Initialize model to empty string
20
- return true;
21
- default:
22
- return false;
16
+ if (node.name === "t") {
17
+ this._text = [];
18
+ this.model = "";
19
+ return true;
23
20
  }
21
+ return false;
24
22
  }
25
23
  parseText(text) {
26
24
  this._text.push(text);
@@ -364,8 +364,10 @@ class XLSX {
364
364
  case OOXML_PATHS.docPropsApp: {
365
365
  const appXform = new AppXform();
366
366
  const appProperties = await appXform.parseStream(stream);
367
- model.company = appProperties.company;
368
- model.manager = appProperties.manager;
367
+ if (appProperties) {
368
+ model.company = appProperties.company;
369
+ model.manager = appProperties.manager;
370
+ }
369
371
  break;
370
372
  }
371
373
  case OOXML_PATHS.docPropsCore: {
@@ -827,8 +829,10 @@ class XLSX {
827
829
  case OOXML_PATHS.docPropsApp: {
828
830
  const appXform = new AppXform();
829
831
  const appProperties = await appXform.parseStream(stream);
830
- model.company = appProperties.company;
831
- model.manager = appProperties.manager;
832
+ if (appProperties) {
833
+ model.company = appProperties.company;
834
+ model.manager = appProperties.manager;
835
+ }
832
836
  break;
833
837
  }
834
838
  case OOXML_PATHS.docPropsCore: {