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