-module(inline_xml). -export([parse_transform/2]). %% If Node is an atom and its name begins with "<", assume it is %% inline XML and replace it with its parsed form (as returned by %% xmerl). If XML did not parse correctly, don't perform substitution %% but warn user through a message. node_parse(Node={atom,Line,Atom}) -> case atom_to_list(Atom) of AtomName = [$<|_] -> case catch xmerl_scan:string(AtomName, [{quiet, true}]) of {'EXIT', {Reason, Stack}} -> io:format( "Line: ~p: Error while parsing XML, not expanding. ~p: ~p", [Line, Reason, Stack]), Node; {XML, []} -> xml_to_ast(XML); {_XML, _Rest} -> io:format( "Line: ~p: More than one top-level XML element, not expanding.~n", [Line]), Node end; _ -> Node end; %% Straight from Philip Robinson's "Erlang Macro Processor" %% (http://chlorophil.blogspot.com/2007/04/erlang-macro-processor-v2-part-iii.html) node_parse(Node) when is_list(Node) -> [node_parse(Element) || Element <- Node]; node_parse(Node) when is_tuple(Node) -> [Type,Line|ListElements] = tuple_to_list(Node), Results = [node_parse(Element) || Element <- ListElements], list_to_tuple([Type,Line|Results]); node_parse(Node) -> Node. %% Takes in XML as returned by xmerl and returns how xmerl's %% representation would look like in an Erlang AST. xml_to_ast(XML) -> {ok, Scanned, _} = erl_scan:string( lists:flatten(io_lib:fwrite("~w.", [XML]))), {ok, [Parsed]} = erl_parse:parse_exprs(Scanned), Parsed. parse_transform(AST, _Options) -> [node_parse(Node) || Node <- AST].