use warnings; use strict; sub escape_ents { local $_ = shift; s/&/&/g; s//>/g; s/"/"/g; # " s/'/'/g; return $_; } sub stringify_attribs { return join '', map{ ' '.escape_ents( $_ ).'="'.escape_ents( $_[0]{$_} ).'"' } sort keys %{$_[0]}; } #### sub XML_elem { my $tag = shift; my @results; # return value my $attribs = shift @_ if( ref( $_[0] ) eq 'HASH' ); push @results, "<${tag}" . stringify_attribs( $attribs ) . ">"; if( @_ == 0 ) { # handle an empty element $results[0] =~ s|>$| />|; return @results; } foreach my $arg ( @_ ) { if( ref( $arg ) eq 'CODE' ) { push @results, map{ " $_" } $arg->(); # <--- ??? } else { push @results, ' ' . escape_ents( $arg ) } } push @results, "<\\${tag}>"; return @results; } #### print "\n == code fragment 1 ============================================= \n"; print join "\n", XML_elem( 'root', { ID => 0 }, XML_elem( 'branch', XML_elem( 'sub_branch', { foo => 2 }, 'some contents & entities, "<>"' ), 'other contents', ), 'root stuff', ); #### __END__ # ml (Make Lazy) takes a reference to a subroutine as it's 1st arg. All # remaining args are saved and used as arguments for the subroutine when # the results of execution are desired. returns a subroutine that behaves # almost exactly as if the subroutine had been called when ml was called. sub ml { my $sub = shift; my @args = @_; return sub { return $sub->( @args ); }; } #### print "\n == code fragment 2 ============================================= \n"; print join "\n", XML_elem( 'root', { ID => 0 }, ml( \&XML_elem, 'branch', ml( \&XML_elem, 'sub_branch', { foo => 2 }, 'some contents & entities, "<>"' ), 'other contents', ), 'root stuff', ); #### __END__ # ca4ml (Curry Arguments for ML) sub ca4ml { my $sub = shift; my $tag = shift; return sub { my @args = @_; return ml( $sub, $tag, @args ); } } print "\n == code fragment 3 ============================================= \n"; my $root = ca4ml( \&XML_elem, 'root' ); my $branch = ca4ml( \&XML_elem, 'branch' ); my $sub_branch = ca4ml( \&XML_elem, 'sub_branch' ); print join "\n", $root->( { ID => 0 }, $branch->( $sub_branch->( { foo => 2 }, 'some contents & entities "<>"' ), 'other contents', ), 'root stuff', )->(); #### __END__ sub make_func { my $tag = shift; return sub { my @args = @_; return ml( \&XML_elem, $tag, @args ); } } print "\n == code fragment 4 ============================================= \n"; $root = make_func( 'root' ); $branch = make_func( 'branch' ); $sub_branch = make_func( 'sub_branch' ); print join "\n", $root->( { ID => 0 }, $branch->( $sub_branch->( { foo => 2 }, 'some contents & entities "<>"' ), 'other contents', ), 'root stuff', )->(); ; __END__