@cj-tech-master/excelts 4.2.2 → 4.2.3-canary.20260122073152.a9bb6b0
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/csv/csv-core.d.ts +0 -9
- package/dist/browser/modules/csv/csv.browser.js +3 -3
- package/dist/browser/modules/excel/utils/parse-sax.d.ts +3 -0
- package/dist/browser/modules/excel/utils/parse-sax.js +32 -13
- package/dist/browser/modules/excel/utils/passthrough-manager.d.ts +77 -0
- package/dist/browser/modules/excel/utils/passthrough-manager.js +129 -0
- package/dist/browser/modules/excel/workbook.d.ts +8 -0
- package/dist/browser/modules/excel/workbook.js +9 -1
- package/dist/browser/modules/excel/worksheet.d.ts +4 -0
- package/dist/browser/modules/excel/worksheet.js +4 -1
- package/dist/browser/modules/excel/xlsx/xform/core/app-xform.js +3 -3
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
- package/dist/browser/modules/excel/xlsx/xform/core/core-xform.js +56 -68
- package/dist/browser/modules/excel/xlsx/xform/list-xform.js +8 -10
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +34 -11
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +256 -86
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +38 -11
- package/dist/browser/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
- package/dist/browser/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +36 -1
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +213 -127
- package/dist/browser/modules/stream/streams.browser.js +0 -3
- package/dist/cjs/modules/csv/csv.browser.js +3 -3
- package/dist/cjs/modules/excel/utils/parse-sax.js +32 -13
- package/dist/cjs/modules/excel/utils/passthrough-manager.js +133 -0
- package/dist/cjs/modules/excel/workbook.js +9 -1
- package/dist/cjs/modules/excel/worksheet.js +4 -1
- package/dist/cjs/modules/excel/xlsx/xform/core/app-xform.js +3 -3
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
- package/dist/cjs/modules/excel/xlsx/xform/core/core-xform.js +56 -68
- package/dist/cjs/modules/excel/xlsx/xform/list-xform.js +8 -10
- package/dist/cjs/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +256 -86
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +38 -11
- package/dist/cjs/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
- package/dist/cjs/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +213 -127
- package/dist/cjs/modules/stream/streams.browser.js +0 -3
- package/dist/esm/modules/csv/csv.browser.js +3 -3
- package/dist/esm/modules/excel/utils/parse-sax.js +32 -13
- package/dist/esm/modules/excel/utils/passthrough-manager.js +129 -0
- package/dist/esm/modules/excel/workbook.js +9 -1
- package/dist/esm/modules/excel/worksheet.js +4 -1
- package/dist/esm/modules/excel/xlsx/xform/core/app-xform.js +3 -3
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +16 -10
- package/dist/esm/modules/excel/xlsx/xform/core/core-xform.js +56 -68
- package/dist/esm/modules/excel/xlsx/xform/list-xform.js +8 -10
- package/dist/esm/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +256 -86
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +38 -11
- package/dist/esm/modules/excel/xlsx/xform/strings/shared-string-xform.js +2 -3
- package/dist/esm/modules/excel/xlsx/xform/strings/text-xform.js +5 -7
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +213 -127
- package/dist/esm/modules/stream/streams.browser.js +0 -3
- package/dist/iife/excelts.iife.js +603 -333
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +25 -52
- package/dist/types/modules/csv/csv-core.d.ts +0 -9
- package/dist/types/modules/excel/utils/parse-sax.d.ts +3 -0
- package/dist/types/modules/excel/utils/passthrough-manager.d.ts +77 -0
- package/dist/types/modules/excel/workbook.d.ts +8 -0
- package/dist/types/modules/excel/worksheet.d.ts +4 -0
- package/dist/types/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +34 -11
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +36 -1
- package/package.json +2 -2
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PassthroughManager - Manages passthrough files for round-trip preservation
|
|
3
|
+
*
|
|
4
|
+
* This module handles files that are not fully parsed by the library but need to be
|
|
5
|
+
* preserved during read/write cycles (e.g., charts, sparklines, slicers).
|
|
6
|
+
*/
|
|
7
|
+
// Pre-compiled regex patterns for content type detection (performance optimization)
|
|
8
|
+
const chartXmlRegex = /^xl\/charts\/chart\d+\.xml$/;
|
|
9
|
+
const chartStyleXmlRegex = /^xl\/charts\/style\d+\.xml$/;
|
|
10
|
+
const chartColorsXmlRegex = /^xl\/charts\/colors\d+\.xml$/;
|
|
11
|
+
/**
|
|
12
|
+
* Content type definitions for passthrough files
|
|
13
|
+
*/
|
|
14
|
+
const PASSTHROUGH_CONTENT_TYPES = new Map([
|
|
15
|
+
[chartXmlRegex, "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"],
|
|
16
|
+
[chartStyleXmlRegex, "application/vnd.ms-office.chartstyle+xml"],
|
|
17
|
+
[chartColorsXmlRegex, "application/vnd.ms-office.chartcolorstyle+xml"]
|
|
18
|
+
]);
|
|
19
|
+
/**
|
|
20
|
+
* Passthrough path prefixes that should be preserved
|
|
21
|
+
*/
|
|
22
|
+
const PASSTHROUGH_PREFIXES = ["xl/charts/"];
|
|
23
|
+
/**
|
|
24
|
+
* PassthroughManager handles storage and retrieval of passthrough files
|
|
25
|
+
* that need to be preserved during Excel read/write cycles.
|
|
26
|
+
*/
|
|
27
|
+
export class PassthroughManager {
|
|
28
|
+
constructor() {
|
|
29
|
+
this.files = new Map();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if a path should be treated as passthrough
|
|
33
|
+
*/
|
|
34
|
+
static isPassthroughPath(path) {
|
|
35
|
+
return PASSTHROUGH_PREFIXES.some(prefix => path.startsWith(prefix));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get the content type for a passthrough file path
|
|
39
|
+
* @returns Content type string or undefined if unknown
|
|
40
|
+
*/
|
|
41
|
+
static getContentType(path) {
|
|
42
|
+
// Chart relationships are handled by Default extension="rels"
|
|
43
|
+
if (path.startsWith("xl/charts/_rels/")) {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
for (const [regex, contentType] of PASSTHROUGH_CONTENT_TYPES) {
|
|
47
|
+
if (regex.test(path)) {
|
|
48
|
+
return contentType;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Add a file to passthrough storage
|
|
55
|
+
*/
|
|
56
|
+
add(path, data) {
|
|
57
|
+
this.files.set(path, data);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get a file from passthrough storage
|
|
61
|
+
*/
|
|
62
|
+
get(path) {
|
|
63
|
+
return this.files.get(path);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Check if a file exists in passthrough storage
|
|
67
|
+
*/
|
|
68
|
+
has(path) {
|
|
69
|
+
return this.files.has(path);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Get all stored paths
|
|
73
|
+
*/
|
|
74
|
+
getPaths() {
|
|
75
|
+
return [...this.files.keys()];
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Get all files as a record (for serialization)
|
|
79
|
+
*/
|
|
80
|
+
toRecord() {
|
|
81
|
+
const record = {};
|
|
82
|
+
for (const [path, data] of this.files) {
|
|
83
|
+
record[path] = data;
|
|
84
|
+
}
|
|
85
|
+
return record;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Load files from a record (for deserialization)
|
|
89
|
+
*/
|
|
90
|
+
fromRecord(record) {
|
|
91
|
+
this.files.clear();
|
|
92
|
+
for (const [path, data] of Object.entries(record)) {
|
|
93
|
+
this.files.set(path, data);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get content types for all stored files that have known types
|
|
98
|
+
*/
|
|
99
|
+
getContentTypes() {
|
|
100
|
+
const contentTypes = [];
|
|
101
|
+
for (const path of this.files.keys()) {
|
|
102
|
+
const contentType = PassthroughManager.getContentType(path);
|
|
103
|
+
if (contentType) {
|
|
104
|
+
contentTypes.push({ partName: path, contentType });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return contentTypes;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Write all passthrough files to a ZIP writer
|
|
111
|
+
*/
|
|
112
|
+
writeToZip(zip) {
|
|
113
|
+
for (const [path, data] of this.files) {
|
|
114
|
+
zip.append(data, { name: path });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Clear all stored files
|
|
119
|
+
*/
|
|
120
|
+
clear() {
|
|
121
|
+
this.files.clear();
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get the number of stored files
|
|
125
|
+
*/
|
|
126
|
+
get size() {
|
|
127
|
+
return this.files.size;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -38,6 +38,8 @@ class Workbook {
|
|
|
38
38
|
this.views = [];
|
|
39
39
|
this.media = [];
|
|
40
40
|
this.pivotTables = [];
|
|
41
|
+
this._passthrough = {};
|
|
42
|
+
this._rawDrawings = {};
|
|
41
43
|
this._definedNames = new DefinedNames();
|
|
42
44
|
}
|
|
43
45
|
// ===========================================================================
|
|
@@ -251,7 +253,9 @@ class Workbook {
|
|
|
251
253
|
themes: this._themes,
|
|
252
254
|
media: this.media,
|
|
253
255
|
pivotTables: this.pivotTables,
|
|
254
|
-
calcProperties: this.calcProperties
|
|
256
|
+
calcProperties: this.calcProperties,
|
|
257
|
+
passthrough: this._passthrough,
|
|
258
|
+
rawDrawings: this._rawDrawings
|
|
255
259
|
};
|
|
256
260
|
}
|
|
257
261
|
set model(value) {
|
|
@@ -292,6 +296,10 @@ class Workbook {
|
|
|
292
296
|
// Handle pivot tables - either newly created or loaded from file
|
|
293
297
|
// Loaded pivot tables come from loadedPivotTables after reconciliation
|
|
294
298
|
this.pivotTables = value.pivotTables || value.loadedPivotTables || [];
|
|
299
|
+
// Preserve passthrough files (charts, etc.) for round-trip preservation
|
|
300
|
+
this._passthrough = value.passthrough || {};
|
|
301
|
+
// Preserve raw drawing data for drawings with chart references
|
|
302
|
+
this._rawDrawings = value.rawDrawings || {};
|
|
295
303
|
}
|
|
296
304
|
}
|
|
297
305
|
// ===========================================================================
|
|
@@ -897,7 +897,8 @@ class Worksheet {
|
|
|
897
897
|
tables: Object.values(this.tables).map(table => table.model),
|
|
898
898
|
pivotTables: this.pivotTables,
|
|
899
899
|
conditionalFormattings: this.conditionalFormattings,
|
|
900
|
-
formControls: this.formControls.map(fc => fc.model)
|
|
900
|
+
formControls: this.formControls.map(fc => fc.model),
|
|
901
|
+
drawing: this._drawing
|
|
901
902
|
};
|
|
902
903
|
// =================================================
|
|
903
904
|
// columns
|
|
@@ -965,6 +966,8 @@ class Worksheet {
|
|
|
965
966
|
this.conditionalFormattings = value.conditionalFormattings;
|
|
966
967
|
// Form controls are currently write-only (not parsed from XLSX)
|
|
967
968
|
this.formControls = [];
|
|
969
|
+
// Preserve loaded drawing data (charts, etc.)
|
|
970
|
+
this._drawing = value.drawing;
|
|
968
971
|
}
|
|
969
972
|
}
|
|
970
973
|
export { Worksheet };
|
|
@@ -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
|
+
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.
|
|
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.
|
|
65
|
+
worksheets: this.map.TitlesOfParts.model,
|
|
66
66
|
company: this.map.Company.model,
|
|
67
67
|
manager: this.map.Manager.model
|
|
68
68
|
};
|
|
@@ -93,11 +93,16 @@ class ContentTypesXform extends BaseXform {
|
|
|
93
93
|
});
|
|
94
94
|
});
|
|
95
95
|
}
|
|
96
|
-
|
|
96
|
+
// VML extension is needed for comments or form controls
|
|
97
|
+
const hasComments = model.commentRefs && model.commentRefs.length > 0;
|
|
98
|
+
const hasFormControls = model.formControlRefs && model.formControlRefs.length > 0;
|
|
99
|
+
if (hasComments || hasFormControls) {
|
|
97
100
|
xmlStream.leafNode("Default", {
|
|
98
101
|
Extension: "vml",
|
|
99
102
|
ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing"
|
|
100
103
|
});
|
|
104
|
+
}
|
|
105
|
+
if (hasComments) {
|
|
101
106
|
model.commentRefs.forEach(({ commentName }) => {
|
|
102
107
|
xmlStream.leafNode("Override", {
|
|
103
108
|
PartName: toContentTypesPartName(commentsPathFromName(commentName)),
|
|
@@ -105,15 +110,7 @@ class ContentTypesXform extends BaseXform {
|
|
|
105
110
|
});
|
|
106
111
|
});
|
|
107
112
|
}
|
|
108
|
-
|
|
109
|
-
if (model.formControlRefs) {
|
|
110
|
-
// Ensure vml extension is declared (may already be declared for comments)
|
|
111
|
-
if (!model.commentRefs) {
|
|
112
|
-
xmlStream.leafNode("Default", {
|
|
113
|
-
Extension: "vml",
|
|
114
|
-
ContentType: "application/vnd.openxmlformats-officedocument.vmlDrawing"
|
|
115
|
-
});
|
|
116
|
-
}
|
|
113
|
+
if (hasFormControls) {
|
|
117
114
|
for (const ctrlPropId of model.formControlRefs) {
|
|
118
115
|
xmlStream.leafNode("Override", {
|
|
119
116
|
PartName: toContentTypesPartName(ctrlPropPath(ctrlPropId)),
|
|
@@ -121,6 +118,15 @@ class ContentTypesXform extends BaseXform {
|
|
|
121
118
|
});
|
|
122
119
|
}
|
|
123
120
|
}
|
|
121
|
+
// Add passthrough content types (charts, etc.)
|
|
122
|
+
if (model.passthroughContentTypes) {
|
|
123
|
+
for (const { partName, contentType } of model.passthroughContentTypes) {
|
|
124
|
+
xmlStream.leafNode("Override", {
|
|
125
|
+
PartName: toContentTypesPartName(partName),
|
|
126
|
+
ContentType: contentType
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
124
130
|
xmlStream.leafNode("Override", {
|
|
125
131
|
PartName: toContentTypesPartName(OOXML_PATHS.docPropsCore),
|
|
126
132
|
ContentType: "application/vnd.openxmlformats-package.core-properties+xml"
|
|
@@ -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
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
tag:
|
|
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
|
-
|
|
30
|
-
tag:
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
this.model
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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) {
|