# Entity, Attribute, Value # Value either SCALAR or ARRAY package EAVa; use strict; use warnings; use bytes; sub freeze{ my $pkg = shift; my $fh = shift; my $eav = shift; seek $fh,0,0; foreach my $ent( keys %{$eav} ){ foreach my $att( keys %{$eav->{$ent}} ){ my $val = $eav->{$ent}{$att}; if(ref $val eq 'ARRAY'){ if(scalar @{$val}){ foreach my $aval( @{$val} ){ ($aval, my $defb) = defined $aval ? ($aval,3) : ('',2); print $fh pack("NNNC", length($ent), length($att), length($aval), $defb).$ent.$att.$aval; } } else{ ($val, my $defb) = ('',4); print $fh pack("NNNC", length($ent), length($att), length($val), $defb).$ent.$att.$val; } } else{ ($val, my $defb) = defined $val ? ($val,1) : ('', 0); print $fh pack("NNNC", length($ent), length($att), length($val), $defb).$ent.$att.$val; } } } } sub thaw{ my $pkg = shift; my $fh = shift; my %res = (); seek $fh,0,0; while( read($fh, my $buffer, 13)){ my($elen, $alen, $vlen, $defb) = unpack "NNNC", $buffer; read($fh, my $ent, $elen); read($fh, my $att, $alen); read($fh, my $val, $vlen); $val = $defb == 1 || $defb == 3 ? $val : undef; if($defb == 0 || $defb == 1){ $res{$ent}{$att} = $val } elsif( $defb == 4 ){ $res{$ent}{$att} = [] } else{ push @{$res{$ent}{$att}}, $val } } return \%res; } 1;######################################################################### package main; use Data::Dumper; use IO::String; use strict; use warnings; my $fh = IO::String->new; my $eav = { foo => { sca => undef, numbers => [1,2,'',undef], name => 'bar', blank => '', nix => [], }, }; EAVa->freeze($fh, $eav); seek $fh,0,0; my $res = EAVa->thaw($fh); print Dumper $eav,$res;