bladestonight has asked for the wisdom of the Perl Monks concerning the following question:

I have a program which outputs an XML file. I want to change a few parameters 'on the fly' from a config file and create a modified XML file. I also want to keep the config file as simple as possible, hence separate my subroutine implementation from the config file.

So far my code compiles but my subroutine isn't being called.
Firstly, is this a good way to do it?
Secondly, why isn't it working?

The config file I have looks like:

# -*- perl -*- $PARAMS{'Task/Params/CellRefinementLevel'}=7; $PARAMS{'Task/Params/GridCellSizeInXDirection'}=100; $PARAMS{'Task/Params/GridCellSizeInYDirection'}=100; 1; # Required for end of config file.
And my code looks like this:
use XML::Twig; use vars qw (%PARAMS); do 'params.cfg'; while( my($key,$val) = each(%PARAMS) ) { substr($val,0,0) = 'sub { upd_param(@_,'; $val .=' },'; $PARAMS{$key} = $val; } my $twigT= new XML::Twig( twig_roots => { %PARAMS,}, twig_print_outside_roots => 1, ); $twigT->parsefile( $task_file); $twigT->purge; #probably not needed sub upd_param { my( $t, $param,$new_param)= @_; my $item = defined($new_param)? $new_param:$param->text; $param->set_text($item); # change it $param->print; # print updated value $t->purge; # free the memory }

Replies are listed 'Best First'.
Re: XML::twig using a hash in twig_roots
by GrandFather (Saint) on Apr 16, 2007 at 10:34 UTC

    Ok, looked a little longer at your code and figure I see what you are trying to do. The following probably addresses your immediate problem:

    use strict; use warnings; use XML::Twig; use vars qw (%PARAMS); do 'noname1.pl'; for my $key (keys %PARAMS) { my $val = $PARAMS{$key}; # Need var because sub turns it into a cl +osure $PARAMS{$key} = sub {upd_param (@_, $val)}; } my $twigT= new XML::Twig( twig_roots => \%PARAMS, twig_print_outside_roots => 1, ); $twigT->parse (do {local $/; <DATA>}); $twigT->purge; #probably not needed sub upd_param { my ($t, $param,$new_param) = @_; my $item = defined($new_param)? $new_param:$param->text; $param->set_text($item); # change it $param->print; # print updated value $t->purge; # free the memory } __DATA__ <task> <params> <CellRefinementLevel></CellRefinementLevel> </params> </task>

    Prints:

    <task> <params> <CellRefinementLevel>7</CellRefinementLevel> </params> </task>

    given a file noname1.pl containing:

    $PARAMS{'CellRefinementLevel'}=7; $PARAMS{'GridCellSizeInXDirection'}=100; $PARAMS{'GridCellSizeInYDirection'}=100;

    However the same mapping could be provided using a rather less frightening text file containing:

    CellRefinementLevel=7 GridCellSizeInXDirection=100 GridCellSizeInYDirection=100

    if the use vars and do lines are replaced with:

    @ARGV = 'noname.txt'; # omit if config file passed on the command line my %PARAMS = map {chomp; split '='} grep {length} <>;

    DWIM is Perl's answer to Gödel

      Thanks for the kind welcome, glad to be here :)

      GrandFather, you definitely see what I want to do, but would you do it any other way?

      I supposed I should say the reason for the separate configuration file is I need to create a quick and easy way for a non-Perl user to update the XML file. So I'm going to at least use your less frightening text file.

        I think the over all technique is fine. I've not used XML::Twig in that fashion before, but it is a technique worth remembering.


        DWIM is Perl's answer to Gödel
Re: XML::twig using a hash in twig_roots
by GrandFather (Saint) on Apr 16, 2007 at 09:27 UTC

    First, welcome to the Monastery! Very nice first post.

    "It isn't working" doesn't generally tell us a lot about what particular problem you are experiencing. Generally it helps to provide a little sample data and tell us what you saw and what you expected to see.

    In this case it may be that the missing ')' in the $val .= ' },'; line is the problem. Try:

    $val = "sub {upd_param (\@_, $val)},";

    in place of the two lines. Not only is it more likely to work, but the intent is much clearer.

    In a similar vein, there are many other ways that you could handle your configuration issue. The method you are using at the moment looks rather fragile non-intuitive. However I'd like to see a full working sample (provide the document to be processed in a __DATA__ section) before advising any alternative technique. Keep the sample data very short - you only need enough to demonstrate how things work (or don't).


    DWIM is Perl's answer to Gödel
Re: XML::twig using a hash in twig_roots
by Anonymous Monk on Apr 16, 2007 at 09:54 UTC

    I don't have much time to answer, but it seems to me that the values of the hash you are passing as argument to twig_roots are just strings, strings that contain sub { upd_param(@_, 7) }, but strings nevertheless. You need the value to be a real function: (untested): $PARAMS{$key}= sub { upd_param(@_, $val) };