@tradik/xslt-processor 1.0.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/bin/xslt.js ADDED
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * XSLT Processor CLI
5
+ *
6
+ * Command-line interface for transforming XML using XSLT stylesheets.
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ import { readFile, writeFile } from 'node:fs/promises';
12
+ import { parseArgs } from 'node:util';
13
+ import { JSDOM } from 'jsdom';
14
+ import { XSLTProcessor } from '../src/XSLTProcessor.js';
15
+
16
+ const VERSION = '1.0.5';
17
+
18
+ function printHelp() {
19
+ console.log(`
20
+ xslt-processor - Transform XML documents using XSLT stylesheets
21
+
22
+ USAGE:
23
+ xslt <xml-file> <xslt-file> [options]
24
+
25
+ ARGUMENTS:
26
+ <xml-file> Path to XML source document
27
+ <xslt-file> Path to XSLT stylesheet
28
+
29
+ OPTIONS:
30
+ -o, --output <file> Write output to file instead of stdout
31
+ -p, --param <n>=<v> Set XSLT parameter (can be used multiple times)
32
+ -f, --format Format output with indentation
33
+ -h, --help Show this help message
34
+ -v, --version Show version number
35
+
36
+ EXAMPLES:
37
+ # Basic transformation
38
+ xslt data.xml transform.xsl
39
+
40
+ # Save output to file
41
+ xslt data.xml transform.xsl -o result.html
42
+
43
+ # With parameters
44
+ xslt data.xml transform.xsl -p title="My Page" -p count=10
45
+
46
+ # Multiple parameters with formatted output
47
+ xslt data.xml transform.xsl -p lang=en -p debug=true -f -o output.html
48
+ `);
49
+ }
50
+
51
+ function printVersion() {
52
+ console.log(`xslt-processor v${VERSION}`);
53
+ }
54
+
55
+ function parseParameters(params) {
56
+ const result = {};
57
+
58
+ if (!params || !Array.isArray(params)) {
59
+ return result;
60
+ }
61
+
62
+ for (const param of params) {
63
+ const equalIndex = param.indexOf('=');
64
+ if (equalIndex === -1) {
65
+ console.error(`Warning: Invalid parameter format "${param}". Expected name=value`);
66
+ continue;
67
+ }
68
+
69
+ const name = param.substring(0, equalIndex);
70
+ const value = param.substring(equalIndex + 1);
71
+ result[name] = value;
72
+ }
73
+
74
+ return result;
75
+ }
76
+
77
+ function formatXml(xml) {
78
+ let formatted = '';
79
+ let indent = 0;
80
+ const lines = xml.replace(/>\s*</g, '>\n<').split('\n');
81
+
82
+ for (const line of lines) {
83
+ const trimmed = line.trim();
84
+ if (!trimmed) continue;
85
+
86
+ if (trimmed.startsWith('</')) {
87
+ indent = Math.max(0, indent - 1);
88
+ }
89
+
90
+ formatted += ' '.repeat(indent) + trimmed + '\n';
91
+
92
+ if (trimmed.startsWith('<') && !trimmed.startsWith('</') &&
93
+ !trimmed.startsWith('<?') && !trimmed.startsWith('<!') &&
94
+ !trimmed.endsWith('/>') && !trimmed.includes('</')) {
95
+ indent++;
96
+ }
97
+ }
98
+
99
+ return formatted;
100
+ }
101
+
102
+ async function main() {
103
+ const options = {
104
+ output: { type: 'string', short: 'o' },
105
+ param: { type: 'string', short: 'p', multiple: true },
106
+ format: { type: 'boolean', short: 'f', default: false },
107
+ help: { type: 'boolean', short: 'h', default: false },
108
+ version: { type: 'boolean', short: 'v', default: false }
109
+ };
110
+
111
+ let args;
112
+ try {
113
+ args = parseArgs({ options, allowPositionals: true });
114
+ } catch (err) {
115
+ console.error(`Error: ${err.message}`);
116
+ process.exit(1);
117
+ }
118
+
119
+ if (args.values.help) {
120
+ printHelp();
121
+ process.exit(0);
122
+ }
123
+
124
+ if (args.values.version) {
125
+ printVersion();
126
+ process.exit(0);
127
+ }
128
+
129
+ const [xmlPath, xsltPath] = args.positionals;
130
+
131
+ if (!xmlPath || !xsltPath) {
132
+ console.error('Error: Both XML and XSLT file paths are required');
133
+ console.error('Run "xslt --help" for usage information');
134
+ process.exit(1);
135
+ }
136
+
137
+ // Setup JSDOM for DOM parsing
138
+ const dom = new JSDOM('<!DOCTYPE html><html><body></body></html>', {
139
+ contentType: 'text/html'
140
+ });
141
+ const { DOMParser, XMLSerializer } = dom.window;
142
+
143
+ try {
144
+ // Read input files
145
+ const [xmlContent, xsltContent] = await Promise.all([
146
+ readFile(xmlPath, 'utf-8'),
147
+ readFile(xsltPath, 'utf-8')
148
+ ]);
149
+
150
+ // Parse documents
151
+ const parser = new DOMParser();
152
+ const xmlDoc = parser.parseFromString(xmlContent, 'application/xml');
153
+ const xsltDoc = parser.parseFromString(xsltContent, 'application/xml');
154
+
155
+ // Check for parsing errors
156
+ const xmlError = xmlDoc.querySelector('parsererror');
157
+ if (xmlError) {
158
+ console.error(`Error parsing XML: ${xmlError.textContent}`);
159
+ process.exit(1);
160
+ }
161
+
162
+ const xsltError = xsltDoc.querySelector('parsererror');
163
+ if (xsltError) {
164
+ console.error(`Error parsing XSLT: ${xsltError.textContent}`);
165
+ process.exit(1);
166
+ }
167
+
168
+ // Create processor
169
+ const processor = new XSLTProcessor();
170
+ processor.importStylesheet(xsltDoc);
171
+
172
+ // Set parameters
173
+ const params = parseParameters(args.values.param);
174
+ for (const [name, value] of Object.entries(params)) {
175
+ processor.setParameter(null, name, value);
176
+ }
177
+
178
+ // Transform
179
+ const fragment = processor.transformToFragment(xmlDoc, dom.window.document);
180
+
181
+ // Serialize result
182
+ const serializer = new XMLSerializer();
183
+ let output = serializer.serializeToString(fragment);
184
+
185
+ // Format if requested
186
+ if (args.values.format) {
187
+ output = formatXml(output);
188
+ }
189
+
190
+ // Output result
191
+ if (args.values.output) {
192
+ await writeFile(args.values.output, output, 'utf-8');
193
+ console.error(`Output written to ${args.values.output}`);
194
+ } else {
195
+ console.log(output);
196
+ }
197
+
198
+ } catch (err) {
199
+ if (err.code === 'ENOENT') {
200
+ console.error(`Error: File not found: ${err.path}`);
201
+ } else {
202
+ console.error(`Error: ${err.message}`);
203
+ }
204
+ process.exit(1);
205
+ }
206
+ }
207
+
208
+ main();