@tradik/xslt-processor 1.0.3 → 1.3.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/LICENSE.md +1 -1
- package/README.md +110 -520
- package/bin/lib/decode.js +15 -0
- package/bin/lib/dom.js +177 -0
- package/bin/lib/loaders.js +127 -0
- package/bin/lib/options.js +131 -0
- package/bin/lib/output.js +114 -0
- package/bin/lib/paths.js +186 -0
- package/bin/lib/transform.js +206 -0
- package/bin/xslt.js +73 -168
- package/dist/xslt-processor.browser.js +9564 -1585
- package/dist/xslt-processor.browser.js.map +4 -4
- package/dist/xslt-processor.browser.min.js +13 -2
- package/dist/xslt-processor.browser.min.js.map +4 -4
- package/dist/xslt-processor.cjs +9572 -1586
- package/dist/xslt-processor.cjs.map +4 -4
- package/dist/xslt-processor.d.cts +658 -0
- package/dist/xslt-processor.d.ts +459 -12
- package/dist/xslt-processor.js +9546 -1582
- package/dist/xslt-processor.js.map +4 -4
- package/package.json +71 -20
- package/src/XSLTProcessor.js +494 -48
- package/src/async/abort.js +63 -0
- package/src/async/documentUris.js +128 -0
- package/src/async/loaders.js +134 -0
- package/src/async/preload.js +159 -0
- package/src/async/processor.js +206 -0
- package/src/async/stream.js +125 -0
- package/src/bridge/engine.js +221 -0
- package/src/bridge/loader.js +78 -0
- package/src/bridge/results.js +75 -0
- package/src/bridge/version.js +63 -0
- package/src/index.js +26 -8
- package/src/io/decode.js +140 -0
- package/src/io/readSource.js +167 -0
- package/src/xpath/axes.js +562 -0
- package/src/xpath/documentOrder.js +270 -0
- package/src/xpath/evaluator.js +518 -357
- package/src/xpath/index.js +8 -2
- package/src/xpath/namespaceNodes.js +172 -0
- package/src/xpath/nodeSetFunctions.js +169 -0
- package/src/xpath/parser.js +30 -5
- package/src/xpath/strings.js +183 -0
- package/src/xpath/tokenizer.js +37 -23
- package/src/xslt/attributeSets.js +95 -0
- package/src/xslt/avt.js +103 -0
- package/src/xslt/computedNames.js +91 -0
- package/src/xslt/copying.js +212 -0
- package/src/xslt/declarationNames.js +80 -0
- package/src/xslt/domParsing.js +95 -0
- package/src/xslt/elements.js +57 -0
- package/src/xslt/engine/bindings.js +195 -0
- package/src/xslt/engine/context.js +105 -0
- package/src/xslt/engine/controlFlow.js +145 -0
- package/src/xslt/engine/copyInstructions.js +133 -0
- package/src/xslt/engine/declarations.js +233 -0
- package/src/xslt/engine/functionSupport.js +103 -0
- package/src/xslt/engine/methods.js +33 -0
- package/src/xslt/engine/nodeConstruction.js +187 -0
- package/src/xslt/engine/numbering.js +104 -0
- package/src/xslt/engine/outputDeclaration.js +77 -0
- package/src/xslt/engine/sequenceConstructor.js +228 -0
- package/src/xslt/engine/stylesheetLoading.js +208 -0
- package/src/xslt/engine/templateInvocation.js +253 -0
- package/src/xslt/engine/templateRules.js +243 -0
- package/src/xslt/engine/textInstructions.js +171 -0
- package/src/xslt/engine/topLevel.js +130 -0
- package/src/xslt/engine/transformation.js +263 -0
- package/src/xslt/engine/workStack.js +245 -0
- package/src/xslt/engine.js +184 -1736
- package/src/xslt/exslt/arguments.js +99 -0
- package/src/xslt/exslt/calendar.js +120 -0
- package/src/xslt/exslt/common.js +44 -0
- package/src/xslt/exslt/dateCalc.js +261 -0
- package/src/xslt/exslt/dateFormat.js +150 -0
- package/src/xslt/exslt/dateParse.js +265 -0
- package/src/xslt/exslt/dates.js +259 -0
- package/src/xslt/exslt/duration.js +207 -0
- package/src/xslt/exslt/dynamic.js +59 -0
- package/src/xslt/exslt/index.js +59 -0
- package/src/xslt/exslt/math.js +177 -0
- package/src/xslt/exslt/sets.js +96 -0
- package/src/xslt/exslt/stringOps.js +163 -0
- package/src/xslt/exslt/strings.js +147 -0
- package/src/xslt/exslt/uri.js +92 -0
- package/src/xslt/formatNumber.js +233 -0
- package/src/xslt/forwardsCompatible.js +75 -0
- package/src/xslt/functions.js +270 -0
- package/src/xslt/index.js +38 -1
- package/src/xslt/keys.js +164 -0
- package/src/xslt/literalResult.js +223 -0
- package/src/xslt/matchScope.js +116 -0
- package/src/xslt/number.js +271 -0
- package/src/xslt/numberFormat.js +253 -0
- package/src/xslt/outputNames.js +58 -0
- package/src/xslt/patternCompiler.js +175 -0
- package/src/xslt/patterns.js +324 -0
- package/src/xslt/qname.js +90 -0
- package/src/xslt/resultDocument.js +98 -0
- package/src/xslt/resultNamespaces.js +219 -0
- package/src/xslt/resultTree.js +211 -0
- package/src/xslt/serializer/baseWriter.js +390 -0
- package/src/xslt/serializer/chunks.js +120 -0
- package/src/xslt/serializer/constants.js +92 -0
- package/src/xslt/serializer/encoding.js +327 -0
- package/src/xslt/serializer/escape.js +135 -0
- package/src/xslt/serializer/frames.js +168 -0
- package/src/xslt/serializer/htmlDoctype.js +102 -0
- package/src/xslt/serializer/htmlEntities.js +77 -0
- package/src/xslt/serializer/htmlSerializer.js +239 -0
- package/src/xslt/serializer/indent.js +51 -0
- package/src/xslt/serializer/namespaces.js +68 -0
- package/src/xslt/serializer/rawText.js +41 -0
- package/src/xslt/serializer/settings.js +179 -0
- package/src/xslt/serializer/textSerializer.js +77 -0
- package/src/xslt/serializer/xhtmlDocument.js +103 -0
- package/src/xslt/serializer/xmlSerializer.js +227 -0
- package/src/xslt/serializer.js +90 -0
- package/src/xslt/sort.js +151 -0
- package/src/xslt/spaceNameTests.js +115 -0
- package/src/xslt/stylesheetChecks.js +206 -0
- package/src/xslt/stylesheetNamespaces.js +266 -0
- package/src/xslt/templatePriority.js +45 -0
- package/src/xslt/uri.js +68 -0
- package/src/xslt/variables.js +152 -0
- package/src/xslt/whitespace.js +200 -0
- package/LICENSE +0 -29
- package/src/XSLTProcessor.test.js +0 -930
- package/src/xpath/evaluator.test.js +0 -1852
- package/src/xpath/tokenizer.test.js +0 -224
- package/src/xslt/engine.test.js +0 -3130
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document order of nodes that are not children of their parent: attributes
|
|
3
|
+
* and synthesized namespace nodes (XPath 1.0 section 5).
|
|
4
|
+
*
|
|
5
|
+
* An element comes first, then its namespace nodes, then its attributes, then
|
|
6
|
+
* its children. `Node.compareDocumentPosition` cannot order namespace nodes,
|
|
7
|
+
* which are not DOM nodes, and jsdom reports an element and one of its own
|
|
8
|
+
* attributes as equal, so both kinds are ordered through their element here.
|
|
9
|
+
*
|
|
10
|
+
* Browsers implement `compareDocumentPosition` natively. The JavaScript DOMs
|
|
11
|
+
* of Node.js walk the ancestors of both nodes on every call, and xmldom also
|
|
12
|
+
* looks each ancestor up in its parent's child list, which makes sorting a
|
|
13
|
+
* large node-set take minutes; some DOMs have no such method at all. A
|
|
14
|
+
* {@link DocumentOrderIndex} numbers the nodes of a tree once instead, in one
|
|
15
|
+
* walk, and sorts node-sets by those numbers: the XSLT engine uses one per
|
|
16
|
+
* transformation (the source tree does not change while it runs) unless the
|
|
17
|
+
* DOM compares positions natively.
|
|
18
|
+
*
|
|
19
|
+
* @module xpath/documentOrder
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
"use strict";
|
|
23
|
+
|
|
24
|
+
import { NAMESPACE_NODE } from "./namespaceNodes.js";
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Rank of a node among the nodes anchored at the same element: the element,
|
|
28
|
+
* its namespace nodes, its attributes.
|
|
29
|
+
*
|
|
30
|
+
* @param {Node} node - Any node
|
|
31
|
+
* @returns {number} 0 for the element (or any other node), 1 for a namespace
|
|
32
|
+
* node, 2 for an attribute
|
|
33
|
+
*/
|
|
34
|
+
function rankOf(node) {
|
|
35
|
+
const type = node.nodeType;
|
|
36
|
+
if (type === NAMESPACE_NODE) return 1;
|
|
37
|
+
return type === 2 ? 2 : 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The node whose position in the tree stands for a node: the element of an
|
|
42
|
+
* attached attribute or namespace node, else the node itself.
|
|
43
|
+
*
|
|
44
|
+
* @param {Node} node - Any node
|
|
45
|
+
* @param {number} rank - The node's rank (see rankOf)
|
|
46
|
+
* @returns {Node} The anchor
|
|
47
|
+
*/
|
|
48
|
+
function anchorOf(node, rank) {
|
|
49
|
+
return rank === 0 ? node : (node.ownerElement ?? node);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Compare two distinct nodes in document order.
|
|
54
|
+
*
|
|
55
|
+
* @param {Node} a - First node
|
|
56
|
+
* @param {Node} b - Second node
|
|
57
|
+
* @param {(a: Node, b: Node) => number} compareDom - Order of two DOM nodes
|
|
58
|
+
* in different positions of the tree (compareDocumentPosition based)
|
|
59
|
+
* @returns {number} Negative when a comes first, positive when b does
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* compareNodeOrder(attribute, ownerElement, compareDom); // 1
|
|
63
|
+
*/
|
|
64
|
+
export function compareNodeOrder(a, b, compareDom) {
|
|
65
|
+
const rankA = rankOf(a);
|
|
66
|
+
const rankB = rankOf(b);
|
|
67
|
+
if (rankA === 0 && rankB === 0) return compareDom(a, b);
|
|
68
|
+
const anchorA = anchorOf(a, rankA);
|
|
69
|
+
const anchorB = anchorOf(b, rankB);
|
|
70
|
+
if (anchorA !== anchorB) return compareDom(anchorA, anchorB);
|
|
71
|
+
if (rankA !== rankB) return rankA - rankB;
|
|
72
|
+
// Two namespace nodes, or two attributes, of the same element
|
|
73
|
+
return rankA === 1 ? a.index - b.index : compareDom(a, b);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Order of two DOM nodes in different positions of a tree, from
|
|
78
|
+
* `compareDocumentPosition`.
|
|
79
|
+
*
|
|
80
|
+
* @param {Node} a - First node
|
|
81
|
+
* @param {Node} b - Second node
|
|
82
|
+
* @returns {number} -1 when a comes first, 1 when b does, 0 when the DOM
|
|
83
|
+
* gives no order
|
|
84
|
+
*/
|
|
85
|
+
export function compareDomPositions(a, b) {
|
|
86
|
+
const position = a.compareDocumentPosition(b);
|
|
87
|
+
if (position & 4) return -1; // b follows a
|
|
88
|
+
if (position & 2) return 1; // b precedes a
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Whether a node's DOM compares positions in native code (browsers), as
|
|
94
|
+
* opposed to a JavaScript implementation (jsdom, xmldom) or none.
|
|
95
|
+
*
|
|
96
|
+
* @param {Node} node - A DOM node
|
|
97
|
+
* @returns {boolean} True for a built-in `compareDocumentPosition`
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* hasNativePositionComparison(document.body); // true in a browser
|
|
101
|
+
*/
|
|
102
|
+
export function hasNativePositionComparison(node) {
|
|
103
|
+
const compare = node.compareDocumentPosition;
|
|
104
|
+
return (
|
|
105
|
+
typeof compare === "function" &&
|
|
106
|
+
Function.prototype.toString.call(compare).includes("[native code]")
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The topmost ancestor of a node.
|
|
112
|
+
*
|
|
113
|
+
* @param {Node} node - A DOM node
|
|
114
|
+
* @returns {Node} The document, or the root of a detached tree
|
|
115
|
+
*/
|
|
116
|
+
function rootOf(node) {
|
|
117
|
+
let root = node;
|
|
118
|
+
while (root.parentNode) root = root.parentNode;
|
|
119
|
+
return root;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Sort key offset of attributes among the nodes anchored at an element:
|
|
124
|
+
* after the element (0) and its namespace nodes (1 + index).
|
|
125
|
+
*/
|
|
126
|
+
const ATTRIBUTE_KEY = 2 ** 30;
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Document order positions of DOM nodes, computed tree by tree.
|
|
130
|
+
*
|
|
131
|
+
* The first time a node of a tree is looked up, the whole tree is numbered
|
|
132
|
+
* in document order (attributes are not: they are ordered through their
|
|
133
|
+
* element, and among themselves by their index in the element's attribute
|
|
134
|
+
* list, looked up only when two attributes of one element are sorted). Trees are numbered in
|
|
135
|
+
* the order they are first seen, so nodes of different documents have a
|
|
136
|
+
* stable, implementation-defined order (XPath 1.0 section 5). A node added
|
|
137
|
+
* to a tree after it was numbered makes the tree numbered again; nodes
|
|
138
|
+
* moved within a numbered tree are not noticed, so an index must not
|
|
139
|
+
* outlive changes to its trees.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* const order = new DocumentOrderIndex();
|
|
143
|
+
* order.sort([lastChild, firstChild]); // [firstChild, lastChild]
|
|
144
|
+
*/
|
|
145
|
+
export class DocumentOrderIndex {
|
|
146
|
+
constructor() {
|
|
147
|
+
/** @type {WeakMap<Node, number>} */
|
|
148
|
+
this.positions = new WeakMap();
|
|
149
|
+
/** @type {WeakMap<Attr, number>} */
|
|
150
|
+
this.attributeIndexes = new WeakMap();
|
|
151
|
+
this.nextPosition = 0;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The position of a tree node in document order.
|
|
156
|
+
*
|
|
157
|
+
* @param {Node} node - A DOM node, not an attribute of an element nor a
|
|
158
|
+
* namespace node (see {@link DocumentOrderIndex#sort})
|
|
159
|
+
* @returns {number} Its position; larger for later nodes
|
|
160
|
+
*/
|
|
161
|
+
positionOf(node) {
|
|
162
|
+
let position = this.positions.get(node);
|
|
163
|
+
if (position === undefined) {
|
|
164
|
+
this.numberTree(rootOf(node));
|
|
165
|
+
position = this.positions.get(node);
|
|
166
|
+
}
|
|
167
|
+
return position ?? this.assign(node);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Give a node the next position.
|
|
172
|
+
*
|
|
173
|
+
* @param {Node} node - A DOM node
|
|
174
|
+
* @returns {number} The assigned position
|
|
175
|
+
*/
|
|
176
|
+
assign(node) {
|
|
177
|
+
const position = this.nextPosition++;
|
|
178
|
+
this.positions.set(node, position);
|
|
179
|
+
return position;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Number a tree in document order, without recursion (deep trees).
|
|
184
|
+
*
|
|
185
|
+
* @param {Node} root - The root of the tree
|
|
186
|
+
* @returns {void}
|
|
187
|
+
*/
|
|
188
|
+
numberTree(root) {
|
|
189
|
+
let node = root;
|
|
190
|
+
for (;;) {
|
|
191
|
+
this.assign(node);
|
|
192
|
+
if (node.firstChild) {
|
|
193
|
+
node = node.firstChild;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
while (node !== root && !node.nextSibling) node = node.parentNode;
|
|
197
|
+
if (node === root) return;
|
|
198
|
+
node = node.nextSibling;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* The index of an attribute in the attribute list of its element.
|
|
204
|
+
*
|
|
205
|
+
* @param {Attr} attribute - An attribute with an ownerElement
|
|
206
|
+
* @returns {number} Its index (0 when the element does not list it)
|
|
207
|
+
*/
|
|
208
|
+
attributeIndexOf(attribute) {
|
|
209
|
+
let index = this.attributeIndexes.get(attribute);
|
|
210
|
+
if (index === undefined) {
|
|
211
|
+
const attributes = attribute.ownerElement.attributes;
|
|
212
|
+
for (let i = 0; i < attributes.length; i++) {
|
|
213
|
+
this.attributeIndexes.set(attributes[i], i);
|
|
214
|
+
}
|
|
215
|
+
index = this.attributeIndexes.get(attribute) ?? 0;
|
|
216
|
+
}
|
|
217
|
+
return index;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The sort key of a node: the position of the node, or of the element it
|
|
222
|
+
* hangs off, then its rank among the nodes anchored at that element. All
|
|
223
|
+
* attributes of an element share one key (see
|
|
224
|
+
* {@link DocumentOrderIndex#compareKeys}): walking the attribute list of
|
|
225
|
+
* every element up front would dominate sorting `$items/@v`, where no two
|
|
226
|
+
* attributes share an element.
|
|
227
|
+
*
|
|
228
|
+
* @param {Node} node - A DOM node or namespace node
|
|
229
|
+
* @returns {{node: Node, major: number, minor: number}} The key
|
|
230
|
+
*/
|
|
231
|
+
keyOf(node) {
|
|
232
|
+
if (node.nodeType === NAMESPACE_NODE) {
|
|
233
|
+
const major = this.positionOf(node.ownerElement);
|
|
234
|
+
return { node, major, minor: 1 + node.index };
|
|
235
|
+
}
|
|
236
|
+
if (node.nodeType === 2 && node.ownerElement) {
|
|
237
|
+
const major = this.positionOf(node.ownerElement);
|
|
238
|
+
return { node, major, minor: ATTRIBUTE_KEY };
|
|
239
|
+
}
|
|
240
|
+
return { node, major: this.positionOf(node), minor: 0 };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Order of two sort keys; attributes of the same element are ordered by
|
|
245
|
+
* their index in its attribute list, looked up only for such a tie.
|
|
246
|
+
*
|
|
247
|
+
* @param {{node: Node, major: number, minor: number}} a - First key
|
|
248
|
+
* @param {{node: Node, major: number, minor: number}} b - Second key
|
|
249
|
+
* @returns {number} Negative when a comes first, positive when b does
|
|
250
|
+
*/
|
|
251
|
+
compareKeys(a, b) {
|
|
252
|
+
const order = a.major - b.major || a.minor - b.minor;
|
|
253
|
+
if (order !== 0 || a.minor !== ATTRIBUTE_KEY) return order;
|
|
254
|
+
return this.attributeIndexOf(a.node) - this.attributeIndexOf(b.node);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Sort nodes in document order: an element, then its namespace nodes (by
|
|
259
|
+
* index), then its attributes, then its children.
|
|
260
|
+
*
|
|
261
|
+
* @param {Node[]} nodes - DOM nodes and namespace nodes, sorted in place
|
|
262
|
+
* @returns {Node[]} The same array
|
|
263
|
+
*/
|
|
264
|
+
sort(nodes) {
|
|
265
|
+
const keyed = nodes.map((node) => this.keyOf(node));
|
|
266
|
+
keyed.sort((a, b) => this.compareKeys(a, b));
|
|
267
|
+
for (let i = 0; i < keyed.length; i++) nodes[i] = keyed[i].node;
|
|
268
|
+
return nodes;
|
|
269
|
+
}
|
|
270
|
+
}
|