yaws + xmerl -> On the fly XSLT lookalike transforms in Erlang

Mikael Karlsson <>
Fri Oct 25 20:05:12 CEST 2002


I implemented a small set of functions that makes it possible
to write XSLT "lookalike" (a can't find a better word) transforms
in Erlang. They actually uses xmerl and just adds "syntactic sugar"
to make the Erlang "stylesheets" look more like XSLT stylesheets.

I have been able to use this in yaws scripts and perform transformations
directly upon http GET requests.


for examples.
NOTE, my IP is dynamically set by dhcp from my ISP so I can not promise
it will last so many days. But it will do until I get a fixed one for the 

Below is the xserl.erl module that collects all the functions.


%%% File    : xserl.erl
%%% Author  :  Mikael Karlsson
%%% Description : XSLT lookalike transformation in Erlang


-export([xslapply/2, value_of/1, select/2, built_in_rules/2 ]).
-export([mapxml/2, foldxml/3, mapfoldxml/3]).

%% Wrapper to make things look similar to xsl:apply-templates
%% I am actually a bit reluctant to use this function, since
%% when you want to look like xslt you actually hide away how
%% simple it is to implement in Erlang. Including some
%% performance loss.
xslapply(Fun, EList) when list(EList) ->
    lists:map( Fun, EList);
xslapply(Fun, E = #xmlElement{})->
    lists:map( Fun, E#xmlElement.content).

%% value_of concatenates all text nodes within the tree

    lists:reverse(foldxml(fun value_of1/2, [], E)).

value_of1(#xmlText{}=T1, Accu)->
value_of1(E, Accu) ->

%% xmerl_xpath does the job.

%% The default fallback behaviour, template funs should
%% end with:
%% template(E)->built_in_rules(fun template/1, E).
built_in_rules(Fun, E = #xmlElement{})->
    lists:map(Fun, E#xmlElement.content);
built_in_rules(Fun, E = #xmlText{}) ->
built_in_rules(Fun, E = #xmlAttribute{}) ->
built_in_rules(Fun, E) ->[].

%%% -------------------- Utilities -------------------------
%%% funs working on the xmerl tree

%% mapxml
%% Fun is fun(Old#xmlElement) -> New#xmlElement

mapxml(Fun, #xmlElement{}= E) ->
    C1 = Fun(E),
    C2 = mapxml(Fun,lists:flatten(C1#xmlElement.content)),
mapxml(Fun, List) when list(List) ->
    AFun = fun(E) -> mapxml(Fun, E) end,
    lists:map(AFun, List);
mapxml(Fun, E) ->

%% foldxml
%% Fun is fun(#xmlElement, OldAccu) -> NewAccu

foldxml(Fun, Accu0, #xmlElement{content=C}=E) ->
    Accu1 = Fun(E, Accu0),
    foldxml(Fun, Accu1, C);
foldxml(Fun, Accu, List) when list(List) ->
    AFun = fun(E,A) -> foldxml(Fun, A, E) end,
    lists:foldl(AFun, Accu, List);
foldxml(Fun, Accu, E) ->
    Fun(E, Accu).

%% mapfoldxml
%% Fun is fun(Old#xmlElement, OldAccu) -> {New#xmlElement, NewAccu}

mapfoldxml(Fun, Accu0, #xmlElement{}=E) ->
    {C1,Accu1} = Fun(E, Accu0),
    {C2,Accu2} = mapfoldxml(Fun, Accu1, lists:flatten(C1#xmlElement.content)),
mapfoldxml(Fun, Accu, List) when list(List) ->
    AFun = fun(E,A) -> mapfoldxml(Fun, A, E) end,
    lists:mapfoldl(AFun, Accu, List);
mapfoldxml(Fun, Accu, E) ->

More information about the erlang-questions mailing list