XSLT like transforms in Erlang using xmerl

Mikael Karlsson <>
Wed Jan 29 15:29:57 CET 2003


Hi,

I posted something similar earlier, 3 months ago, but I'll do it again, 
since I would like to make a humble request to add a couple of functions 
to the xmerl application.

I implemented a small set of functions that makes it possible
to write XSLT like transforms in Erlang. They actually 
uses xmerl and just adds "syntactic sugar" to make the Erlang 
"stylesheets" look more like XSLT stylesheets.
They are not many, but seem to be enough for most simple 
transforms, more complex things can be done better in
straight Erlang I think.They are too few to make an own
contribution, but they would fit nicely in xmerl.

Are there any others that feel that such functions would add value
to xmerl, or maybe you would like to see more/other XSLT type
of functions (or other implementations of the ones I made).

I have been able to use this in yaws scripts and perform transformations
of xml to html "on the fly".

Check the little Yaws server at:  http://213.64.169.87:8001/

to see what you can do and for comparing examples between XSLT 
and Erlang stylesheets. (And to see "on the fly" transformations live :-)

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 hopefully last long 
enough, so you can have a chance to respond. 

Thanks
Mikael

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

-module(xserl).
-vsn('0.1').
-date('02-10-18').
-author('').

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


%% Wrapper to make things look similar to xsl:apply-templates
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

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

value_of1(#xmlText{}=T1, Accu)->
    [T1#xmlText.value|Accu];
value_of1(E, Accu) ->
    Accu.

%% xmerl_xpath does the job.
select(Str,E)->
    xmerl_xpath:string(Str,E).

%% 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{}) ->
    E#xmlText.value;
built_in_rules(Fun, E = #xmlAttribute{}) ->
    E#xmlAttribute.value;
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)),
    C1#xmlElement{content=C2};
mapxml(Fun, List) when list(List) ->
    AFun = fun(E) -> mapxml(Fun, E) end,
    lists:map(AFun, List);
mapxml(Fun, E) ->
    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)),
    {C1#xmlElement{content=C2},Accu2};
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) ->
    Fun(E,Accu).




More information about the erlang-questions mailing list