@tradik/xslt-processor 1.0.2 → 1.1.1

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.
Files changed (47) hide show
  1. package/README.md +292 -47
  2. package/bin/lib/options.js +114 -0
  3. package/bin/lib/paths.js +186 -0
  4. package/bin/lib/transform.js +115 -0
  5. package/bin/xslt.js +68 -162
  6. package/dist/xslt-processor.browser.js +2073 -163
  7. package/dist/xslt-processor.browser.js.map +4 -4
  8. package/dist/xslt-processor.browser.min.js +6 -2
  9. package/dist/xslt-processor.browser.min.js.map +4 -4
  10. package/dist/xslt-processor.cjs +2077 -162
  11. package/dist/xslt-processor.cjs.map +4 -4
  12. package/dist/xslt-processor.d.cts +299 -0
  13. package/dist/xslt-processor.d.ts +92 -4
  14. package/dist/xslt-processor.js +2072 -161
  15. package/dist/xslt-processor.js.map +4 -4
  16. package/package.json +27 -16
  17. package/src/XSLTProcessor.js +177 -8
  18. package/src/index.js +11 -5
  19. package/src/xpath/evaluator.js +48 -7
  20. package/src/xslt/elements.js +57 -0
  21. package/src/xslt/engine.js +474 -185
  22. package/src/xslt/formatNumber.js +220 -0
  23. package/src/xslt/functions.js +191 -0
  24. package/src/xslt/index.js +31 -0
  25. package/src/xslt/keys.js +141 -0
  26. package/src/xslt/literalResult.js +167 -0
  27. package/src/xslt/number.js +178 -0
  28. package/src/xslt/numberFormat.js +155 -0
  29. package/src/xslt/resultTree.js +74 -0
  30. package/src/xslt/serializer/baseWriter.js +283 -0
  31. package/src/xslt/serializer/constants.js +78 -0
  32. package/src/xslt/serializer/escape.js +98 -0
  33. package/src/xslt/serializer/htmlSerializer.js +141 -0
  34. package/src/xslt/serializer/indent.js +51 -0
  35. package/src/xslt/serializer/namespaces.js +68 -0
  36. package/src/xslt/serializer/rawText.js +41 -0
  37. package/src/xslt/serializer/settings.js +103 -0
  38. package/src/xslt/serializer/textSerializer.js +29 -0
  39. package/src/xslt/serializer/xmlSerializer.js +127 -0
  40. package/src/xslt/serializer.js +57 -0
  41. package/src/xslt/templatePriority.js +45 -0
  42. package/src/xslt/uri.js +68 -0
  43. package/src/xslt/whitespace.js +184 -0
  44. package/src/XSLTProcessor.test.js +0 -930
  45. package/src/xpath/evaluator.test.js +0 -1852
  46. package/src/xpath/tokenizer.test.js +0 -224
  47. package/src/xslt/engine.test.js +0 -3130
@@ -1,930 +0,0 @@
1
- /**
2
- * XSLTProcessor Tests
3
- *
4
- * Tests for JavaScript XSLTProcessor implementation.
5
- */
6
-
7
- import { describe, it, beforeEach } from "node:test";
8
- import assert from "node:assert";
9
- import { JSDOM } from "jsdom";
10
- import {
11
- XSLTProcessor,
12
- isNativeXSLTSupported,
13
- installGlobal,
14
- } from "./XSLTProcessor.js";
15
-
16
- // Setup JSDOM environment
17
- function setupDOM() {
18
- const dom = new JSDOM("<!DOCTYPE html><html><body></body></html>", {
19
- contentType: "text/html",
20
- });
21
-
22
- global.document = dom.window.document;
23
- global.DOMParser = dom.window.DOMParser;
24
- global.XMLSerializer = dom.window.XMLSerializer;
25
-
26
- return dom;
27
- }
28
-
29
- function parseXML(xmlString) {
30
- const parser = new DOMParser();
31
- return parser.parseFromString(xmlString, "application/xml");
32
- }
33
-
34
- describe("XSLTProcessor", () => {
35
- beforeEach(() => {
36
- setupDOM();
37
- });
38
-
39
- describe("Constructor", () => {
40
- it("should create a new XSLTProcessor instance", () => {
41
- const processor = new XSLTProcessor();
42
- assert.ok(processor instanceof XSLTProcessor);
43
- });
44
- });
45
-
46
- describe("importStylesheet", () => {
47
- it("should import a valid XSLT stylesheet", () => {
48
- const processor = new XSLTProcessor();
49
- const xslt = parseXML(`<?xml version="1.0"?>
50
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
51
- <xsl:template match="/">
52
- <html><body>Hello</body></html>
53
- </xsl:template>
54
- </xsl:stylesheet>
55
- `);
56
-
57
- assert.doesNotThrow(() => {
58
- processor.importStylesheet(xslt);
59
- });
60
- });
61
-
62
- it("should throw when no argument provided", () => {
63
- const processor = new XSLTProcessor();
64
- assert.throws(() => {
65
- processor.importStylesheet();
66
- }, /1 argument required/);
67
- });
68
-
69
- it("should throw for invalid node type", () => {
70
- const processor = new XSLTProcessor();
71
- assert.throws(() => {
72
- processor.importStylesheet(document.createTextNode("text"));
73
- }, /not a Document or Element/);
74
- });
75
- });
76
-
77
- describe("transformToFragment", () => {
78
- it("should transform XML to fragment", () => {
79
- const processor = new XSLTProcessor();
80
-
81
- const xslt = parseXML(`<?xml version="1.0"?>
82
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
83
- <xsl:template match="/">
84
- <div class="result">
85
- <xsl:value-of select="/root/item"/>
86
- </div>
87
- </xsl:template>
88
- </xsl:stylesheet>
89
- `);
90
-
91
- const xml = parseXML(`<?xml version="1.0"?>
92
- <root>
93
- <item>Hello World</item>
94
- </root>
95
- `);
96
-
97
- processor.importStylesheet(xslt);
98
- const fragment = processor.transformToFragment(xml, document);
99
-
100
- assert.ok(fragment);
101
- assert.ok(fragment.nodeType === 11); // DocumentFragment
102
- });
103
-
104
- it("should throw when no stylesheet imported", () => {
105
- const processor = new XSLTProcessor();
106
- const xml = parseXML("<root/>");
107
-
108
- assert.throws(() => {
109
- processor.transformToFragment(xml, document);
110
- }, /No stylesheet/);
111
- });
112
-
113
- it("should throw when missing arguments", () => {
114
- const processor = new XSLTProcessor();
115
- const xslt = parseXML(`<?xml version="1.0"?>
116
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
117
- <xsl:template match="/"><out/></xsl:template>
118
- </xsl:stylesheet>
119
- `);
120
-
121
- processor.importStylesheet(xslt);
122
-
123
- assert.throws(() => {
124
- processor.transformToFragment();
125
- }, /2 arguments required/);
126
- });
127
- });
128
-
129
- describe("transformToDocument", () => {
130
- it("should transform XML to document", () => {
131
- const processor = new XSLTProcessor();
132
-
133
- const xslt = parseXML(`<?xml version="1.0"?>
134
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
135
- <xsl:template match="/">
136
- <result>
137
- <xsl:value-of select="/root/item"/>
138
- </result>
139
- </xsl:template>
140
- </xsl:stylesheet>
141
- `);
142
-
143
- const xml = parseXML(`<?xml version="1.0"?>
144
- <root>
145
- <item>Test</item>
146
- </root>
147
- `);
148
-
149
- processor.importStylesheet(xslt);
150
- const result = processor.transformToDocument(xml);
151
-
152
- assert.ok(result);
153
- });
154
-
155
- it("should throw when no stylesheet imported", () => {
156
- const processor = new XSLTProcessor();
157
- const xml = parseXML("<root/>");
158
-
159
- assert.throws(() => {
160
- processor.transformToDocument(xml);
161
- }, /No stylesheet/);
162
- });
163
- });
164
-
165
- describe("Parameters", () => {
166
- it("should set and get parameter", () => {
167
- const processor = new XSLTProcessor();
168
-
169
- processor.setParameter(null, "myParam", "myValue");
170
- const value = processor.getParameter(null, "myParam");
171
-
172
- assert.strictEqual(value, "myValue");
173
- });
174
-
175
- it("should set parameter with namespace", () => {
176
- const processor = new XSLTProcessor();
177
-
178
- processor.setParameter("http://example.com", "param", "value");
179
- const value = processor.getParameter("http://example.com", "param");
180
-
181
- assert.strictEqual(value, "value");
182
- });
183
-
184
- it("should return empty string for unset parameter", () => {
185
- const processor = new XSLTProcessor();
186
- const value = processor.getParameter(null, "nonexistent");
187
- assert.strictEqual(value, "");
188
- });
189
-
190
- it("should remove parameter", () => {
191
- const processor = new XSLTProcessor();
192
-
193
- processor.setParameter(null, "param", "value");
194
- processor.removeParameter(null, "param");
195
- const value = processor.getParameter(null, "param");
196
-
197
- assert.strictEqual(value, "");
198
- });
199
-
200
- it("should clear all parameters", () => {
201
- const processor = new XSLTProcessor();
202
-
203
- processor.setParameter(null, "param1", "value1");
204
- processor.setParameter(null, "param2", "value2");
205
- processor.clearParameters();
206
-
207
- assert.strictEqual(processor.getParameter(null, "param1"), "");
208
- assert.strictEqual(processor.getParameter(null, "param2"), "");
209
- });
210
-
211
- it("should throw when setParameter has insufficient arguments", () => {
212
- const processor = new XSLTProcessor();
213
- assert.throws(() => {
214
- processor.setParameter(null, "param");
215
- }, /3 arguments required/);
216
- });
217
-
218
- it("should throw when getParameter has insufficient arguments", () => {
219
- const processor = new XSLTProcessor();
220
- assert.throws(() => {
221
- processor.getParameter(null);
222
- }, /2 arguments required/);
223
- });
224
- });
225
-
226
- describe("reset", () => {
227
- it("should reset processor state", () => {
228
- const processor = new XSLTProcessor();
229
-
230
- const xslt = parseXML(`<?xml version="1.0"?>
231
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
232
- <xsl:template match="/"><out/></xsl:template>
233
- </xsl:stylesheet>
234
- `);
235
-
236
- processor.importStylesheet(xslt);
237
- processor.setParameter(null, "param", "value");
238
- processor.reset();
239
-
240
- assert.strictEqual(processor.getParameter(null, "param"), "");
241
-
242
- const xml = parseXML("<root/>");
243
- assert.throws(() => {
244
- processor.transformToFragment(xml, document);
245
- }, /No stylesheet/);
246
- });
247
- });
248
-
249
- describe("XSLT Features", () => {
250
- it("should handle xsl:value-of", () => {
251
- const processor = new XSLTProcessor();
252
-
253
- const xslt = parseXML(`<?xml version="1.0"?>
254
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
255
- <xsl:template match="/">
256
- <p><xsl:value-of select="/root/text"/></p>
257
- </xsl:template>
258
- </xsl:stylesheet>
259
- `);
260
-
261
- const xml = parseXML(`<root><text>Hello</text></root>`);
262
-
263
- processor.importStylesheet(xslt);
264
- const fragment = processor.transformToFragment(xml, document);
265
-
266
- assert.ok(fragment);
267
- const p = fragment.querySelector("p");
268
- assert.ok(p);
269
- assert.strictEqual(p.textContent, "Hello");
270
- });
271
-
272
- it("should handle xsl:for-each", () => {
273
- const processor = new XSLTProcessor();
274
-
275
- const xslt = parseXML(`<?xml version="1.0"?>
276
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
277
- <xsl:template match="/">
278
- <ul>
279
- <xsl:for-each select="/root/item">
280
- <li><xsl:value-of select="."/></li>
281
- </xsl:for-each>
282
- </ul>
283
- </xsl:template>
284
- </xsl:stylesheet>
285
- `);
286
-
287
- const xml = parseXML(`
288
- <root>
289
- <item>One</item>
290
- <item>Two</item>
291
- <item>Three</item>
292
- </root>
293
- `);
294
-
295
- processor.importStylesheet(xslt);
296
- const fragment = processor.transformToFragment(xml, document);
297
-
298
- const items = fragment.querySelectorAll("li");
299
- assert.strictEqual(items.length, 3);
300
- });
301
-
302
- it("should handle xsl:if", () => {
303
- const processor = new XSLTProcessor();
304
-
305
- const xslt = parseXML(`<?xml version="1.0"?>
306
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
307
- <xsl:template match="/">
308
- <xsl:if test="/root/show">
309
- <p>Visible</p>
310
- </xsl:if>
311
- </xsl:template>
312
- </xsl:stylesheet>
313
- `);
314
-
315
- const xmlWithShow = parseXML(`<root><show/></root>`);
316
- const xmlWithoutShow = parseXML(`<root></root>`);
317
-
318
- processor.importStylesheet(xslt);
319
-
320
- const fragment1 = processor.transformToFragment(xmlWithShow, document);
321
- assert.ok(fragment1.querySelector("p"));
322
-
323
- const fragment2 = processor.transformToFragment(xmlWithoutShow, document);
324
- assert.ok(!fragment2.querySelector("p"));
325
- });
326
-
327
- it("should handle xsl:choose", () => {
328
- const processor = new XSLTProcessor();
329
-
330
- const xslt = parseXML(`<?xml version="1.0"?>
331
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
332
- <xsl:template match="/">
333
- <xsl:choose>
334
- <xsl:when test="/root/type = 'a'">
335
- <p>Type A</p>
336
- </xsl:when>
337
- <xsl:when test="/root/type = 'b'">
338
- <p>Type B</p>
339
- </xsl:when>
340
- <xsl:otherwise>
341
- <p>Unknown</p>
342
- </xsl:otherwise>
343
- </xsl:choose>
344
- </xsl:template>
345
- </xsl:stylesheet>
346
- `);
347
-
348
- const xml = parseXML(`<root><type>b</type></root>`);
349
-
350
- processor.importStylesheet(xslt);
351
- const fragment = processor.transformToFragment(xml, document);
352
-
353
- const p = fragment.querySelector("p");
354
- assert.strictEqual(p.textContent, "Type B");
355
- });
356
-
357
- it("should handle xsl:apply-templates", () => {
358
- const processor = new XSLTProcessor();
359
-
360
- const xslt = parseXML(`<?xml version="1.0"?>
361
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
362
- <xsl:template match="/">
363
- <div><xsl:apply-templates select="/root/item"/></div>
364
- </xsl:template>
365
- <xsl:template match="item">
366
- <span><xsl:value-of select="."/></span>
367
- </xsl:template>
368
- </xsl:stylesheet>
369
- `);
370
-
371
- const xml = parseXML(`
372
- <root>
373
- <item>A</item>
374
- <item>B</item>
375
- </root>
376
- `);
377
-
378
- processor.importStylesheet(xslt);
379
- const fragment = processor.transformToFragment(xml, document);
380
-
381
- const spans = fragment.querySelectorAll("span");
382
- assert.strictEqual(spans.length, 2);
383
- });
384
-
385
- it("should handle xsl:call-template", () => {
386
- const processor = new XSLTProcessor();
387
-
388
- const xslt = parseXML(`<?xml version="1.0"?>
389
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
390
- <xsl:template match="/">
391
- <xsl:call-template name="greeting">
392
- <xsl:with-param name="name" select="/root/name"/>
393
- </xsl:call-template>
394
- </xsl:template>
395
- <xsl:template name="greeting">
396
- <xsl:param name="name"/>
397
- <p>Hello, <xsl:value-of select="$name"/>!</p>
398
- </xsl:template>
399
- </xsl:stylesheet>
400
- `);
401
-
402
- const xml = parseXML(`<root><name>World</name></root>`);
403
-
404
- processor.importStylesheet(xslt);
405
- const fragment = processor.transformToFragment(xml, document);
406
-
407
- const p = fragment.querySelector("p");
408
- assert.ok(p.textContent.includes("Hello"));
409
- assert.ok(p.textContent.includes("World"));
410
- });
411
-
412
- it("should handle xsl:copy-of", () => {
413
- const processor = new XSLTProcessor();
414
-
415
- const xslt = parseXML(`<?xml version="1.0"?>
416
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
417
- <xsl:template match="/">
418
- <div>
419
- <xsl:copy-of select="/root/content/*"/>
420
- </div>
421
- </xsl:template>
422
- </xsl:stylesheet>
423
- `);
424
-
425
- const xml = parseXML(`
426
- <root>
427
- <content>
428
- <p>Paragraph</p>
429
- <span>Span</span>
430
- </content>
431
- </root>
432
- `);
433
-
434
- processor.importStylesheet(xslt);
435
- const fragment = processor.transformToFragment(xml, document);
436
-
437
- assert.ok(fragment.querySelector("p"));
438
- assert.ok(fragment.querySelector("span"));
439
- });
440
-
441
- it("should handle xsl:attribute", () => {
442
- const processor = new XSLTProcessor();
443
-
444
- const xslt = parseXML(`<?xml version="1.0"?>
445
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
446
- <xsl:template match="/">
447
- <div>
448
- <xsl:attribute name="class">
449
- <xsl:value-of select="/root/className"/>
450
- </xsl:attribute>
451
- Content
452
- </div>
453
- </xsl:template>
454
- </xsl:stylesheet>
455
- `);
456
-
457
- const xml = parseXML(`<root><className>my-class</className></root>`);
458
-
459
- processor.importStylesheet(xslt);
460
- const fragment = processor.transformToFragment(xml, document);
461
-
462
- const div = fragment.querySelector("div");
463
- assert.strictEqual(div.getAttribute("class"), "my-class");
464
- });
465
-
466
- it("should handle attribute value templates", () => {
467
- const processor = new XSLTProcessor();
468
-
469
- const xslt = parseXML(`<?xml version="1.0"?>
470
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
471
- <xsl:template match="/">
472
- <a href="/item/{/root/id}">Link</a>
473
- </xsl:template>
474
- </xsl:stylesheet>
475
- `);
476
-
477
- const xml = parseXML(`<root><id>123</id></root>`);
478
-
479
- processor.importStylesheet(xslt);
480
- const fragment = processor.transformToFragment(xml, document);
481
-
482
- const a = fragment.querySelector("a");
483
- assert.strictEqual(a.getAttribute("href"), "/item/123");
484
- });
485
-
486
- it("should handle xsl:sort", () => {
487
- const processor = new XSLTProcessor();
488
-
489
- const xslt = parseXML(`<?xml version="1.0"?>
490
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
491
- <xsl:template match="/">
492
- <ul>
493
- <xsl:for-each select="/root/item">
494
- <xsl:sort select="@name"/>
495
- <li><xsl:value-of select="@name"/></li>
496
- </xsl:for-each>
497
- </ul>
498
- </xsl:template>
499
- </xsl:stylesheet>
500
- `);
501
-
502
- const xml = parseXML(`
503
- <root>
504
- <item name="Charlie"/>
505
- <item name="Alice"/>
506
- <item name="Bob"/>
507
- </root>
508
- `);
509
-
510
- processor.importStylesheet(xslt);
511
- const fragment = processor.transformToFragment(xml, document);
512
-
513
- const items = fragment.querySelectorAll("li");
514
- assert.strictEqual(items[0].textContent, "Alice");
515
- assert.strictEqual(items[1].textContent, "Bob");
516
- assert.strictEqual(items[2].textContent, "Charlie");
517
- });
518
- });
519
-
520
- describe("Utility Functions", () => {
521
- it("isNativeXSLTSupported should return boolean", () => {
522
- const result = isNativeXSLTSupported();
523
- assert.strictEqual(typeof result, "boolean");
524
- });
525
-
526
- it("installGlobal with force should work", () => {
527
- const result = installGlobal(true);
528
- assert.strictEqual(typeof result, "boolean");
529
- });
530
-
531
- it("installGlobal without force when native not supported", () => {
532
- // Save original
533
- const original = globalThis.XSLTProcessor;
534
- delete globalThis.XSLTProcessor;
535
-
536
- const result = installGlobal(false);
537
-
538
- // Restore
539
- if (original) {
540
- globalThis.XSLTProcessor = original;
541
- }
542
-
543
- assert.strictEqual(typeof result, "boolean");
544
- });
545
-
546
- it("isNativeXSLTSupported should return true with working mock native", () => {
547
- // Save original
548
- const original = globalThis.XSLTProcessor;
549
-
550
- // Create a mock native XSLTProcessor that works
551
- class MockNativeXSLTProcessor {
552
- importStylesheet() {}
553
- transformToFragment() {
554
- // Return a mock fragment with childNodes
555
- const fragment = document.createDocumentFragment();
556
- fragment.appendChild(document.createElement("test"));
557
- return fragment;
558
- }
559
- }
560
-
561
- globalThis.XSLTProcessor = MockNativeXSLTProcessor;
562
-
563
- const result = isNativeXSLTSupported();
564
-
565
- // Restore
566
- globalThis.XSLTProcessor = original;
567
-
568
- assert.strictEqual(result, true);
569
- });
570
-
571
- it("isNativeXSLTSupported should return false when native throws", () => {
572
- // Save original
573
- const original = globalThis.XSLTProcessor;
574
-
575
- // Create a mock that throws
576
- class MockThrowingXSLTProcessor {
577
- importStylesheet() {
578
- throw new Error("Mock error");
579
- }
580
- }
581
-
582
- globalThis.XSLTProcessor = MockThrowingXSLTProcessor;
583
-
584
- const result = isNativeXSLTSupported();
585
-
586
- // Restore
587
- globalThis.XSLTProcessor = original;
588
-
589
- assert.strictEqual(result, false);
590
- });
591
-
592
- it("isNativeXSLTSupported should return false when transformToFragment returns null", () => {
593
- // Save original
594
- const original = globalThis.XSLTProcessor;
595
-
596
- // Create a mock that returns null
597
- class MockNullResultXSLTProcessor {
598
- importStylesheet() {}
599
- transformToFragment() {
600
- return null;
601
- }
602
- }
603
-
604
- globalThis.XSLTProcessor = MockNullResultXSLTProcessor;
605
-
606
- const result = isNativeXSLTSupported();
607
-
608
- // Restore
609
- globalThis.XSLTProcessor = original;
610
-
611
- assert.strictEqual(result, false);
612
- });
613
-
614
- it("isNativeXSLTSupported should return false when transformToFragment returns empty fragment", () => {
615
- // Save original
616
- const original = globalThis.XSLTProcessor;
617
-
618
- // Create a mock that returns empty fragment
619
- class MockEmptyResultXSLTProcessor {
620
- importStylesheet() {}
621
- transformToFragment() {
622
- return document.createDocumentFragment();
623
- }
624
- }
625
-
626
- globalThis.XSLTProcessor = MockEmptyResultXSLTProcessor;
627
-
628
- const result = isNativeXSLTSupported();
629
-
630
- // Restore
631
- globalThis.XSLTProcessor = original;
632
-
633
- assert.strictEqual(result, false);
634
- });
635
-
636
- it("installGlobal should return false when native is supported and force is false", () => {
637
- // Save original
638
- const original = globalThis.XSLTProcessor;
639
-
640
- // Create a working mock native
641
- class MockNativeXSLTProcessor {
642
- importStylesheet() {}
643
- transformToFragment() {
644
- const fragment = document.createDocumentFragment();
645
- fragment.appendChild(document.createElement("test"));
646
- return fragment;
647
- }
648
- }
649
-
650
- globalThis.XSLTProcessor = MockNativeXSLTProcessor;
651
-
652
- const result = installGlobal(false);
653
-
654
- // Restore
655
- globalThis.XSLTProcessor = original;
656
-
657
- assert.strictEqual(result, false);
658
- });
659
- });
660
-
661
- describe("importStylesheet error cases", () => {
662
- it("should throw for stylesheet with parse errors", () => {
663
- const processor = new XSLTProcessor();
664
-
665
- // Create document with parsererror element
666
- const doc = document.implementation.createDocument(null, null, null);
667
- const root = doc.createElement("root");
668
- const parseError = doc.createElement("parsererror");
669
- parseError.textContent = "XML parsing error";
670
- root.appendChild(parseError);
671
- doc.appendChild(root);
672
-
673
- assert.throws(() => {
674
- processor.importStylesheet(doc);
675
- }, /parse errors/);
676
- });
677
- });
678
-
679
- describe("setParameter with existing engine", () => {
680
- it("should update engine parameters after stylesheet import", () => {
681
- const processor = new XSLTProcessor();
682
-
683
- const xslt = parseXML(`<?xml version="1.0"?>
684
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
685
- <xsl:param name="myParam" select="'default'"/>
686
- <xsl:template match="/">
687
- <result><xsl:value-of select="$myParam"/></result>
688
- </xsl:template>
689
- </xsl:stylesheet>
690
- `);
691
-
692
- processor.importStylesheet(xslt);
693
- processor.setParameter(null, "myParam", "updated");
694
-
695
- // Verify the parameter was set
696
- const value = processor.getParameter(null, "myParam");
697
- assert.strictEqual(value, "updated");
698
- });
699
-
700
- it("should apply pre-set parameters when importing stylesheet", () => {
701
- const processor = new XSLTProcessor();
702
-
703
- // Set parameter before importing stylesheet
704
- processor.setParameter(null, "presetParam", "presetValue");
705
-
706
- const xslt = parseXML(`<?xml version="1.0"?>
707
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
708
- <xsl:param name="presetParam"/>
709
- <xsl:template match="/"><out/></xsl:template>
710
- </xsl:stylesheet>
711
- `);
712
-
713
- processor.importStylesheet(xslt);
714
-
715
- const value = processor.getParameter(null, "presetParam");
716
- assert.strictEqual(value, "presetValue");
717
- });
718
- });
719
-
720
- describe("transformToFragment error handling", () => {
721
- it("should throw when output is missing", () => {
722
- const processor = new XSLTProcessor();
723
-
724
- const xslt = parseXML(`<?xml version="1.0"?>
725
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
726
- <xsl:template match="/"><out/></xsl:template>
727
- </xsl:stylesheet>
728
- `);
729
-
730
- processor.importStylesheet(xslt);
731
- const xml = parseXML("<root/>");
732
-
733
- assert.throws(() => {
734
- processor.transformToFragment(xml);
735
- }, /2 arguments required/);
736
- });
737
-
738
- it("should throw for invalid source node type", () => {
739
- const processor = new XSLTProcessor();
740
-
741
- const xslt = parseXML(`<?xml version="1.0"?>
742
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
743
- <xsl:template match="/"><out/></xsl:template>
744
- </xsl:stylesheet>
745
- `);
746
-
747
- processor.importStylesheet(xslt);
748
-
749
- // Text node is not valid source
750
- const textNode = document.createTextNode("text");
751
-
752
- assert.throws(() => {
753
- processor.transformToFragment(textNode, document);
754
- }, /not a valid node type/);
755
- });
756
-
757
- it("should throw for invalid output document type", () => {
758
- const processor = new XSLTProcessor();
759
-
760
- const xslt = parseXML(`<?xml version="1.0"?>
761
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
762
- <xsl:template match="/"><out/></xsl:template>
763
- </xsl:stylesheet>
764
- `);
765
-
766
- processor.importStylesheet(xslt);
767
- const xml = parseXML("<root/>");
768
-
769
- // Element is not a document
770
- const element = document.createElement("div");
771
-
772
- assert.throws(() => {
773
- processor.transformToFragment(xml, element);
774
- }, /not a Document/);
775
- });
776
-
777
- it("should return null on transformation error", () => {
778
- const processor = new XSLTProcessor();
779
-
780
- const xslt = parseXML(`<?xml version="1.0"?>
781
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
782
- <xsl:template match="/">
783
- <xsl:message terminate="yes">Force error</xsl:message>
784
- </xsl:template>
785
- </xsl:stylesheet>
786
- `);
787
-
788
- processor.importStylesheet(xslt);
789
- const xml = parseXML("<root/>");
790
-
791
- const result = processor.transformToFragment(xml, document);
792
- assert.strictEqual(result, null);
793
- });
794
- });
795
-
796
- describe("transformToDocument error handling", () => {
797
- it("should throw when source is missing", () => {
798
- const processor = new XSLTProcessor();
799
-
800
- const xslt = parseXML(`<?xml version="1.0"?>
801
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
802
- <xsl:template match="/"><out/></xsl:template>
803
- </xsl:stylesheet>
804
- `);
805
-
806
- processor.importStylesheet(xslt);
807
-
808
- assert.throws(() => {
809
- processor.transformToDocument();
810
- }, /1 argument required/);
811
- });
812
-
813
- it("should throw for invalid source node type", () => {
814
- const processor = new XSLTProcessor();
815
-
816
- const xslt = parseXML(`<?xml version="1.0"?>
817
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
818
- <xsl:template match="/"><out/></xsl:template>
819
- </xsl:stylesheet>
820
- `);
821
-
822
- processor.importStylesheet(xslt);
823
- const textNode = document.createTextNode("text");
824
-
825
- assert.throws(() => {
826
- processor.transformToDocument(textNode);
827
- }, /not a valid node type/);
828
- });
829
-
830
- it("should return null on transformation error", () => {
831
- const processor = new XSLTProcessor();
832
-
833
- const xslt = parseXML(`<?xml version="1.0"?>
834
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
835
- <xsl:template match="/">
836
- <xsl:message terminate="yes">Force error</xsl:message>
837
- </xsl:template>
838
- </xsl:stylesheet>
839
- `);
840
-
841
- processor.importStylesheet(xslt);
842
- const xml = parseXML("<root/>");
843
-
844
- const result = processor.transformToDocument(xml);
845
- assert.strictEqual(result, null);
846
- });
847
- });
848
-
849
- describe("setParameter validation", () => {
850
- it("should throw for non-string localName", () => {
851
- const processor = new XSLTProcessor();
852
-
853
- assert.throws(() => {
854
- processor.setParameter(null, 123, "value");
855
- }, /non-empty string/);
856
- });
857
-
858
- it("should throw for empty localName", () => {
859
- const processor = new XSLTProcessor();
860
-
861
- assert.throws(() => {
862
- processor.setParameter(null, "", "value");
863
- }, /non-empty string/);
864
- });
865
- });
866
-
867
- describe("getParameter validation", () => {
868
- it("should throw for non-string localName", () => {
869
- const processor = new XSLTProcessor();
870
-
871
- assert.throws(() => {
872
- processor.getParameter(null, 123);
873
- }, /must be a string/);
874
- });
875
- });
876
-
877
- describe("removeParameter validation", () => {
878
- it("should throw when arguments missing", () => {
879
- const processor = new XSLTProcessor();
880
-
881
- assert.throws(() => {
882
- processor.removeParameter();
883
- }, /2 arguments required/);
884
- });
885
-
886
- it("should throw for non-string localName", () => {
887
- const processor = new XSLTProcessor();
888
-
889
- assert.throws(() => {
890
- processor.removeParameter(null, 123);
891
- }, /must be a string/);
892
- });
893
-
894
- it("should remove parameter from engine", () => {
895
- const processor = new XSLTProcessor();
896
-
897
- const xslt = parseXML(`<?xml version="1.0"?>
898
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
899
- <xsl:template match="/"><out/></xsl:template>
900
- </xsl:stylesheet>
901
- `);
902
-
903
- processor.importStylesheet(xslt);
904
- processor.setParameter(null, "testParam", "value");
905
- processor.removeParameter(null, "testParam");
906
-
907
- assert.strictEqual(processor.getParameter(null, "testParam"), "");
908
- });
909
- });
910
-
911
- describe("clearParameters with engine", () => {
912
- it("should clear parameters from engine", () => {
913
- const processor = new XSLTProcessor();
914
-
915
- const xslt = parseXML(`<?xml version="1.0"?>
916
- <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
917
- <xsl:template match="/"><out/></xsl:template>
918
- </xsl:stylesheet>
919
- `);
920
-
921
- processor.importStylesheet(xslt);
922
- processor.setParameter(null, "param1", "value1");
923
- processor.setParameter(null, "param2", "value2");
924
- processor.clearParameters();
925
-
926
- assert.strictEqual(processor.getParameter(null, "param1"), "");
927
- assert.strictEqual(processor.getParameter(null, "param2"), "");
928
- });
929
- });
930
- });