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

Dear Wise and Kind Monks:

The code below is mis-behaving when it does not find the XML element it is looking for.
If I look for "IssuerCountry" the correct customBucketValue is returned.

However, if I look for "SandPRating" which is not contained in the customBucketList, the code mis-behaves. In this case @rtnVal returned is defined. I would expect it to be undefined. The code does not do the assignment to @rtnVal so I would expect @rtnVal to be undefined.

many thanks for your kind assistance

kd

sub getCBLValue { my ($cblIn, $cbNameIn); my @cdn = undef; my $textEl = undef; my @rtnVal = undef; # return the CustomBucketValue element #** ** ** ** ** ** ** ** ** # pass in the customBucketList and the name of the # dimension to look for ($cblIn, $cbNameIn) = @_; foreach my $cb ( $cblIn->getChildNodes() ) { if ($cb->getNodeType() == ELEMENT_NODE && $cb->getNodeName() eq 'customBucket' ) { print '$cb node name: ' .$cb->getNodeName() . ' type: ' . n +odeTypeText($cb->getNodeType() ) . "\n"; #scanner( $cb ); @cdn = $cb->getElementsByTagName("customDimensionName", 0); #print scalar @cdn; $textEl = $cdn[0]->getFirstChild(); if ( $textEl->getData() eq $cbNameIn ) { print "\n Assignment to rtnVal "; @rtnVal = $cb->getElementsByTagName("customBucketValue", 0); last; } } # if customBucket node } # foreach print "\n Return from getCBLValue: " ; print ( defined(@rtnVal) ? " defined \n" : " undefined \n" ); return @rtnVal; } # getCBLValue


given a node that contains XML like the following:
<customBucketList> <customBucket> <customDimensionName>GSEC_SecuritySubType</customDimensionName> <customBucketValue>1041</customBucketValue> </customBucket> <customBucket> <customDimensionName>IssuerCountryOfDomicile</customDimensionName> <customBucketValue>US</customBucketValue> </customBucket> <customBucket> <customDimensionName>icbSubSector</customDimensionName> <customBucketValue>Banks</customBucketValue> </customBucket> <customBucket> </customBucketList>


Replies are listed 'Best First'.
Re: defined or undef
by ikegami (Patriarch) on Oct 30, 2007 at 14:54 UTC

    defined is not meant to be used on arrays and must not be used on arrays in forward-compatible code. It doesn't do anything meaningful.

    There's some uncertainty as to what you are trying to do.

    • Are you trying to return a list (0 or more items)? If so, you probably want to count the number of elements in the array.

      print("Number of elements: ", scalar(@rtnVal), "\n");

      That will reveal that you do have a bug.
      my @rtnVal = undef;
      should be
      my @rtnVal = ();
      or just
      my @rtnVal = undef;

    • Are you trying to return a scalar (1 item or undefined)? If so, you shouldn't be using an array. In fact, your code actually behaves as if @rtnVal is a scalar. If you change it to a scalar $rtnVal, you should get the results you were expecting.

    Update: Added second bullet.

      I am attempting to return a list, because getElementsByTagName retruns a list. In this case the list sould contain one item.

      my @rtnVal = undef;
      is adding an undefined element to the @rtnVal array? Oh my. Not what I expected.

      Is this valid code
      print ( @rtnVal ? " defined \n" : " undefined \n" );

      Please take a look at your suggested code. I do believe that your second suggestion is what I have.

      thanks for your quick reply.

      kd

        Undefined is a special *scalar* value. It makes no sense to call an array undefined, so that should read
        print ( @rtnVal ? " not empty \n" : " empty \n" );

        Whether getElementsByTagName returns an list or not is irrelevant. I was asking what did you want getCBLValue to return.

Re: defined or undef
by Jenda (Abbot) on Oct 31, 2007 at 21:07 UTC

    Are you sure you are using the right module? The DOM objects look ... erm ... rather inconvenient to me. Assuming you parsed the XML using XML::Rules and used these rules:

    ..., 'customDimensionName,customBucketValue' => 'content', 'customBucket' => sub { '@'.$_[1]->{customDimensionName} => $_[1]-> +{customBucketValue} }, 'customBucketList' => 'no content', ...
    and already had in $cblIn a reference to the hash containing the bucket list, then getting the values would be just @{$cblIn->{$cbNameIn}}. And the memory footprint would be much smaller.