Search code examples
xmlperlparameterssubroutine

How to pass parameters in Perl with out data getting altered


I have curious problem I can't get around. Can you please see what I am doing wrong. I am trying to build an XML in Perl using XML::LibXML. All works fine until I start building sub routine and pass arguments.

First The code that works

 my $root = $doc->createElement("XML_FILE");
 my @sortedOuterTags = qw ( JMS_VERSION
                       FILE_NAME
                       SUBMIT_BY
                       SUBMIT_DATE
                      );

# Use hash slice to access the list in hash elements
# Remember has elements are accessed randomly, hence hash slice-ing

 my %outHashTags;
 @outHashTags { @sortedOuterTags } = ( 'data1',
                                'data2',
                                'data3',
                                'data3');

for my $name (@sortedOuterTags) {
    my $outTag = $doc->createElement($name);
    my $outValue = $outHashTags{$name};
    $outTag->appendTextNode($outValue);
    $root->appendChild($outTag);
}

Builds output:

<JMS_VERSION>data1</JMS_VERSION>

<FILE_NAME>data2</FILE_NAME>

<SUBMIT_BY>data3</SUBMIT_BY>

<SUBMIT_DATE>data4</SUBMIT_DATE>

Now the error:

As soon as I spin off for loop to an sub routine as show below I get errors. I am passing 3 paramenters. 1) can't get array values of storedReportTag 2) can't get %reportHashTag data 3) $report element is empty

Code:

buildXMLElements(\@sortedReportTag, %reportHashTags, $report);

sub buildXMLElements() {
    my( @elementTags, %hashTags, $parentElement) = @_;

    for my $name (@elementTags) {
        my $reportTag = $doc->createElement($name);
        my $reportValue = $hashTags{$name};
        $reportTag->appendTextNode($reportValue);
        $parentElement->appendChild($reportTag);
    }
}

I want to put in sub as I have several tags to build to re-use the code. I tried passing parameters both directly and as reference.......

Thank you

Update:

After editing my Sub it now looks like this:

buildXMLElements(\@sortedReportTag, \%reportHashTags, $report);

sub buildXMLElements() {
    my($elementTags, $hashTags, $parentElement) = @_;
    for my $name (@$elementTags) {
        my $reportTag = $doc->createElement($name);
        my $reportValue = $hashTags->[$name];
        $reportTag->appendTextNode($reportValue);
        $parentElement->appendChild($reportTag);
    }
}

it dies at the line:

my $reportValue = $hashTags->[$name];

Final update:

With Jim's help I corrected the code: Here is final version that works

buildXMLElements(\@sortedReportTag, \%reportHashTags, $report);

sub buildXMLElements() {
    my($elementTags, $hashTags, $parentElement) = @_;
        for my $name (@$elementTags) {
        my $reportTag = $doc->createElement($name);
        my $reportValue = $hashTags->{$name};
        $reportTag->appendTextNode($reportValue);
        $parentElement->appendChild($reportTag);
    }
}

Solution

  • buildXMLElements(\@sortedReportTag, %reportHashTags, $report);
    ...
    sub buildXMLElements() {
      my( @elementTags, %hashTags, $parentElement) = @_;
    

    You can't do that. The entire contents of @_ will be assigned to @elementTags. To pass arrays or hashes to a subroutine you must pass a reference. Try instead

    buildXMLElements(\@sortedReportTag, \%reportHashTags, $report);
    ...
    sub buildXMLElements() {
      my( $elementTags, $hashTags, $parentElement) = @_;
    

    Now, in the subroutine $elementTags is an array reference, and $hashTags is a hash reference. To refer to an element of elementTags use $elementTags->[$i] or to refer to the entire array do @$elementTags. Likewise, for reportHashTags key lookup use $hashTags->[$key], or for the entire hash use %$hashTags.