Let perl do it for you. Put the pen in paragraph mode :
$/ = "";
while (<>) {
...
}
Now, at each iteration, the loop $_will contain an entire record, where each record is separated by two or more newline characters.
See in action:
use warnings;
use strict;
use 5.10.0;
my $equipconst = qr/
^
constant \s+ fixup \s+ (?:private \s+)?
(?<logicalName>.+?) # non-greedy to right-trim whitespace
\s+ = \s+
< (?<valueType>\S+) \s+ (?<value>\S+) >
/x;
my $equipattr = qr/
\s*
(?<name>\S+)
\s* = \s*
(?<value>.+?) # must be non-greedy!
/x;
*ARGV = *DATA;
print "<EquipmentConstants>\n";
$/ = "";
while (<>) {
if (/$equipconst/g) {
my @attrs = map [ $_ => $+{$_} ] =>
qw/ logicalName valueType value /;
while (/\G $equipattr (?=\s*$|$equipattr)/gx) {
my($name,$value) = @+{ qw/ name value / };
$value =~ s/<.+ (.+)>/$1/;
push @attrs => [ $name => $value ];
}
my $attrs = join " ",
map {
$_->[1] =~ s/^"(.*)"$/$1/;
qq{$_->[0]="$_->[1]"};
}
@attrs;
print "<ECID $attrs></ECID>\n";
}
}
print "</EquipmentConstants>\n";
__DATA__
constant fixup GemEstabCommDelay = <U2 20>
vid = 6
name = "ESTABLISHCOMMUNICATIONSTIMEOUT"
units = "s"
min = <U2 0>
max = <U2 1800>
default = <U2 20>
constant fixup private GemConstantFileName = <A "C:\\TMP\\CONST.LOG">
vid = 4
name = "" units = ""
constant fixup private GemAlarmFileName = <A "C:\\TMP\\ALARM.LOG">
vid = 0
name = ""
units = ""
Output:
<EquipmentConstants>
<ECID logicalName="GemEstabCommDelay" valueType="U2" value="20" vid="6" name="ESTABLISHCOMMUNICATIONSTIMEOUT" units="s" min="0" max="1800" default="20"></ECID>
<ECID logicalName="GemConstantFileName" valueType="A" value="C:\\TMP\\CONST.LOG" vid="4" name="" units=""></ECID>
<ECID logicalName="GemAlarmFileName" valueType="A" value="C:\\TMP\\ALARM.LOG" vid="0" name="" units=""></ECID>
</EquipmentConstants>
, spec: logicalName .