XSLT like transforms in Erlang using xmerl
Mikael Karlsson
mikael.karlsson@REDACTED
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('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
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