2

I am hoping to make a loop that allows me to use less lines of code to make changes to a settings file with Perl. Currently my code reads an XML file and locates a settings ID and replaces the setting value in that ID with a new one. The current request involves a lot of changes to the settings file and the code is very long. I have set my values in an array and my settings ID's in an array. Like this:

@GreetGoalDP1 = (3, 5, 7, 10);
@GreetSIDSunDP1 = ('//xsd:Settings/xsd:Setting[@SID="7012"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7013"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7014"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7015"]/xsd:Value');

and run the following.

my($matchSunDP1G1) = $xpc->findnodes($GreetSIDSunDP1[0]);
$matchSunDP1G1->removeChildNodes();
$matchSunDP1G1->appendText($GreetGoalDP1[0]);
#GreetB
my($matchSunDP1G2) = $xpc->findnodes($GreetSIDSunDP1[1]);
$matchSunDP1G2->removeChildNodes();
$matchSunDP1G2->appendText($GreetGoalDP1[1]);
#GreetC
my($matchSunDP1G3) = $xpc->findnodes($GreetSIDSunDP1[2]);
$matchSunDP1G3->removeChildNodes();
$matchSunDP1G3->appendText($GreetGoalDP1[2]);
#GreetD
my($matchSunDP1G4) = $xpc->findnodes($GreetSIDSunDP1[3]);
$matchSunDP1G4->removeChildNodes();
$matchSunDP1G4->appendText($GreetGoalDP1[3]);

I would like to run these changes through a loop just using the array [0] - [3] until completed as I have to do this same set of 4 multiple times. I am not too familiar with looping arrays. Is this something I can do in Perl? If so, what would be the most efficient way to do so?

3 Answers 3

2

A simple take

use warnings;
use strict;
...

for my $i (0..$#GreetGoalDP1) {
    my ($matchSunDP1G) = $xpc->findnodes( $GreetSIDSunDP1[$i] );
    $matchSunDP1G->removeChildNodes();
    $matchSunDP1G->appendText( $GreetGoalDP1[$i] );
}

I take it that you don't need all those individual $matchSunDP1G1 etc. It's assumed that the two arays always have the same length, and their elements are needed in pairs at same indices.

The syntax $#aryname is for the last index in the array @aryname, and .. is the range operator, so 0 .. $#GreetGoalDP1 for your example is the list 0,1,2,3.

Then there are libraries that help with use of multiple arrays in parallel, that can be particularly useful when things get messier or more complicated. An example of using an iterator

use List::MoreUtils qw(each_array);

my $it = each_array @GreetSIDSunDP1, @GreetGoalDP1;

while ( my ($sidsun, $goal) = $it->() ) {
    my ($matchSunDP1G) = $xpc->findnodes($sidsun);
    $matchSunDP1G -> removeChildNodes();
    $matchSunDP1G -> appendText( $goal );
}

If the lists are uneven in size the iterator keeps going through the length of the longer one. After the shorter one gets exhausted its would-be value is undef.

Sign up to request clarification or add additional context in comments.

8 Comments

Thank you for the feedback. I gave the simple take a try and was able to get the first value to update but the remaining value in the array did not change. I believe it may be because the $matchSunDP1 also needs to change with each loop. Does that sound correct? Is there a way to just increase the number by 1 each loop, to the end of the $matchSunDP1?
@TaylorStevens That is strange -- the $GreetSIDSunDP1[$i] and $GreetGoalDP1[$i] elements are exactly like the ones typed in by hand in the question. All that the first snippet in the answer does is to put those indices in the loop instead of entering them manually. And $matchSunDP1G is made anew every time through, even declared anew (that's the my in front). I don't see what could be different (wrong) with the loop?
@TaylorStevens Fixed typos -- missing closing ), and I added G to the name (that's irrelevant)
@TaylorStevens Ah, that explains it. The syntax $#aryname is for the index of the last element in the array @aryname. (This code always had $#GreetGoalDP1, must've gotten lost when you copied it.) So for @ary = (5,6,7); the $#ary is 2 (index of the last value in it, 7). That .. is the "range operator" and when we say 0 .. 3 that is expanded into (0, 1, 2, 3). So 0 .. $#ary (with the array in this example) is 0..2, so the list 0, 1, 2. In your question there are four elements so the loop goes over 0,1,2,3.
@TaylorStevens Let me say this just in case: Make sure to always have use warnings; at the beginning of a program. It catches all kinds of bad things, it is really really helpful. (I suspect that here it would've told you about something wrong, due to a copy-paste error.) Then another good one is use strict;, which forces you to declare things with my.
|
1

Following code sample demonstrates how you could use %hash for alternation you try to achieve.

my %hash = (
        3   => '//xsd:Settings/xsd:Setting[@SID="7012"]/xsd:Value',
        5   => '//xsd:Settings/xsd:Setting[@SID="7013"]/xsd:Value',
        7   => '//xsd:Settings/xsd:Setting[@SID="7014"]/xsd:Value',
        10  => '//xsd:Settings/xsd:Setting[@SID="7015"]/xsd:Value')
);

while( my($k,$v) = each %hash ) {
    my $match = $xpc->findnodes($v);
    $match->removeChildNodes();
    $match->appendText($k);
}

Reference: hash, hash operations

Comments

1

Yet Another Way, using zip from the core List::Util module:

#!/usr/bin/env perl
use warnings;
use strict;
use List::Util qw/zip/;

...;

my @GreetGoalDP1 = (3, 5, 7, 10);
my @GreetSIDSunDP1 = ('//xsd:Settings/xsd:Setting[@SID="7012"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7013"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7014"]/xsd:Value', 
'//xsd:Settings/xsd:Setting[@SID="7015"]/xsd:Value');

foreach my $pair (zip \@GreetSIDSunDP1, \@GreetGoalDP1) {
    my ($matchSunDP1G1) = $xpc->findnodes($pair->[0]);
    $matchSunDP1G1->removeChildNodes();
    $matchSunDP1G1->appendText($pair->[1]);

}

2 Comments

Should copyright that YAW (yet-another-way), Well, at least disseminate widely :)
@zdim "There's more than one way to say TMTOWTDI©"?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.