daniel99 has asked for the wisdom of the Perl Monks concerning the following question:

I need to extract the data elements in a data file containing curly brace neted data to produce a list of NAT pairs. For example, here is a dump from our Palo Alto FW:

------------------ Sample input { { { Prod1_Core_10.2.6.1 { to WAN; from WAN; source any; destination 8.39.63.3; service service-https; to-interface any; destination-translation { translated-address 10.2.6.1; } description "Static NAT to Core 10.2.6.1"; } Prod1_Core_10.2.6.2 { to WAN; from WAN; source any; destination 8.39.63.4; service service-https; to-interface any; destination-translation { translated-address 10.2.6.2; } description "Static NAT to Core 10.2.6.2"; } } } end sample input ---------------

Essentially, we want to extract these values:

>>>> Prod1_Core_10.2.6.2 { to WAN; from WAN; source any; >>>> destination 8.39.63.4; service service-https; to-interface any; destination-translation { >>>> translated-address 10.2.6.2; <<<<

From this data we need to produce a list of the nat pairs like:

queue = [ {:corename => "Prod1_Core_10.2.6.1", :pubip => "8.39.63.3", :privip + => "10.2.6.1"}, {:corename => "Prod1_Core_10.2.6.2", :pubip => "8.39.63.4", :privip +=> "10.2.6.2"}, ]

Is there a parser that will be able to map the data blocks in the nested data into single entities like a string?

any guidance is greatly appreciated :)

Daniel

2018-05-02 Athanasius changed pre to paragraph and code tags

Replies are listed 'Best First'.
Re: Parsing { } nested data in a file
by NetWallah (Canon) on May 02, 2018 at 00:56 UTC
    Here you go:
    use strict; use warnings; local $/="}\n"; my ($currentitem, %item); while (<>){ #print "---$_;;;\n"; for my $line (split "\n"){ if ($currentitem){ if ( $line=~ m/^\s*(\S+)\s*\{\s*$/){ #ignore "destination-translation"# ; }elsif ( $line=~/(\S+)\s+(\S+)\s*;/){ $item{$currentitem}{$1}=$2; } }elsif( $line=~ m/^\s*(\S+)\s*\{\s*$/){ $currentitem = $1 } } $currentitem=undef; } for my $name (sort keys %item){ print qq| \{:corename => "$name", :pubip => "$item{$name}{destinati +on}", :privip => "$item{$name}{'translated-address'}"},\n|; }
    Run:
    >perl 1213915.pl YourFileName.txt {:corename => "Prod1_Core_10.2.6.1", :pubip => "8.39.63.3", :privip + => "10.2.6.1"}, {:corename => "Prod1_Core_10.2.6.2", :pubip => "8.39.63.4", :privip + => "10.2.6.2"},
    Note: This depends on the format of the file having consistent braces. Not the smartest parser - just a hack.

                    Memory fault   --   brain fried

      Beautiful hack! thanks so much NetWallah :)
Re: Parsing { } nested data in a file
by Anonymous Monk on May 02, 2018 at 15:38 UTC
    It looks to me like a very simple awk-like approach would serve you just as well, if the data appears with one item per-line. Ignoring the braces completely, you can simply look for an identifier, followed by something, followed by a semicolon, grabbing the identifier and the something. (Or, an identifier followed by a left-brace.) Since you know the sequence of the items in the file you can simply process the file line-by-line in this way.

      It If it would be very simple, please take 5 minutes to write the code to demonstrate the idea. Perl does awk quite nicely after all and the more approaches demonstrated, the better.

        Instead, it is quite reasonable to assume that the OP was not born yesterday. Every significant \n-delimited line of any interest within the file as presented contains an instantly-identifiable, regex-friendly pattern. Long before a man named Larry Wall decided that he could do awk one-better, awk was solving pragmatic problems more-or-less exactly like this one. Translation of this concept into actual Perl source-code is left as an exercise to the reader, and s/he has about thirty years' worth of source-code to get ideas from.