use strict; use warnings; use XML::Twig; # Could specify $infile in @ARGV, but this is a specialized use case my $infile = 'DPNoncashDetails.xml'; #************************************************* open( my $outfh, '>', $infile . '.txt' ) or die $!; my %data; # holds item and pricing data my $twig = XML::Twig->new( start_tag_handlers => { Item => \&item } ); $twig->parsefile( $infile ); my @fields = ( 'name', 'Like New', 'Minor Wear', 'Average Wear' ); print $outfh '# ', join( "\t", 'Category', @fields ), "\n"; foreach my $treestr ( sort { $a cmp $b } keys %data ) { my $h = $data{$treestr}; foreach my $id ( sort { $h->{$a}{name} cmp $h->{$b}{name} } keys %$h ) { print $outfh join( "\t", $treestr, @{ $h->{$id} }{ @fields } ), "\n"; } } #************************************************* sub item { my ( $twig, $elt ) = @_; my $tree = get_category_tree( $elt ); $tree = join( " => ", @$tree ); my $href = $elt->atts; verify_id( $tree, $href ); $data{$tree}{ $href->{itemNum} }{name} = $href->{name}; $data{$tree}{ $href->{itemNum} }{ $href->{quality} } = $href->{fmv}; } sub get_category_tree { my ( $elt ) = @_; my @tree; while( my $parent = $elt->parent ) { last if $parent->tag eq 'NonCashDetails'; next if $parent->tag ne 'Category'; unshift( @tree, $parent->att('name') ); $elt = $parent; } return \@tree; } sub verify_id { my ( $tree, $href ) = @_; my $id = $href->{itemNum}; my $name = $href->{name}; if( exists $data{$tree} && exists $data{$tree}{$id} ) { if( $name ne $data{$tree}{$id}{name} ) { print "Warning: about to overwrite data due to record mismatch\n"; print " $tree, item id = $id:\n"; print " [existing]: $data{$tree}{$id}{name}\n"; print " [new]: $name\n"; } } }