yaws + xmerl -> On the fly XSLT lookalike transforms in Erlang
Mikael Karlsson
mikael.karlsson@REDACTED
Fri Oct 25 20:05:12 CEST 2002
Hi,
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.
Check http://213.64.169.138:8001/
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
examples.
Below is the xserl.erl module that collects all the functions.
Cheers
Mikael
%%% File : xserl.erl
%%% Author : Mikael Karlsson
%%% Description : XSLT lookalike transformation in Erlang
%%%
%%%
-module(xserl).
-vsn('0.1').
-date('02-10-18').
-author('mikael.karlsson@REDACTED').
-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
%% 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
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