Marcheur: XSLT-like Tree Processor Builder
Marcheur is a JavaScript library designed for building simplistic tree-walking and pattern-matching processors, drawing inspiration from XSLT 1.0's core algorithm. It allows developers to define rules for transforming tree structures, offering functionality analogous to XSLT without aiming to be a full replacement. The current stable version is 0.9.0, indicating it is pre-1.0 and its API may still be subject to changes. Due to the incomplete documentation (marked with 'XXX TDB' in the provided README excerpt), the release cadence is likely irregular, and the project's current development activity might be low. Its key differentiator is providing a lightweight mechanism for common tree transformation needs in JavaScript where full XSLT support is cumbersome or unavailable.
Warnings
- breaking As a pre-1.0 release (version 0.9.0), Marcheur's API is not yet stable. Expect potential breaking changes in minor or even patch versions before a stable 1.0 release.
- gotcha The provided README contains 'XXX TDB' placeholders, indicating incomplete or missing documentation for key API sections (Core, Matcher, Nodal). This makes understanding the full capabilities and precise usage challenging without diving into the source code.
- gotcha The library's design is heavily inspired by XSLT 1.0. Developers unfamiliar with XSLT's tree-walking and pattern-matching paradigm may face a steeper learning curve.
Install
-
npm install marcheur -
yarn add marcheur -
pnpm add marcheur
Imports
- Matcher
const { Matcher } = require('marcheur');import { Matcher } from 'marcheur'; - Nodal
const { Nodal } = require('marcheur/nodal');import { Nodal } from 'marcheur/nodal'; - qname
const { qname } = require('marcheur/qname');import { qname } from 'marcheur/qname';
Quickstart
import { createTreeWalker } from 'marcheur'; // Hypothetical core processor builder
import { Matcher } from 'marcheur';
import { qname } from 'marcheur/qname';
// Example source data representing an XML-like JS object tree
const document = {
element: 'root',
attrs: { 'xmlns:foo': 'http://foo.com/ns', version: '1.0' },
children: [
{ element: 'item', attrs: { id: 'a' }, children: ['Text A'] },
{ element: 'foo:data', attrs: { value: '123' }, children: ['Some Foo Data'] },
],
};
const nsMap = { foo: 'http://foo.com/ns' };
// Define transformation rules using Matcher and qname for pattern matching
const rules = [
{
// Match any 'item' element and transform it
match: new Matcher().element('item'),
apply: (node) => ({
element: 'transformedItem',
attrs: { ...node.attrs, processed: 'true' },
children: node.children.map(c => typeof c === 'string' ? `MODIFIED: ${c}` : c),
}),
},
{
// Match 'foo:data' using qname for namespace-aware matching
match: new Matcher().element(qname('foo:data', nsMap)),
apply: (node) => ({
element: 'foo:transformedData',
attrs: { originalValue: node.attrs.value },
children: ['Namespace handled!'],
}),
},
{
// Default rule: copy nodes and recurse for unmatched elements
match: new Matcher().any(), // Assumes a generic 'any' matcher
apply: (node, walk) => {
if (typeof node === 'string') return node; // Handle text nodes
return {
...node,
children: node.children ? node.children.map(walk) : [],
};
},
},
];
// Hypothetical function to create and execute a tree walker/processor
const walker = createTreeWalker(rules); // 'createTreeWalker' is an assumed API
const transformedDoc = walker.walk(document);
console.log('Original Document:', JSON.stringify(document, null, 2));
console.log('\nTransformed Document:', JSON.stringify(transformedDoc, null, 2));
// Direct usage of the qname utility
const qualifiedNameInfo = qname('foo:bar', nsMap);
console.log('\nqname("foo:bar", nsMap):', qualifiedNameInfo);
// Expected output: { ns: 'http://foo.com/ns', ln: 'bar' }
const simpleNameInfo = qname('baz');
console.log('qname("baz"):', simpleNameInfo);
// Expected output: { qn: 'baz' }