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

I'm trying to wrap my ahead around an XML config file I'm trying to implement, more for learning than anything else. I find that a lot of the scripts I write (Perl, Bash, etc.) all start with the same 8-10 variables being defined at the top. Change one directory/IP/user, and you have to hunt for all the scripts which will now break. So, I thought what if I made an XML file and coded the scripts to pull from the file. If something changes, just change the XML! Maybe I'm building a bird house with a chainsaw, but I wanted to try.

Then I thought "well, I can add xxx and yyy to it too!" Maybe that was a mistake. ;)

XML config example:
<Config> <Variableconfig> <Variable> <Name>NAME</Name> <Value>somevalue</Value> </Variable> ... </variableconfig> <ServerConfig> <Server> <Name>blue</Name> <IP>xxx.xxx.xxx.xx</IP> <IP>xxx.xxx.xxx.xx</IP> <FQDN>blue.some.domain</FQDN> </Server> ... </ServerConfig> </Config>

So, I got the XML file done and slurped it in with XML::Simple using forcearray and Dumped it with data dumper. What I have are hashes of arrays of hashes etc.,etc. I can access elements with $xml->{yadda}[0]->{yadda}[0], but that seemed awfully painful.


So, I thought I'd give XML::LibXML a shot. This seemed a little more straight forward, although there's no visible data structure created that I could tell (I'm a visual type). I could get the file in, but couldn't do something like "find the element with the name 'Name'". I was trying various functions of LibXML (getAttributes, etc.) trying to walk the tree with no luck.


I guess to end this book, is there someone who could give me an example of "find the elements labeled 'Server' and pull out all FQDNs" using XML::LibXML or XML::Simple for that matter? Or suggest a better/different way of doing all this?


Sorry for the long read... :)

Replies are listed 'Best First'.
Re: XML for Dummies
by tilly (Archbishop) on Jul 12, 2008 at 04:13 UTC
    You're overengineering this. XML buys you nothing useful in this case.

    Write a bash script that does nothing but set these 8-10 variables. Modify your existing bash scripts to source this new configuration script. Write a Perl function to parse this configuration script. Put that in a library, and in all of your Perl scripts load that library and call that function.

    Now you're done in the simplest manner possible. And the next person who has to pick up your code should find it easy to understand.

      Better yet: use Config::File, Config::General, Config::IniFile, Config::Tiny or Config::Any. IMHO it's never a good idea to roll your own config file parsing, when you have many CPAN modules to do the heavy lifting for you. With Config::Any you can even use XML config files if necessary.
      []s, HTH, Massa
        You missed the requirement that the configuration be accessible in 2 different languages. A CPAN module will not help a bash script.

        As for configuration file parsing, I'm not a fan of anything that I've seen on CPAN yet. Admittedly I haven't looked in years, but I still hold to the opinion that I expressed in Re (tilly) 6: using strict and a config file.

Re: XML for Dummies
by Anonymous Monk on Jul 12, 2008 at 04:00 UTC
Re: XML for Dummies
by Jenda (Abbot) on Jul 12, 2008 at 11:23 UTC

    You do not have to forcearray everything, just those things that actually can be repeated. In this case you might be better off using a module that'll let you tweak the created datastructure. Something like:

    use strict; use XML::Rules; use Data::Dumper; my $parser = XML::Rules->new( rules => { _default => 'content', Variable => sub {$_[1]->{Name} => $_[1]->{Value}}, IP => 'content array', 'VariableConfig,ServerConfig' => 'no content', Server => 'no content by Name', Config => 'pass no content', }, ); my $data = $parser->parse(\*DATA); print Dumper($data); my @FQDNs = map {$_->{FQDN}} values %{$data->{ServerConfig}}; print "@FQDNs"; __DATA__ <Config> <VariableConfig> <Variable> <Name>NAME</Name> <Value>somevalue</Value> </Variable> <Variable> <Name>NAME2</Name> <Value>somevalue blah</Value> </Variable> </VariableConfig> <ServerConfig> <Server> <Name>blue</Name> <IP>xxx.xxx.xxx.xx</IP> <IP>xxx.xxx.xxx.xx</IP> <FQDN>blue.some.domain</FQDN> </Server> <Server> <Name>black</Name> <IP>xxx.xxx.xxx.xx</IP> <IP>xxx.xxx.xxx.xx</IP> <FQDN>black.some.domain</FQDN> </Server> </ServerConfig> </Config>
Re: XML for Dummies
by kevlinux (Initiate) on Jul 12, 2008 at 18:12 UTC

    Thanks for all the replies. I'm leaning toward the over engineering comment as well. :-\ However, I will check out some of the config::* modules regardless.

    Thank you keepers of wisdom!