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

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');

Replies are listed 'Best First'.
Re^7: Update XML Values using two primary keys
by hippo (Archbishop) on Jan 11, 2021 at 23:05 UTC
    my($lat_key, $lon_key) = split(/./, $, 2);

    The first argument to split is a regular expression in which the dot is a metacharacter and should be escaped. Note that since both lat and lon also contain a dot perhaps some other separator character would be a better choice if you want to split the keys. A comma would do and would not need to be escaped.

    but I am getting error

    You've chosen not to share the precise text of the error message. I cannot imagine why.


    🦛

      Sorry, It was my mistake, I pasted the wrong code. The correct code is below. I am trying to add new nodes in the XML with the rejected HoH keys but during building, I am getting an error of "bad name at /usr/local/lib/x86_64-linux-gnu/perl/5.30.0/XML/LibXML.pm".

      When I am splitting the key to lat long, it gets split with the number, not the decimal part.

      In the else part, how can I get the rejected HoH keys?

      Thank you.
      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 { foreach my $key (keys %HoH) { #print $key,"\n"; my ($lat_key,$lon_key) = (split /[.]/, $key)[0,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');
        When I am splitting the key to lat long, it gets split with the number, not the decimal part.

        I'm not the best one to help with XML stuff, but I can perhaps offer help on this. I think the best approach is not to split away what you do not want, but to extract what you do want, real numbers in this case. The Regexp::Common module is useful in this, for it defines a real-number pattern.

        Win8 Strawberry 5.30.3.1 (64) Tue 01/12/2021 14:15:24 C:\@Work\Perl\monks >perl -Mstrict -Mwarnings # pm#11126809 use Regexp::Common qw(number); my $rx_lat_lon = qr{ (?<! \d) $RE{num}{real} (?! \d) }xms; for my $lat_lon ( '123,456', '12.345, -0', ' -2. , 0.987', ' -.0 ,0.987 ', '0, -0', '.0 ,-.0', '0. , -0.', ' 0.0 , -0.0 ', '1, -1', '.1 ,-.1', '1. , -1.', ' 1.2 , -1.2 ', '123 456', '123', 'foo', '123,foo', 'foo,123', '1.234.5', ) { my $got_lat_lon = my ($lat, $lon) = $lat_lon =~ m{ \A \s* ($rx_lat_lon) \s* , \s* ($rx_lat_lon) \s* \z + }xms; # $lat_lon =~ m{ $rx_lat_lon }xmsg; # no data validation if ($got_lat_lon) { printf "%18s -> lat %-10s lon %-10s \n", "'$lat_lon'", n_or_undef($lat), n_or_undef($lon); } else { print "'$lat_lon' FAILED to extract lat/lon \n"; } } sub n_or_undef { return defined $_[0] ? "'$_[0]'" : 'undef'; } ^Z '123,456' -> lat '123' lon '456' '12.345, -0' -> lat '12.345' lon '-0' ' -2. , 0.987' -> lat '-2.' lon '0.987' ' -.0 ,0.987 ' -> lat '-.0' lon '0.987' '0, -0' -> lat '0' lon '-0' '.0 ,-.0' -> lat '.0' lon '-.0' '0. , -0.' -> lat '0.' lon '-0.' ' 0.0 , -0.0 ' -> lat '0.0' lon '-0.0' '1, -1' -> lat '1' lon '-1' '.1 ,-.1' -> lat '.1' lon '-.1' '1. , -1.' -> lat '1.' lon '-1.' ' 1.2 , -1.2 ' -> lat '1.2' lon '-1.2' '123 456' FAILED to extract lat/lon '123' FAILED to extract lat/lon 'foo' FAILED to extract lat/lon '123,foo' FAILED to extract lat/lon 'foo,123' FAILED to extract lat/lon '1.234.5' FAILED to extract lat/lon
        (I haven't tested it, but I think this code will work under virtually any Perl version. (Update: Counter-examples are welcome!))

        Some comments:

        • The $RE{num}{real} pattern is not bounded (by design!), so defining an explicit $rx_lat_lon bounded pattern with
              my $rx_lat_lon = qr{ (?<! \d) $RE{num}{real} (?! \d) }xms;
          is IMHO good practice and gives you a single point at which to change the definition of a lat/lon value should this become necessary.
        • Defining an explicit pattern for matching a lat/lon field with
              m{ \A \s* ($rx_lat_lon) \s* , \s* ($rx_lat_lon) \s* \z }xms
          is again good practice IMHO because it can provide for a high degree of data validation. The $got_lat_lon flag is true if valid data is extracted.
        • If you are certain there will always be exactly two lat/lon sub-fields present and you don't care what else is there, you can use the simpler
              m{ $rx_lat_lon }xmsg
          matching expression (note the /g modifier). The $got_lat_lon flag becomes almost meaningless in this case.


        Give a man a fish:  <%-{-{-{-<

Re^7: Update XML Values using two primary keys
by AnomalousMonk (Archbishop) on Jan 11, 2021 at 23:24 UTC
    my($lat_key, $lon_key) = split(/./, $, 2);

    In addition to hippo's comment, note that the quoted extract from this does not compile. While there is a $, Perl special variable (see perlvar), you don't seem to be using it (nor would I recommend doing so in this application). I suspect this is just a cut/paste error and not the error your code is actually producing, but again, who knows?

    Win8 Strawberry 5.8.9.5 (32) Mon 01/11/2021 18:12:15 C:\@Work\Perl\monks >perl -Mstrict -Mwarnings $, = 'foo.bar'; my($lat_key, $lon_key) = split(/\./, $, 2); Number found where operator expected at - line 3, near "$, 2" (Missing operator before 2?) ^Z syntax error at - line 3, near "$, 2" Execution of - aborted due to compilation errors.


    Give a man a fish:  <%-{-{-{-<

      Sorry, It was my mistake, I pasted the wrong code. The correct code is given in the comment section.