Here are a few examples of what you can do with my (small[jslt.min.js]) JSLT -- JavaScript Lightweight Transforms:
https://jsfiddle.net/YSharpLanguage/c7usrpsL/10
([jslt.min.js] weighs ~ 3.1kb minified)
that is, just one function,
function Per ( subject ) { ... }
... which actually mimics XSLT (1.0)'s processing model.
(cf. the "transform" and "template" inner functions, in Per's body)
So, in essence, it's simply just all baked into that single function Per ( subject ) { ... }
which forks its evaluation on the type of its (also) unique argument, to implement, either:
1) Array subject
nodeset creation / filtering / flattening / grouping / ordering / etc, if subject is an array, where the resulting nodeset (an Array as well) is extended with, and bound to methods named accordingly (only the returned Array instance of the call to Per ( subjectArray )
is extended; i.e., Array.prototype is left untouched)
i.e., Per :: Array -->
Array
(the resulting Array's extension methods having self-explanatory names such as, groupBy, orderBy, flattenBy, etc -- cf. the usage in the examples)
2) String subject
string interpolation, if subject is a string
("Per" then returns an object with a method map ( source )
, which is bound to the subject template string)
i.e., Per :: String -->
{ map :: (AnyValue -->
String) }
e.g.,
Per("Hi honey, my name is {last}. {first}, {last}.").map({ "first": "James", "last": "Bond" })
yields:
"Hi honey, my name is Bond. James, Bond."
while either of
Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ])
or
Per("Those '{*}' are our 10 digits.").map(0, 1, 2, 3, 4, 5, 6, 7, 8, 9)
yields the same:
"Those '0123456789' are our 10 digits."
but only
Per("Those '{*}' are our 10 digits.").map([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ], ", ")
yields
"Those '0, 1, 2, 3, 4, 5, 6, 7, 8, 9' are our 10 digits."
3) Transform subject
XSLT look-alike transformation, if the subject is a hash with a conventionally-defined "$" member providing the array of rewriting rules (and same as in (2), "Per" then returns an object with a method map ( source )
bound to the subject transform -- where
"ruleName" in Per ( subjectTransform [ , ruleName ])
is optional and provides functionality similar to <xsl:call-template name="templateName">...)
i.e., Per :: (Transform [ , ruleName :: String ]) -->
{ map :: (AnyValue -->
AnyValue) }
with
Transform :: { $ :: Array of rewriting rules[rw.r.] }
([rw.r.] predicate and template function pairs)
e.g., given (... another contrived example)
// (A "Member" must have first and last names, and a gender)
function Member(obj) {
return obj.first && obj.last && obj.sex;
}
var a_transform = { $: [
//...
[ [ Member ], // (alike <xsl:template match="...">...)
function(member) {
return {
li: Per("{first} {last}").map(member) +
" " +
Per(this).map({ gender: member.sex })
};
}
],
[ [ function(info) { return info.gender; } ], // (alike <xsl:template match="...">...)
function(info) { return Per("(gender: {gender})").map(info); }
],
[ [ "betterGenderString" ], // (alike <xsl:template name="betterGenderString">...)
function(info) {
info.pronoun = info.pronoun || "his/her";
return Per("({pronoun} gender is {gender})").map(info);
}
]
//...
] };
then
Per(a_transform).map({ "first": "John", "last": "Smith", "sex": "Male" })
yields:
{ "li": "John Smith (gender: Male)" }
while... (much alike <xsl:call-template name="betterGenderString">...
)
"James Bond... " +
Per(a_transform, "betterGenderString").map({ "pronoun": "his", "gender": "Male" })
yields:
"James Bond... (his gender is Male)"
and
"Someone... " +
Per(a_transform, "betterGenderString").map({ "gender": "Male or Female" })
yields:
"Someone... (his/her gender is Male or Female)"
4) Otherwise
the identity function, in all other cases
i.e., Per :: T -->
T
( i.e., Per === function ( value ) { return value ; }
)
Note
in (3) above, a JavaScript's "this" in the body of a template function is thus bound to the container / owner Transform and its set of rules (as defined by the $: [ ... ] array) -- therefore, making the expression "Per(this)", in that context, a functionally-close equivalent to XSLT's
<xsl:apply-templates select="..."/>
'HTH,