Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

Re: Logic Help - Output to csv

by haukex (Bishop)
on Jun 07, 2020 at 22:11 UTC ( #11117793=note: print w/replies, xml ) Need Help??


in reply to Logic Help - Output to csv

Assuming none of the downloads, group, or group_items elements can be repeated in a single product, here's a slightly simpler way with XML::Rules (but XML::LibXML would probably still be my personally preferred solution):

use warnings; use strict; use XML::Rules; use Text::CSV; my $parser = XML::Rules->new( stripspaces => 3|4, rules => [ 'products|downloads|group|group_items' => 'pass', product => 'by sku', 'sku|name|url' => 'content', item => sub { $_[1]->{name} => $_[1]->{url} }, _default => sub { die "Unknown tag $_[0]" } ], ); my $itms = $parser->parse_file('example.xml'); my @columns = sort keys %{{map {$_=>1} map {keys %$_} values %$itms}}; my $csv = Text::CSV->new({binary=>1, auto_diag=>2, eol=>$/, always_quote=>1 }); $csv->print(select, ["sku", @columns]); for my $sku (sort keys %$itms) { $csv->print(select, [$sku, map { $itms->{$sku}{$_} } @columns ]); }

Replies are listed 'Best First'.
Re^2: Logic Help - Output to csv
by audioboxer (Acolyte) on Jun 07, 2020 at 23:19 UTC
    Thank you Haukex, you池e always helping me out. Works great. I have no idea what you did but it gives me a place to start and learn.

    Follow up question. I知 trying to print this out to a file but I知 getting errors about print usage. This is what I did

    open my $fh, "<:encoding(utf8)", "output.csv" or die "output.csv: $!"; my $csv = Text::CSV->new({binary=>1, auto_diag=>2, eol=>$/, always_quote=>1 }); $csv->print($fh, (select, ["sku", @columns])); for my $sku (sort keys %$itms) { $csv->print($fh, (select, [$sku, map { $itms->{$sku}{$_} } @column +s ])); }
    Thanks again
      open my $fh, "<:encoding(utf8)", "output.csv" or die "output.csv: $!";

      You have called your file output.csv but have opened it for reading. That's contradictory.

      I知 getting errors about print usage

      Why keep them a secret? In general, always supply the full, exact text of any error message you have.

      I have no idea what you did but it gives me a place to start and learn.

      Yes, XML::Rules does take a bit of studying its docs to understand all the rules. As for my XML::LibXML code, I hope that's a bit more clear. If you add use Data::Dump; at the top and add a dd \%items; just after the loop, you'll see the data structure:

      { "00123" => { "File 1" => "www.site.com/path/to/file/file.pdf", "File 2" => "www.site.com/path/to/file/file.pdf", }, "00124" => { "File 1" => "www.site.com/path/to/file/file.pdf", "File 6" => "www.site.com/path/to/file/file.pdf", }, "00125" => { "File 2" => "www.site.com/path/to/file/file.pdf", "File 7" => "www.site.com/path/to/file/file.pdf", }, }

      The other tricky bit is the line that generates the @columns array. It has two main parts: map {keys %$_} values %items takes the values of the %items, which are hashes themselves ({ "File 1" => "www..." etc.), and then uses map to get the keys of each of those hashes. In other words, the map statement will return the list "File 1", "File 2", "File 1", "File 6", .... The second part is the keys %{{map {$_=>1} ...}}, which is an idiom to get only unique values from a list. It does this by first building an anonymous hash with {map {$_=>1} values}, and then immediately dereferencing the hash (%{...}) and getting its keys. Then, all that's left to do is sort the unique strings.

      I知 trying to print this out to a file but I知 getting errors about print usage.

      What hippo said: first, you're opening the file for reading instead of writing. Second, note that the first argument of $csv->print should be the filehandle, which you did, but note that I was getting the output filehandle (STDOUT by default) using select, so you need to remove that call. This works for me:

      open my $fh, ">:encoding(UTF-8)", "output.csv" or die "output.csv: $!" +; my $csv = Text::CSV->new({binary=>1, auto_diag=>2, eol=>$/, always_quote=>1 }); $csv->print($fh, ["sku", @columns]); for my $sku (sort keys %$itms) { $csv->print($fh, [$sku, map { $itms->{$sku}{$_} } @columns ]); } close $fh;

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11117793]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (3)
As of 2021-07-26 16:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found

    Notices?