To the OP: you did not describe the configuration format properly, an XML fragment would have helped us. As it is you will probably have to modify the solution below to match your format.
I assumed a the following format:
<conf>
<option><name>configuration1</name><value>string1 modified</value></option>
<option><name>configuration2</name><value>string2 re-modded</value></option>
<option><name>configuration3</name><value>string3</value></option>
</conf>
Code that would process this format would be:
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw( -nosticky -utf8 :standard form );
use XML::LibXML;
my $CONF="/web/data/conf.xml"; # or wherever your XML is located
# dispatch table, action => code to process it
my $dispatch= { display => \&display_conf,
edit => \&display_edit_form,
save => \&save_edits,
};
# action is "what to do"
my $action= param( 'action') || 'display';
$dispatch->{$action}->() || exit_error( "wrong action");
exit;
# load the XML and build a table to display it
sub display_conf
{ my $conf= XML::LibXML->load_xml( location => $CONF);
my $content;
foreach my $option ($conf->findnodes( '/conf/option'))
{ $content .= Tr( td( $option->findvalue( './name')),
td( $option->findvalue( './value'))
);
}
$content= table( $content);
# add a link to the edit form
$content .= p( a({ href => url() . '?action=edit' }, 'edit'));
output( $content);
}
# load the XML and build a form that will let you edit it
sub display_edit_form
{ my $conf= XML::LibXML->load_xml( location => $CONF);
my $content;
foreach my $option ($conf->findnodes( '/conf/option'))
{ $content .= Tr( td( $option->findvalue( './name')),
td( input( { type => "text", size => 40,
name => $option->findvalue( 'name'),
value => $option->findvalue( './value')}
)
)
);
}
$content= table( $content);
$content= form( { action => url() },
hidden( { name => 'action', value => 'save', override => 1 }),
$content,
submit( 'Save'),
);
output( $content);
}
# load the XML, go through all options, update the value from the form,
# save the XML, display it value, from the form
sub save_edits
{ my $conf= XML::LibXML->load_xml( location => $CONF);
foreach my $option ($conf->findnodes( '/conf/option'))
{ my $new_value= param( $option->findvalue( './name'));
my( $value_node)= $option->findnodes( './value');
$value_node->removeChildNodes();
$value_node->appendText( $new_value);
}
$conf->toFile( $CONF);
display_conf();
}
# placeholder,
sub exit_error
{ my $message= shift;
print header(), p($message);
}
# output subs, load the template, inject the content and output (with header)
sub output
{ my $content= shift;
print header(), fill_in_string( template(), content => $content );
}
sub fill_in_string
{ my( $template, %param)= @_;
$template=~ s{<<(\w+)>>}{$param{$1}}g;
return $template;
}
sub template
{ return join '', <DATA>; }
# template, very simple
__DATA__
<html>
<head>
<title>Configuration Editor</title>
</head>
<body>
<h1>Configuration Editor</h1>
<h2>Configuration</h2>
<<content>>
</h2>
</body>
</html>
Deployement: put the code somewhere it can be run as CGI, and make sure conf.xml
can be read and written by the web server. It's probably better to put it outside of the web tree.
This is in a way prehistorical Perl. CGI is widely considered archaic and there are more modern and fancy options available in Perl. If your configuration is more complex than a key/value list, if you want to have custom help for each field or if you need to use a more complex template to conform to your company's look'n feel, then web Frameworks like Dancer or Mojolicious would be better suited than the simple solution above.
OTOH it works, and I this is still how I write a lot of small tools, that have a few internal users and don't need much in terms of UI.
To the people who suggested that this is too complex to do for people not familiar with Perl, way to go guys! This is not rocket science. It's the kind of code that gets people to start with Perl, why wouldn't we help with writing it? This is in fact a perfect illustration of The Reluctant Perl Programmer.