#!/usr/bin/perl use strict; use warnings; use XML::Simple; use Text::CSV; my $in_file=shift(@ARGV); my $out_file=shift(@ARGV); my $namesep='>'; my $print_names=1; # parse XML my $tree=XMLin($in_file, KeyAttr => {}, KeepRoot => 1); my @names; my @lines; # finde alle Namen # und löse den Baum auf: my @stack=([$tree,'',{}]); while(@stack) { my ($t,$p,$d)=@{shift(@stack)}; if(ref($t) eq 'HASH') { # daten der ebene einsammeln # kinder überspringen my $end=1; my %data=%$d; while( my ($k,$v)=each(%$t)){ if(ref($v)){ $end=0; } else{ my $pp="$p$namesep$k"; # unbekannten namen zur Liste push(@names,[$k,$pp]) unless( grep{ $_->[1] eq $pp }@names); $data{$pp}=$v; } } # es gibt keine kinder # Datensatz vollständig if($end) { push(@lines,\%data); } # Kinder auf den Stack while( my ($k,$v)=each(%$t)) { my $pp="$p$namesep$k"; if(ref($v) eq 'ARRAY') { for my $vv (@$v) { if(ref($vv)) { push(@stack,[$vv,$pp,{%data}]); } else { # unbekannten namen zur Liste push(@names,[$k,$pp]) unless( grep{ $_->[1] eq $pp }@names); push(@lines,{%data, $pp => $vv}); } } } elsif(ref($v) eq 'HASH') { push(@stack,[$v,$pp,{%data}]); } } } elsif(ref($t) eq 'ARRAY') { die("Fehler im Baum! $p\n"); } } # CSV schreiben: open( my $fh, ">:unix:encoding(UTF-8)", $out_file) or die "Can't open $out_file $!\n"; my $csv = Text::CSV->new({ binary => 1, eol => "\n", sep_char => ';' }); # Titelzeile schreiben wenn gewollt if($print_names > -1) { my @n = map{$_=~s/^\Q$namesep\E//s; $_}map{$_->[$print_names]}@names; $csv->print ($fh,\@n); } # Daten schreiben for my $data (@lines) { my @line; for my $n (@names) { push(@line,$data->{$n->[1]} // ''); } $csv->print ($fh,\@line); } close($fh);