@office-open/xml 0.3.1 → 0.3.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.
- package/dist/index.d.mts +11 -1
- package/dist/index.mjs +56 -62
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -32,9 +32,19 @@ declare function escapeXml(str: string): string;
|
|
|
32
32
|
* Handles already-escaped entities to prevent double-escaping.
|
|
33
33
|
*/
|
|
34
34
|
declare function escapeAttributeValue(str: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Build an XML attribute string fragment from a record.
|
|
37
|
+
* `undefined` values are automatically skipped.
|
|
38
|
+
* String values are escaped via `escapeXml`.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* attrs({ id: 1, name: "foo", hidden: undefined })
|
|
42
|
+
* // => ' id="1" name="foo"'
|
|
43
|
+
*/
|
|
44
|
+
declare function attrs(record: Record<string, string | number | boolean | undefined>): string;
|
|
35
45
|
//#endregion
|
|
36
46
|
//#region src/json.d.ts
|
|
37
47
|
/** Convert XML string to JSON string — xml-js compatible export */
|
|
38
48
|
declare function xml2json(xml: string, options?: Xml2JsOptions): string;
|
|
39
49
|
//#endregion
|
|
40
|
-
export { Attributes, DeclarationAttributes, Element, ElementCompact, ElementObject, IgnoreOptions, Js2XmlOptions, Xml2JsOptions, XmlAtom, XmlAttrs, XmlDesc, XmlDescArray, XmlObject, XmlOption, allChildren, attr, attrBool, attrNum, childCount, childText, children, collectText, colorAttr, escapeAttributeValue, escapeXml, findChild, findDeep, hasChild, js2xml, json2xml, textOf, toElement, xml, xml2js, xml2json };
|
|
50
|
+
export { Attributes, DeclarationAttributes, Element, ElementCompact, ElementObject, IgnoreOptions, Js2XmlOptions, Xml2JsOptions, XmlAtom, XmlAttrs, XmlDesc, XmlDescArray, XmlObject, XmlOption, allChildren, attr, attrBool, attrNum, attrs, childCount, childText, children, collectText, colorAttr, escapeAttributeValue, escapeXml, findChild, findDeep, hasChild, js2xml, json2xml, textOf, toElement, xml, xml2js, xml2json };
|
package/dist/index.mjs
CHANGED
|
@@ -19,6 +19,20 @@ function escapeXml(str) {
|
|
|
19
19
|
function escapeAttributeValue(str) {
|
|
20
20
|
return String(str).replace(/&(?!amp;|lt;|gt;|quot;|apos;)/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
21
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Build an XML attribute string fragment from a record.
|
|
24
|
+
* `undefined` values are automatically skipped.
|
|
25
|
+
* String values are escaped via `escapeXml`.
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* attrs({ id: 1, name: "foo", hidden: undefined })
|
|
29
|
+
* // => ' id="1" name="foo"'
|
|
30
|
+
*/
|
|
31
|
+
function attrs(record) {
|
|
32
|
+
let s = "";
|
|
33
|
+
for (const [k, v] of Object.entries(record)) if (v !== void 0) s += ` ${k}="${typeof v === "string" ? escapeXml(v) : v}"`;
|
|
34
|
+
return s;
|
|
35
|
+
}
|
|
22
36
|
//#endregion
|
|
23
37
|
//#region src/serialize.ts
|
|
24
38
|
const DEFAULT_INDENT = " ";
|
|
@@ -37,7 +51,8 @@ function xml(input, options) {
|
|
|
37
51
|
}
|
|
38
52
|
const items = Array.isArray(input) ? input : [input];
|
|
39
53
|
for (let i = 0; i < items.length; i++) {
|
|
40
|
-
|
|
54
|
+
const keys = Object.keys(items[i]);
|
|
55
|
+
parts.push(formatElement(keys[0], items[i][keys[0]], opts.indent, 0));
|
|
41
56
|
if (opts.indent && i < items.length - 1) parts.push("\n");
|
|
42
57
|
}
|
|
43
58
|
return parts.join("");
|
|
@@ -51,71 +66,50 @@ function normalizeOptions$1(options) {
|
|
|
51
66
|
declaration: opts.declaration
|
|
52
67
|
};
|
|
53
68
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
};
|
|
67
|
-
switch (typeof values) {
|
|
68
|
-
case "object":
|
|
69
|
-
if (values._attr) for (const key of Object.keys(values._attr)) attributes.push(`${key}="${escapeXml(String(values._attr[key]))}"`);
|
|
70
|
-
if (values._attributes) for (const key of Object.keys(values._attributes)) attributes.push(`${key}="${escapeXml(String(values._attributes[key]))}"`);
|
|
71
|
-
if (values._cdata) {
|
|
72
|
-
const escaped = String(values._cdata).replace(/\]\]>/g, "]]]]><![CDATA[>");
|
|
73
|
-
content.push(`<![CDATA[${escaped}]]>`);
|
|
74
|
-
}
|
|
75
|
-
if (Array.isArray(values)) {
|
|
76
|
-
if (values.length === 0) return {
|
|
77
|
-
name,
|
|
78
|
-
attributes,
|
|
79
|
-
content,
|
|
80
|
-
indent,
|
|
81
|
-
depth,
|
|
82
|
-
emptyArray: true
|
|
83
|
-
};
|
|
84
|
-
for (const value of values) if (value && typeof value === "object" && "_attr" in value) for (const key of Object.keys(value._attr)) attributes.push(`${key}="${escapeXml(String(value._attr[key]))}"`);
|
|
85
|
-
else if (value && typeof value === "object" && "_attributes" in value) for (const key of Object.keys(value._attributes)) attributes.push(`${key}="${escapeXml(String(value._attributes[key]))}"`);
|
|
86
|
-
else if (value && typeof value === "object") content.push(resolve(value, indent, depth + 1));
|
|
87
|
-
else if (value != null) content.push(escapeXml(String(value)));
|
|
88
|
-
}
|
|
89
|
-
break;
|
|
90
|
-
default: content.push(escapeXml(String(values)));
|
|
69
|
+
/**
|
|
70
|
+
* Single-pass XML formatter: directly converts IXmlableObject to string,
|
|
71
|
+
* eliminating the intermediate ResolvedElement tree.
|
|
72
|
+
*/
|
|
73
|
+
function formatElement(name, values, indent, depth) {
|
|
74
|
+
const attrParts = [];
|
|
75
|
+
const textParts = [];
|
|
76
|
+
const elemParts = [];
|
|
77
|
+
let emptyArray = false;
|
|
78
|
+
if (values == null) {
|
|
79
|
+
const attrStr = attrParts.length ? " " + attrParts.join(" ") : "";
|
|
80
|
+
return `${indent ? indent.repeat(depth) : ""}<${name}${attrStr}/>`;
|
|
91
81
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
82
|
+
if (typeof values === "object") {
|
|
83
|
+
if (values._attr) for (const key of Object.keys(values._attr)) attrParts.push(`${key}="${escapeXml(String(values._attr[key]))}"`);
|
|
84
|
+
if (values._attributes) for (const key of Object.keys(values._attributes)) attrParts.push(`${key}="${escapeXml(String(values._attributes[key]))}"`);
|
|
85
|
+
if (values._cdata) {
|
|
86
|
+
const escaped = String(values._cdata).replace(/\]\]>/g, "]]]]><![CDATA[>");
|
|
87
|
+
textParts.push(`<![CDATA[${escaped}]]>`);
|
|
88
|
+
}
|
|
89
|
+
if (Array.isArray(values)) {
|
|
90
|
+
if (values.length === 0) emptyArray = true;
|
|
91
|
+
else for (const value of values) if (value && typeof value === "object" && "_attr" in value) for (const key of Object.keys(value._attr)) attrParts.push(`${key}="${escapeXml(String(value._attr[key]))}"`);
|
|
92
|
+
else if (value && typeof value === "object" && "_attributes" in value) for (const key of Object.keys(value._attributes)) attrParts.push(`${key}="${escapeXml(String(value._attributes[key]))}"`);
|
|
93
|
+
else if (value && typeof value === "object") {
|
|
94
|
+
const childKeys = Object.keys(value);
|
|
95
|
+
elemParts.push(formatElement(childKeys[0], value[childKeys[0]], indent, depth + 1));
|
|
96
|
+
} else if (value != null) textParts.push(escapeXml(String(value)));
|
|
97
|
+
}
|
|
98
|
+
} else textParts.push(escapeXml(String(values)));
|
|
104
99
|
const ind = indent ? indent.repeat(depth) : "";
|
|
105
|
-
const attrStr =
|
|
106
|
-
if (
|
|
107
|
-
|
|
108
|
-
return `${ind}<${name}${attrStr}/>`;
|
|
109
|
-
}
|
|
110
|
-
const textContent = content.length === 1 && typeof content[0] === "string" ? content[0] : null;
|
|
111
|
-
if (textContent !== null && !indent) return `<${name}${attrStr}>${textContent}</${name}>`;
|
|
112
|
-
if (textContent !== null) return `${ind}<${name}${attrStr}>${textContent}</${name}>`;
|
|
100
|
+
const attrStr = attrParts.length ? " " + attrParts.join(" ") : "";
|
|
101
|
+
if (textParts.length + elemParts.length === 0) return emptyArray ? `${ind}<${name}${attrStr}></${name}>` : `${ind}<${name}${attrStr}/>`;
|
|
102
|
+
if (elemParts.length === 0 && textParts.length === 1) return indent ? `${ind}<${name}${attrStr}>${textParts[0]}</${name}>` : `<${name}${attrStr}>${textParts[0]}</${name}>`;
|
|
113
103
|
const parts = [];
|
|
114
104
|
parts.push(`${ind}<${name}${attrStr}>`);
|
|
115
105
|
if (indent) parts.push("\n");
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
106
|
+
const childIndent = indent ? indent.repeat(depth + 1) : "";
|
|
107
|
+
for (const t of textParts) {
|
|
108
|
+
parts.push(`${childIndent}${t}`);
|
|
109
|
+
if (indent) parts.push("\n");
|
|
110
|
+
}
|
|
111
|
+
for (const e of elemParts) {
|
|
112
|
+
parts.push(e);
|
|
119
113
|
if (indent) parts.push("\n");
|
|
120
114
|
}
|
|
121
115
|
parts.push(`${ind}</${name}>`);
|
|
@@ -502,4 +496,4 @@ function xml2json(xml, options) {
|
|
|
502
496
|
return JSON.stringify(xml2js(xml, options));
|
|
503
497
|
}
|
|
504
498
|
//#endregion
|
|
505
|
-
export { allChildren, attr, attrBool, attrNum, childCount, childText, children, collectText, colorAttr, escapeAttributeValue, escapeXml, findChild, findDeep, hasChild, js2xml, json2xml, textOf, toElement, xml, xml2js, xml2json };
|
|
499
|
+
export { allChildren, attr, attrBool, attrNum, attrs, childCount, childText, children, collectText, colorAttr, escapeAttributeValue, escapeXml, findChild, findDeep, hasChild, js2xml, json2xml, textOf, toElement, xml, xml2js, xml2json };
|