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

What if there are some tag values which are in csv file and that needs to be added as new nodes in xml file with the maximum node id assigned. For e.g.-

"latitude";"longitude";"name";"id" 59.58464;8.56069;A13_PRA_KEI;-1643794 59.58464;8.56069;A13_RAT_KEI;-1643795 59.59465;8.57070;A14_PQR_KEI;-1643796
The first 2 rows have same lat and long value but the 2nd row value needs to be added in xml file as it has maximum node id value. Thank you.

Replies are listed 'Best First'.
Re^3: Update XML Values using two primary keys
by hippo (Archbishop) on Jan 07, 2021 at 19:05 UTC

    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.


    🦛

      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.


        🦛

      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 } }

        🦛