@office-open/xml 0.10.15 → 0.12.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/README.md CHANGED
@@ -5,17 +5,15 @@
5
5
  ![npm license](https://img.shields.io/npm/l/@office-open/xml)
6
6
  ![zero dependencies](https://img.shields.io/badge/dependencies-0-green)
7
7
 
8
- > XML parsing and serialization for Office Open XML. Zero dependencies, drop-in replacement for xml + xml-js.
8
+ > XML parsing and serialization for Office Open XML. Zero dependencies, pure TypeScript.
9
9
 
10
10
  ## Features
11
11
 
12
12
  - **Zero Dependencies** - No external runtime dependencies, pure TypeScript implementation
13
- - **xml() Serialization** - Drop-in replacement for the `xml` package
14
- - **xml2js() Parsing** - Drop-in replacement for `xml-js` XML parsing
15
- - **js2xml() Stringifying** - Drop-in replacement for `xml-js` JS-to-XML conversion
16
- - **toElement() Direct Convert** - Direct conversion from xml object format to xml-js Element, 10-19x faster than the xml→xml2js bridge
17
- - **Complete Type Definitions** - Full type compatibility with `xml` and `xml-js`, import without changes
18
- - **OOXML Optimized** - Implements all options needed for Office Open XML document generation
13
+ - **parse() / stringify()** - XML string Element tree, OOXML-optimized
14
+ - **Element Type** - Tolerant element model for round-tripping Office Open XML parts
15
+ - **escapeXml() / unescapeXml()** - Low-level XML entity escaping
16
+ - **OOXML Optimized** - Implements the options needed for Office Open XML document generation and parsing
19
17
 
20
18
  ## Installation
21
19
 
@@ -33,113 +31,72 @@ yarn add @office-open/xml
33
31
  bun add @office-open/xml
34
32
  ```
35
33
 
36
- ## Migration from xml + xml-js
37
-
38
- Replace your existing imports:
39
-
40
- ```typescript
41
- // Before
42
- import xml from "xml";
43
- import { xml2js, js2xml } from "xml-js";
44
- import type { Element } from "xml-js";
45
-
46
- // After
47
- import { xml, xml2js, js2xml } from "@office-open/xml";
48
- import type { Element } from "@office-open/xml";
49
- ```
50
-
51
- No other code changes needed. All options and output formats are compatible.
52
-
53
34
  ## Quick Start
54
35
 
55
36
  ```typescript
56
- import { xml, xml2js, js2xml, toElement } from "@office-open/xml";
57
-
58
- // Serialize JS objects to XML
59
- const xmlStr = xml({ "w:p": [{ _attr: { "w:val": "1" } }, { "w:r": [{ "w:t": "Hello" }] }] });
60
- // <w:p w:val="1"><w:r><w:t>Hello</w:t></w:r></w:p>
61
-
62
- // Parse XML to JS objects
63
- const parsed = xml2js("<w:t>Hello</w:t>", { compact: false });
37
+ import { parse, stringify } from "@office-open/xml";
64
38
 
65
- // Convert JS objects back to XML
66
- const output = js2xml(parsed);
39
+ // Parse XML to an Element tree
40
+ const doc = parse("<w:t>Hello</w:t>");
67
41
 
68
- // Direct conversion (faster than xml xml2js bridge)
69
- const element = toElement({
70
- "w:p": [{ _attr: { "w:val": "1" } }, { "w:r": [{ "w:t": "Hello" }] }],
71
- });
42
+ // Serialize an Element tree back to XML
43
+ const xml = stringify(doc);
72
44
  ```
73
45
 
74
46
  ## API
75
47
 
76
- ### xml(input, options?)
77
-
78
- Serialize JavaScript objects to XML string. Compatible with the `xml` package.
79
-
80
- ### xml2js(xmlString, options?)
48
+ ### parse(xmlString, options?)
81
49
 
82
- Parse XML string to JavaScript object. Compatible with `xml-js`.
50
+ Parse an XML string into an `Element` tree. Options include `compact`, `trim`, `nativeType`, `captureSpacesBetweenElements`, the `ignore*` flags, and the `*Fn` transformation hooks.
83
51
 
84
- ### js2xml(jsObject, options?)
52
+ ### stringify(element, options?)
85
53
 
86
- Convert JavaScript object (xml-js Element format) to XML string. Compatible with `xml-js`.
54
+ Serialize an `Element` tree to an XML string. Options include `spaces` (indentation), the `ignore*` flags, and the `*Fn` hooks.
87
55
 
88
- ### json2xml(jsObject, options?)
56
+ ### escapeXml(str) / unescapeXml(str)
89
57
 
90
- Alias for `js2xml`.
58
+ Low-level XML entity escaping and unescaping.
91
59
 
92
- ### xml2json(xmlString, options?)
60
+ ### Element
93
61
 
94
- Convenience function that returns `JSON.stringify(xml2js(xmlString, options))`.
62
+ The tolerant element type used across all office-open packages:
95
63
 
96
- ### toElement(input)
97
-
98
- Direct conversion from xml object format to xml-js Element format. Much faster than the `xml() → xml2js()` bridge path.
99
-
100
- ### escapeXml(str) / escapeAttributeValue(str)
101
-
102
- Low-level XML entity escaping functions.
64
+ ```typescript
65
+ interface Element {
66
+ declaration?: { attributes?: DeclarationAttributes };
67
+ attributes?: Attributes;
68
+ type?: string;
69
+ name?: string;
70
+ text?: string | number | boolean;
71
+ cdata?: string;
72
+ comment?: string;
73
+ elements?: Element[];
74
+ }
75
+ ```
103
76
 
104
77
  ## Benchmark
105
78
 
106
- Performance comparison against original `xml` (1.0.1) and `xml-js` (1.6.11) packages:
107
-
108
- ### Serialization (xml)
109
-
110
- | Scenario | @office-open/xml | xml | Speedup |
111
- | ----------------------- | ---------------: | ---------: | --------: |
112
- | Simple element | 5,440,771 hz | 805,545 hz | **6.75x** |
113
- | Nested element | 1,050,272 hz | 315,184 hz | **3.33x** |
114
- | Nested with declaration | 967,945 hz | 275,684 hz | **3.51x** |
115
-
116
- ### Parsing (xml2js)
117
-
118
- | Scenario | @office-open/xml | xml-js | Speedup |
119
- | ------------------ | ---------------: | ---------: | --------: |
120
- | Simple XML | 869,965 hz | 100,507 hz | **8.66x** |
121
- | Complex OOXML | 346,440 hz | 53,621 hz | **6.46x** |
122
- | With captureSpaces | 344,586 hz | 52,414 hz | **6.57x** |
123
-
124
- ### Stringifying (js2xml)
79
+ Performance vs [txml](https://github.com/TobiasNickel/tXml), [xml-js](https://github.com/nashwaan/xml-js), and [xml](https://github.com/dylang/node-xml) (higher ops/s is better, Windows 11; each scenario runs under both Node 24 and Bun 1.4). `@office-open/xml` is a drop-in replacement for xml-js and xml. The `xml` (npm) package is generation-only (no parser), so it only appears under stringify. `Bun.XML` is Bun-only and its compact parse mode is lossy (`#text` runs concatenate, same-name children collapse into keyed arrays), so it is a throughput reference rather than a drop-in option.
125
80
 
126
- | Scenario | @office-open/xml | xml-js | Speedup |
127
- | -------------- | ---------------: | ---------: | --------: |
128
- | Simple element | 793,710 hz | 207,730 hz | **3.82x** |
129
- | Complex OOXML | 366,515 hz | 135,815 hz | **2.70x** |
81
+ txml skips entity encoding by default (`encodeEntities: false`), which emits invalid XML when text contains `&`, `<`, or `>`; the `txml` column shows that raw mode and the `txml (entities)` column is the output-equivalent mode.
130
82
 
131
- ### Direct Conversion (toElement vs bridge)
83
+ **parse() XML string Element tree**
132
84
 
133
- | Scenario | toElement() | xml() + xml2js() bridge | Speedup |
134
- | -------- | ------------: | ----------------------: | ---------: |
135
- | Simple | 15,471,913 hz | 1,073,016 hz | **14.42x** |
136
- | Nested | 4,278,499 hz | 441,468 hz | **9.69x** |
85
+ | Scenario | Runtime | @office-open/xml | txml | xml-js | Bun.XML.parse |
86
+ | ------------- | ------- | ---------------- | ------------- | ------------- | ------------- |
87
+ | simple XML | Node 24 | 1,301,742 ops/s | 983,046 ops/s | 93,951 ops/s | — |
88
+ | | Bun 1.4 | 1,906,525 ops/s | 616,562 ops/s | 161,894 ops/s | 828,554 ops/s |
89
+ | complex OOXML | Node 24 | 423,536 ops/s | 388,743 ops/s | 49,771 ops/s | — |
90
+ | | Bun 1.4 | 483,512 ops/s | 241,036 ops/s | 63,029 ops/s | 451,177 ops/s |
137
91
 
138
- ## Bundle Size
92
+ **stringify() Element tree → XML string**
139
93
 
140
- | | @office-open/xml | xml + xml-js |
141
- | ---- | ---------------: | -----------: |
142
- | gzip | **4.22 kB** | ~15 kB |
94
+ | Scenario | Runtime | @office-open/xml | txml (entities) | txml | xml-js | xml (npm) | Bun.XML.stringify |
95
+ | -------------- | ------- | ---------------- | --------------- | --------------- | ------------- | ------------- | ----------------- |
96
+ | simple element | Node 24 | 2,049,617 ops/s | 1,255,456 ops/s | 2,765,770 ops/s | 190,783 ops/s | 303,724 ops/s | — |
97
+ | | Bun 1.4 | 2,588,728 ops/s | 1,721,498 ops/s | 4,248,377 ops/s | 438,430 ops/s | 483,526 ops/s | 584,746 ops/s |
98
+ | complex OOXML | Node 24 | 583,811 ops/s | 447,274 ops/s | 1,326,397 ops/s | 130,335 ops/s | 172,258 ops/s | — |
99
+ | | Bun 1.4 | 510,448 ops/s | 528,375 ops/s | 2,303,173 ops/s | 226,645 ops/s | 292,534 ops/s | 251,444 ops/s |
143
100
 
144
101
  ## License
145
102
 
package/dist/index.d.mts CHANGED
@@ -1,26 +1,15 @@
1
- import { A as XmlObject, C as IgnoreOptions, D as XmlAttrs, E as XmlAtom, O as XmlDesc, S as ElementObject, T as Xml2JsOptions, _ as textOf, a as attrMeasure, b as Element, c as childText, d as colorAttr, f as findChild, g as isNonEmpty, h as hasChild, i as attrBool, j as XmlOption, k as XmlDescArray, l as children, m as findFirst, n as allChildren, o as attrNum, p as findDeep, r as attr, s as childCount, t as NonEmptyArray, u as collectText, v as Attributes, w as Js2XmlOptions, x as ElementCompact, y as DeclarationAttributes } from "./utils-BFKTfRa8.mjs";
2
-
3
- //#region src/serialize.d.ts
4
- declare function xml(input: Record<string, unknown> | Record<string, unknown>[], options?: boolean | string | {
5
- indent?: boolean | string;
6
- declaration?: boolean | {
7
- encoding?: string;
8
- standalone?: string;
9
- };
10
- }): string;
11
- //#endregion
1
+ import { C as IgnoreOptions, S as ElementCompact, T as StringifyOptions, _ as isNonEmpty, a as attrBool, b as DeclarationAttributes, c as childCount, d as collectText, f as colorAttr, g as hasChild, h as findFirst, i as attr, l as childText, m as findDeep, n as OOXML_XML_DECLARATION, o as attrMeasure, p as findChild, r as allChildren, s as attrNum, t as NonEmptyArray, u as children, v as textOf, w as ParseOptions, x as Element, y as Attributes } from "./utils-qhk6IlD8.mjs";
12
2
  //#region src/parse.d.ts
13
3
  declare function unescapeXml(str: string): string;
14
4
  declare function nativeTypeValue(value: string): string | number | boolean;
15
- declare function parse(xmlString: string, options?: Xml2JsOptions): Element;
5
+ declare function parse(xmlString: string, options?: ParseOptions): Element;
16
6
  declare function parseAttributes(str: string): Record<string, string>;
17
7
  //#endregion
18
8
  //#region src/stringify.d.ts
19
- declare function stringify(js: Element, options?: Js2XmlOptions): string;
20
- declare function json2xml(json: Element, options?: Js2XmlOptions): string;
9
+ declare function stringify(js: Element, options?: StringifyOptions): string;
21
10
  //#endregion
22
- //#region src/convert.d.ts
23
- declare function toElement(xmlObject: Record<string, unknown>): Element;
11
+ //#region src/stringify-element.d.ts
12
+ declare function stringifyElement(el: Element): string;
24
13
  //#endregion
25
14
  //#region src/escape.d.ts
26
15
  declare function escapeXml(str: string): string;
@@ -29,8 +18,5 @@ declare function attrsRaw(record: Record<string, string | number | boolean | und
29
18
  declare function selfCloseElement(tag: string, attrStr?: string): string;
30
19
  declare function element(name: string, attrRecord?: Readonly<Record<string, string | number | boolean | undefined>>, children?: readonly string[]): string;
31
20
  //#endregion
32
- //#region src/json.d.ts
33
- declare function xml2json(xml: string, options?: Xml2JsOptions): string;
34
- //#endregion
35
- export { type Attributes, type DeclarationAttributes, type Element, type ElementCompact, type ElementObject, type IgnoreOptions, type Js2XmlOptions, NonEmptyArray, type Xml2JsOptions, type XmlAtom, type XmlAttrs, type XmlDesc, type XmlDescArray, type XmlObject, type XmlOption, allChildren, attr, attrBool, attrMeasure, attrNum, attrs, attrsRaw, childCount, childText, children, collectText, colorAttr, element, escapeXml, findChild, findDeep, findFirst, hasChild, isNonEmpty, stringify as js2xml, stringify, json2xml, nativeTypeValue, parse, parse as xml2js, parseAttributes, selfCloseElement, textOf, toElement, unescapeXml, xml, xml2json };
21
+ export { type Attributes, type DeclarationAttributes, type Element, type ElementCompact, type IgnoreOptions, NonEmptyArray, OOXML_XML_DECLARATION, type ParseOptions, type StringifyOptions, allChildren, attr, attrBool, attrMeasure, attrNum, attrs, attrsRaw, childCount, childText, children, collectText, colorAttr, element, escapeXml, findChild, findDeep, findFirst, hasChild, isNonEmpty, nativeTypeValue, parse, parseAttributes, selfCloseElement, stringify, stringifyElement, textOf, unescapeXml };
36
22
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/serialize.ts","../src/parse.ts","../src/stringify.ts","../src/convert.ts","../src/escape.ts","../src/json.ts"],"mappings":";;;iBASgB,GAAA,CACd,KAAA,EAAO,MAAA,oBAA0B,MAAM,qBACvC,OAAA;EAIM,MAAA;EACA,WAAA;IAA0B,QAAA;IAAmB,UAAA;EAAA;AAAA;;;iBCHrC,WAAA,CAAY,GAAW;AAAA,iBAWvB,eAAA,CAAgB,KAAa;AAAA,iBAa7B,KAAA,CAAM,SAAA,UAAmB,OAAA,GAAU,aAAA,GAAgB,OAAO;AAAA,iBAmN1D,eAAA,CAAgB,GAAA,WAAc,MAAM;;;iBCrPpC,SAAA,CAAU,EAAA,EAAI,OAAA,EAAS,OAAA,GAAU,aAAa;AAAA,iBAmB9C,QAAA,CAAS,IAAA,EAAM,OAAA,EAAS,OAAA,GAAU,aAAa;;;iBChB/C,SAAA,CAAU,SAAA,EAAW,MAAA,oBAA0B,OAAO;;;iBCLtD,SAAA,CAAU,GAAW;AAAA,iBA6CrB,KAAA,CAAM,MAA6D,EAArD,MAAM;AAAA,iBAqBpB,QAAA,CAAS,MAA6D,EAArD,MAAM;AAAA,iBAevB,gBAAA,CAAiB,GAAA,UAAa,OAAgB;AAAA,iBAoB9C,OAAA,CACd,IAAA,UACA,UAAA,GAAa,QAAQ,CAAC,MAAA,kDACtB,QAAA;;;iBCrGc,QAAA,CAAS,GAAA,UAAa,OAAA,GAAU,aAAa"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/parse.ts","../src/stringify.ts","../src/stringify-element.ts","../src/escape.ts"],"mappings":";;iBAagB,YAAY;iBAgBZ,gBAAgB;iBA4ChB,MAAM,mBAAmB,UAAU,eAAe;iBAwXlD,gBAAgB,cAAc;;;iBC1b9B,UAAU,IAAI,SAAS,UAAU;;;iBCIjC,iBAAiB,IAAI;;;iBCPrB,UAAU;iBA6BV,MAAM,QAAQ;iBAsBd,SAAS,QAAQ;iBAejB,iBAAiB,aAAa;iBAoB9B,QACd,cACA,aAAa,SAAS,wDACtB"}