in reply to Re^2: Update XML Values using two primary keys
in thread Update XML Values using two primary keys

When you build the hash, you can store both values (name and id) and each time compare to the existing id (a hash of hashes). If the new id isn't larger then just discard that row. You can then delete items from the hash as you go through the XML and add any left in the hash at the end.


🦛

  • Comment on Re^3: Update XML Values using two primary keys

Replies are listed 'Best First'.
Re^4: Update XML Values using two primary keys
by pratikpooja (Novice) on Jan 08, 2021 at 23:09 UTC

    I have created a routine to read the CSV file as a hash but I don't get how to compare to the existing id. Here is my piece of code. Can you please help how to do the comparison? Thank you.

    #!/usr/bin/perl use strict; use warnings; use Text::CSV; use Data::Dumper qw(Dumper); my $file = 'test_data.csv'; csv_hash($file); sub csv_hash { my ($filename) = @_; my $csv = Text::CSV->new ({binary => 1,auto_diag => 1,sep_char => + ';'}); open(my $data, '<:encoding(utf8)', $filename) or die "Could not op +en '$filename' $!\n"; my $header = $csv->getline($data); $csv->column_names($header); while (my $row = $csv->getline_hr($data)) { print(Dumper $row); } close $data; }

      Your code as presented is not building a HoH or indeed any single data structure at all from the CSV data. All it is doing is reading and printing it line by line. Replace your while loop with something like this (untested):

      my %HoH; while (my $row = $csv->getline_hr($data)) { my $key = "$row->{latitude}.$row->{longitude}"; # Compare next if exists $HoH{$key} && $row->{id} <= $HoH{$key}->{id}; # Set (or overwrite) $HoH{$key} = { name => $row->{name}, id => $row->{id} }; } # At this point I would return the hash (or a reference to it) but you + would need to change the calling line, of course

      See perldsc for more on such deep/nested structures.


      🦛

Re^4: Update XML Values using two primary keys
by pratikpooja (Novice) on Jan 10, 2021 at 22:34 UTC

    The HoH worked, Thank you. Since the HoH is not sorted so how can we compare the key of hashes with the node latitude and longitude and update the names. For e.g. what should be the condition in the if statement?

    my $inputfile = 'test_data.csv'; my $csv = Text::CSV->new ({binary => 1,auto_diag => 1,sep_char =>';'} +); open(my $data, '<:encoding(utf8)', $inputfile) or die "Could not open +'$inputfile' $!\n"; my $header = $csv->getline($data); $csv->column_names($header); my %HoH; while (my $row = $csv->getline_hr($data)) { my $key = "$row->{latitude}.$row->{longitude}"; # Compare next if exists $HoH{$key} && $row->{id} >= $HoH{$key}->{id}; # Set (or overwrite) $HoH{$key} = {name => $row->{name},id => $row->{id}}; } foreach my $key1 (keys %HoH) { print "'$key1'\n"; foreach my $key2 (keys %{$HoH{$key1}}) { print $key2=$HoH{$key1}{$key2},"\n"; } } my $myhash = \%HoH; my $dom = 'XML::LibXML'->load_xml(location => 'test.osm'); for my $node ($dom->findnodes('/osm/node')) { my $tag = $node->findnodes('tag[@k="name"]')->[0]; print $tag,"\n"; if () { } }

      Just build the key from the lat and lon as before:

      for my $node ($dom->findnodes('/osm/node')) { my $tag = $node->findnodes('tag[@k="name"]')->[0]; print $tag,"\n"; my $key = "$node->{lat}.$node->{lon}"; if (exists $HoH{$key}) { print "Matching key found for $key with id $HoH{$key}->{id}\n" +; # Do something useful with it here } }

      🦛

        Thank you. I am trying to add the rejected HoH to the XML as new nodes in the else part of the statement but I am getting error in forming the new XML with the rejected HoH.

        my $myhash = \%HoH; my $dom = 'XML::LibXML'->load_xml(location => 'test.osm'); for my $node ($dom->findnodes('/osm/node')) { my $tag = $node->findnodes('tag[@k="name"]')->[0]; my $key = "$node->{lat}.$node->{lon}"; if (exists $HoH{$key}){ $tag->{v} = $HoH{$key}->{name}; $node->{id} = $HoH{$key}->{id}; } else { print "$_\n" for keys %HoH; my($lat_key, $lon_key) = split(/./, $, 2); my $new_node = 'XML::LibXML::Element'->new("node"); my $id = 'XML::LibXML::Attr'->new("id",$HoH{$key}->{id}); my $lat = 'XML::LibXML::Attr'->new("lat",$lat_key); my $lon = 'XML::LibXML::Attr'->new("lon",$lon_key); $new_node->setAttribute($id); $new_node->setAttribute($lat); $new_node->setAttribute($lon); my $new_node_child = 'XML::LibXML::Element'->new("tag"); my $k = 'XML::LibXML::Attr'->new("k",'name'); my $v = 'XML::LibXML::Attr'->new("v",$HoH{$key}->{name}); $new_node_child->setAttribute($k); $new_node_child->setAttribute($v); $new_node->addChild($new_node_child); } } $dom->toFile('new_test.osm');