Search code examples
perlhashxml-simple

What is wrong with my declaration of a hash inside a hash in Perl?


I am struggling with the following declaration of a hash in Perl:

my %xmlStructure = {
            hostname    =>  $dbHost,
            username    =>  $dbUsername,
            password    =>  $dbPassword,
            dev_table   =>  $dbTable,
            octopus     =>  {
                                alert_dir       =>  $alert_dir,
                                broadcast_id    =>  $broadcast_id,
                                system_id       =>  $system_id,
                                subkey          =>  $subkey
                            }
 };

I've been googling, but I haven't been able to come up with a solution, and every modification I make ends up in another warning or in results that I do not want.

Perl complaints with the following text:

Reference found where even-sized list expected at ./configurator.pl line X.

I am doing it that way, since I want to use the module:

XML::Simple

In order to generate a XML file with the following structure:

 <settings>
  <username></username>
  <password></password>
  <database></database>
  <hostname></hostname>

  <dev_table></dev_table>

  <octopus>
      <alert_dir></alert_dir>
      <broadcast_id></broadcast_id>
      <subkey></subkey>
  </octopus>
 </settings>

so sometthing like:

my $data = $xmlFile->XMLout(%xmlStructure);
warn Dumper($data);

would display the latter xml sample structure.

Update:

I forgot to mention that I also tried using parenthesis instead of curly braces for the hash reference, and eventhough it seems to work, the XML file is not written properly: I end up with the following structure:

<settings>

 <dev_table>5L3IQWmNOw==</dev_table>
 <hostname>gQMgO3/hvMjc</hostname>

 <octopus>
  <alert_dir>l</alert_dir>
  <broadcast_id>l</broadcast_id>
  <subkey>l</subkey>
  <system_id>l</system_id>
 </octopus>

 <password>dZJomteHXg==</password>
 <username>sjfPIQ==</username>

</settings>

Which is not exactly wrong, but I'm not sure if I'm going to have problems latter on as the XML file grows bigger. The credentials are encrypted using RC4 algorith, but I am encoding in base 64 to avoid any misbehavior with special characters. Thanks


Solution

  • For your second issue, you should keep in mind that XML::Simple is indeed too simple for most applications. If you need a specific layout, you're better off with a different way of producing the XML, say, using HTML::Template. For example (I quoted variable names for illustrative purposes):

    #!/usr/bin/env perl
    
    use strict; use warnings;
    use HTML::Template;
    
    my $tmpl = HTML::Template->new(filehandle => \*DATA);
    $tmpl->param(
        hostname    =>  '$dbHost',
        username    =>  '$dbUsername',
        password    =>  '$dbPassword',
        dev_table   =>  '$dbTable',
        octopus     =>  [
            {
                alert_dir       =>  '$alert_dir',
                broadcast_id    =>  '$broadcast_id',
                system_id       =>  '$system_id',
                subkey          =>  '$subkey',
            }
        ]
    );
    
    print $tmpl->output;
    
    __DATA__
    <settings>
      <username><TMPL_VAR username></username>
      <password><TMPL_VAR password></password>
      <database><TMPL_VAR database></database>
      <hostname><TMPL_VAR hostname></hostname>
    
      <dev_table><TMPL_VAR dev_table></dev_table>
    
      <octopus><TMPL_LOOP octopus>
        <alert_dir><TMPL_VAR alert_dir></alert_dir>
        <broadcast_id><TMPL_VAR broadcast_id></broadcast_id>
        <subkey><TMPL_VAR subkey></subkey>
        <system_id><TMPL_VAR system_id></system_id>
      </TMPL_LOOP></octopus>
    </settings>
    

    Output:

    <settings>
      <username>$dbUsername</username>
      <password>$dbPassword</password>
      <database></database>
      <hostname>$dbHost</hostname>
    
      <dev_table>$dbTable</dev_table>
    
      <octopus>
        <alert_dir>$alert_dir</alert_dir>
        <broadcast_id>$broadcast_id</broadcast_id>
        <subkey>$subkey</subkey>
        <system_id>$system_id</system_id>
      </octopus>
    </settings>