Here's an implementation that uses both arrays and hashes, to make an internal perl representation of the data that corresponds more closely (compared to a just arrays) to what you need to output. The output loop therefore becomes a bit simpler.
Note that I stubbed out the CSV processing module you're using. My CSV parsing is a bit rougher around the edges :-)#!/usr/bin/perl use strict; use warnings; #use Text::CSV_XS; my $csv = CSV_Stub->new(); my $file = ''; if (defined $ARGV[0]) { $file = $ARGV[0]; } open(my $data, '<', $file) or die "Could not open '$file'\n"; # Get raw textual input: an array of strings my @input = <$data>; close $data; # Convert CSV text into an array of arrays @input = map { $csv->parse($_); [$csv->fields()] } @input; # Use input data to build a data structure which maps (fairly closely) + onto what we want to output # A hash of arrays # Key = order id # Value = the array of items in that order my %internalRepresentation; foreach my $input (@input) { push @{$internalRepresentation{$input->[0]}}, { name => $input->[1], itemId => $input->[2], itemDesc => $input->[3], price => $input->[4], } } # For each order we want to output: foreach my $orderNumber (keys %internalRepresentation) { open (OUTFILE, "> output/$orderNumber.xml") or die $! . " can't op +en the file\n"; print OUTFILE "<order>\n"; print OUTFILE " <order_id>$orderNumber</order_id>\n"; print OUTFILE " <name>$internalRepresentation{$orderNumber}->[0] +->{name}</name>\n"; # For each item in the order: foreach my $item (@{$internalRepresentation{$orderNumber}}) { print OUTFILE " <item>\n"; print OUTFILE " <item_id>$item->{itemId}</item_id>\n"; print OUTFILE " <item_desc>$item->{itemDesc}</item_desc>\n +"; print OUTFILE " <price>$item->{price}</price>\n"; print OUTFILE " </item>\n"; } print OUTFILE "</order>\n"; close OUTFILE; } package CSV_Stub; sub new { return bless {}, shift; } sub parse { my $self = shift; my $line = shift; chomp $line; $self->{currentFields} = [split ",", $line]; return 1; } sub fields { my $self = shift; return @{$self->{currentFields}}; }
Also note that in the input, the order name is repeated for each item in the order. In the internal representation, it's still repeated. Hence, in the output loop, it gets the name for the order from the first item in the order. Ie:
is used when it outputs the name. If you were seeking perfection, you'd need to avoids this redundancy in the internal representation, by only storing the name once per order. That means that the structure of the data would need to change to accommodate it. I'll leave that option to you :-)->[0]
--
use JAPH;
print JAPH::asString();
In reply to Re^3: merging .csv text input based on matching column field values in multiple rows
by wol
in thread merging .csv text input based on matching column field values in multiple rows
by abrg
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |