Skip to content

About

JavaScript implementation of XSLTProcessor for browser environments and Node.js CLI. This package provides a complete implementation of the W3C XSLTProcessor API that can be used as a drop-in replacement for the native browser implementation.

Resources

Code of conduct

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Repository files navigation

@tradik/xslt-processor

GitHub GitHub stars GitHub forks

CI Browser tests Release npm version @tradik/xslt3 xslt-migrate-check npm downloads GitHub release License Node.js Version Quality Gate Line Coverage TypeScript

Source Code: github.com/spagu/XSLT-Processor

JavaScript implementation of XSLTProcessor for browser environments and Node.js CLI. This package provides a complete implementation of the W3C XSLTProcessor API that can be used as a drop-in replacement for the native browser implementation.

Background

Chrome and other browsers are removing native XSLT (Chrome's announcement):

  • Chrome 143 (December 2025): XSLTProcessor and <?xml-stylesheet type="text/xsl"?> are deprecated, with warnings in the console
  • Chrome 158 (17 November 2026): XSLT stops working in stable Chrome, except for sites in the origin trial and browsers under the enterprise policy
  • Chrome 176 (17 August 2027): the origin trial and the enterprise policy end; XSLT is off everywhere
  • Firefox and WebKit support the removal but have not announced dates

This library ensures your XSLT-based applications continue to work regardless of browser support.

Used by Schema Resume, Job Tailor and others: see References.

Features

  • 1:1 Native API Compatibility: Drop-in replacement for native XSLTProcessor
  • One-line migration: import "@tradik/xslt-processor/polyfill" or a <script> tag keeps XSLTProcessor pages working, and the same tag inside an XML document keeps <?xml-stylesheet?> rendering; npx xslt-migrate-check . finds the pages that need it, --fix writes the patch and xslt-migrate-test compares the output with the browser's (wizard, how-to)
  • XSLT 1.0: Every element and function of the W3C XSLT 1.0 Recommendation, with the few gaps listed under Known Deviations
  • XPath 1.0 Engine: Built-in XPath evaluator with all core functions
  • xsl:output Serialization: transformToString() honors method, indent, doctype, CDATA sections and disable-output-escaping
  • Zero Dependencies: The library has no runtime dependencies; only the xslt command line tool needs jsdom (an optional peer dependency)
  • Multiple Formats: ESM, CommonJS, and browser IIFE bundles
  • TypeScript Support: Includes TypeScript declarations

Documentation

The documentation is also published as a website with an interactive playground: https://xslt-processor.tradik.com/ (playground: XSLT 1.0 transformations, and with the in-development @tradik/xslt3 XSLT 3.0 stylesheets at ?mode=xslt3 and XPath 3.1 expressions at ?mode=xpath; blog with an RSS feed).

Guide Contents
API Reference XSLTProcessor methods, parameters, xsl:output serialization, module exports, XsltEngine options, TypeScript
Loaders xsl:import, xsl:include and the document() function
Complete Example A product list transformed into an HTML table (browser and CLI)
Command Line Tool xslt options, base directory, includes, input encodings
Conformance W3C compliance tables, supported elements and functions, known deviations, test coverage
Security Limits XPath and XSLT limits, prototype pollution protection, input validation
Browser Compatibility Minimum browser versions, native XSLT removal timeline, feature detection
XSLT 2.0 and 3.0 @tradik/xslt3: one engine for XSLT 3.0 and 2.0 in a separate package; options, conformance and design
Migration checker npx xslt-migrate-check .: finds XSLTProcessor usages, <?xml-stylesheet?> documents and stylesheets in a project, rates the Chrome risk and prints the one-line migration; --json and --fail-on for CI; online at xslt-processor.tradik.com/check
Migration fixes npx xslt-migrate-check . --fix: the polyfill import, the script tags and the dependencies written as migration.patch for review (--write applies it); xslt-migrate-check/analyze runs the same analysis in a browser
Migration test xslt-migrate-test: runs every XML + XSL pair on the browser's engine (Chromium) or libxslt and on this library, compares the output and reports the compatibility
Benchmarks Every version side by side (1.1.3, 1.2.0, 1.3.0, @tradik/xslt3) in one chart and table; then the detailed runs: 1.1.3 vs 1.2.0 speed-up, time and peak memory per scenario, with charts, tables and npm run bench to reproduce; XPath 1.0 of this package vs XPath 3.1 of @tradik/xslt3 (npm run bench -- --suite xpath); the XSLT 1.0 engine vs @tradik/xslt3 on the same stylesheets, idiomatic 2.0/3.0 rewrites and 3.0-only scenarios (npm run bench -- --suite xslt)
Development Setup, tests, Docker, Makefile, publishing to npm
Style Guide Project colors with WCAG 2.2 contrast ratios

All guides are listed in the documentation index.

Installation

npm install @tradik/xslt-processor
# or
yarn add @tradik/xslt-processor
pnpm add @tradik/xslt-processor
bun add @tradik/xslt-processor

Every change is installed and smoke-tested in CI with npm, Yarn 1, Yarn 4 (Plug'n'Play), pnpm and bun (npm run test:package-managers). The XSLT 2.0/3.0 engine installs the same way (yarn add @tradik/xslt3 and so on), and the migration checker runs without installing: npx xslt-migrate-check ., pnpm dlx xslt-migrate-check . or bunx xslt-migrate-check ..

The library itself has no dependencies. The xslt command line tool also needs jsdom (an optional peer dependency, >=25), see CLI Usage.

Quick Start

Browser via CDN (Recommended)

Use a CDN for the easiest browser integration - no build step required:

<!-- jsDelivr (recommended) -->
<script src="https://cdn.jsdelivr.net/npm/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js"></script>

<!-- or unpkg -->
<script src="https://unpkg.com/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js"></script>

<script>
  // XSLTProcessor is the native one, or this polyfill when native XSLT is unavailable
  const processor = new XSLTProcessor();

  // Load and transform XML
  const parser = new DOMParser();
  const xslt = parser.parseFromString(xsltString, 'application/xml');
  const xml = parser.parseFromString(xmlString, 'application/xml');

  processor.importStylesheet(xslt);
  const result = processor.transformToFragment(xml, document);
  document.getElementById('output').appendChild(result);
</script>

The bundle defines the global XsltProcessorLib (all module exports) and calls installGlobal(): window.XSLTProcessor is replaced only when the browser has no working native implementation. To always use this implementation, call XsltProcessorLib.installGlobal(true) or use new XsltProcessorLib.XSLTProcessor().

CDN URLs:

CDN URL
jsDelivr https://cdn.jsdelivr.net/npm/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js
unpkg https://unpkg.com/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js

Tip: Use @1 for the latest 1.x version, or an exact version such as @1.1.3 for pinning.

One line for XML documents with <?xml-stylesheet?>

An XML file that Chrome rendered through <?xml-stylesheet type="text/xsl"?> shows up as raw XML once native XSLT is gone. One line right after the processing instruction keeps it rendering: browsers without XSLT run an XHTML <script> found in an XML document, the bundle finds the instruction, fetches the stylesheet (and its imports), transforms the document and replaces it with the result, scripts of the result included.

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="catalog.xsl"?>
<catalog><script xmlns="http://www.w3.org/1999/xhtml" src="https://cdn.jsdelivr.net/npm/@tradik/xslt-processor@1/dist/xslt-processor.browser.min.js"></script>
  <item>…</item>
</catalog>

Browsers that still have XSLT apply the instruction themselves and never see the script. The stylesheet does not see it either: it is removed from the source before the transformation. To find the pages that need this line, run npx xslt-migrate-check . in your project (migration checker).

Browser (Local Install)

If you prefer local installation:

<script src="node_modules/@tradik/xslt-processor/dist/xslt-processor.browser.min.js"></script>
<script>
  // XSLTProcessor is now available globally
  const processor = new XSLTProcessor();
  // ...
</script>

One import for bundled code

import "@tradik/xslt-processor/polyfill"; // first, before code that uses XSLTProcessor

const processor = new XSLTProcessor(); // the native one, or this library where there is none

The entry exports nothing: it installs this XSLTProcessor as the global one when the browser has no working native XSLT (installGlobal()), and applies an <?xml-stylesheet?> the browser left unapplied (autoApplyXmlStylesheet()). In browsers that still have XSLT it changes nothing. CommonJS: require("@tradik/xslt-processor/polyfill").

ESM Module

import { XSLTProcessor, installGlobal } from '@tradik/xslt-processor';

// Optional: Force install as global XSLTProcessor
installGlobal();

// Or use directly
const processor = new XSLTProcessor();
const parser = new DOMParser();

// Load and parse XSLT stylesheet
const xsltText = await fetch('template.xsl').then(r => r.text());
const xsltDoc = parser.parseFromString(xsltText, 'application/xml');
processor.importStylesheet(xsltDoc);

// Load and parse XML source
const xmlText = await fetch('data.xml').then(r => r.text());
const xmlDoc = parser.parseFromString(xmlText, 'application/xml');

// Transform
const fragment = processor.transformToFragment(xmlDoc, document);
document.getElementById('output').appendChild(fragment);

CommonJS

const { XSLTProcessor } = require('@tradik/xslt-processor');

const processor = new XSLTProcessor();
// ...

Node.js

Node.js has no DOM, so bring one such as jsdom. The filesystem loader example is a complete Node.js script, and the API Reference covers every method.

XSLT 2.0 and 3.0 (opt-in)

By default every stylesheet runs with the XSLT 1.0 engine, and a version="2.0" stylesheet runs in forwards-compatible mode, as in Chrome. With xsltVersion: "auto", a stylesheet that declares version 2.0 or 3.0 is run by @tradik/xslt3, an optional peer dependency loaded with import() only when such a stylesheet is imported, so the XSLT 1.0 bundles do not grow by the size of the new engine:

// npm install @tradik/xslt3
const processor = new XSLTProcessor({ xsltVersion: "auto" });
const html = await processor.transformAsync(xmlText, { stylesheet: xsl20Text });

// The synchronous W3C API needs the engine loaded first
await XSLTProcessor.preload();
processor.importStylesheet(xsl20Doc);
const fragment = processor.transformToFragment(xmlDoc, document);

The CLI flag is --xslt-version auto. Details: Opt-in XSLT 2.0/3.0.

CLI Usage

The package includes a command-line tool for transforming XML documents.

Without Node.js, use the standalone executable attached to every GitHub release (Linux x64/arm64, macOS x64/arm64, Windows x64), installed with a checksum check:

curl -fsSL https://raw.githubusercontent.com/spagu/XSLT-Processor/main/scripts/install.sh | bash

See Standalone executables for manual installation. With Node.js, the command line tool needs a DOM implementation, so install jsdom next to the package. It is an optional peer dependency: library users do not need it. Without it, xslt exits with an explanation instead of a stack trace.

# Global installation
npm install -g @tradik/xslt-processor jsdom

# Transform XML with XSLT
xslt data.xml template.xsl

# Save output to file
xslt data.xml template.xsl -o result.html

# With parameters
xslt data.xml template.xsl -p title="My Page" -p count=10

# Format output with indentation
xslt data.xml template.xsl -f -o output.html

# Override the output method and drop the XML declaration
xslt data.xml template.xsl --method text
xslt data.xml template.xsl --no-declaration

# Run an XSLT 2.0/3.0 stylesheet with @tradik/xslt3 (npm install -g @tradik/xslt3)
xslt data.xml grouping.xsl --xslt-version auto

See Command Line Tool for all options, the base directory, xsl:include/document() resolution and input encodings.

Known Deviations

The main differences from XSLT 1.0 / XPath 1.0 and from libxslt:

  • xsl:number ignores lang and letter-value;
  • unparsed-entity-uri() always returns '';
  • numbers convert to strings in the XPath 1.0 form (10000000000), where libxslt writes 1e+10.

Details and workarounds: Known Deviations.

Contributing and Security

License

BSD-3-Clause License - see LICENSE.md for details.

Related

About

JavaScript implementation of XSLTProcessor for browser environments and Node.js CLI. This package provides a complete implementation of the W3C XSLTProcessor API that can be used as a drop-in replacement for the native browser implementation.

Resources

Code of conduct

Security policy

Stars

3 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages