0

I have an XML response as follows which I receive from a third party application on basis of the request URL I hit from my perl script from which I need to extract and print values using Perl script. How do i achieve this?

Response:

<LineAnalyseCheck>
     <LineInfo>
        <ParameterInfo>
             <Parameter>
                <DownVal>1</DownVal>
                <Name>Volt</Name>
                <Unit>V</Unit>
                <UpVal>29</UpVal>
            </Parameter>
        </ParameterInfo>
        <LineConfigInfo>
            <Type2>non.8b</Type2>
            <LineSync>true</LineSync>
    </LineConfigInfo>
    </LineInfo>
    <LineInfo>
        <ParameterInfo>
            <Parameter>
                <DownVal>2</DownVal>
                <Name>Volt</Name>
                <Unit>V</Unit>
                <UpVal>20</UpVal>
            </Parameter>
        </ParameterInfo>
        <LineConfigInfo>
            <Type2>non.7b</Type2>
            <LineSync>true</LineSync>
    </LineConfigInfo>
    </LineInfo>
</LineAnalyseCheck>

I am taking the above response received in a content array as follows:

 @content_arr = split /\s+</, $resp->content();

Based on this content array i am separating the name value and adding in my template.

sample code:

    $resp = $ua->request(
        GET 'https://URL?xml=' . &GetRequest($input)
);

@content_arr = split /\s+</, $resp->content();

foreach (@content_arr) {

    if (/^Parameter>/) {
            my @tmp = splice(@content_arr,$counter,4);
            &ParamValues(\@tmp);

    } elsif (/^(LineStatusExplanation>)/) {
            my ($param,$val, undef) = &GetParVal($_);
            if ($TEMPLATE{$param} eq "unknown") {
                    $TEMPLATE{$param} =  "$val\n";
            } else {
                    $TEMPLATE{$param} .=  "$val\n";
    }

    } 
    ## Verhoog de loopteller.
    $counter++;
}

&PrintIt($);

######## functions ########
sub GetRequest($) {
//request I hit
}

 sub PrintIt ($) {
    print <<EOF;
Type2                      : $TEMPLATE{Type2}
LineSync                   : $TEMPLATE{LineSync}
Attenuation                 : Down: $TEMPLATE{'Volt'}->{DownVal} $TEMPLATE{'Volt'}->{Unit} / Up: $TEMPLATE{'Volt'}->{UpVal} $TEMPLATE{'Volt'}->{Unit}
EOF
}

   sub GetParVal($) {

    split />|</, shift;
}

I need the output as

#expectedOutput:

Type2                        : non.8b

LineSync                     : true

Attenuation                  : Down: 1 V / Up: 29 V

Type2                        : non.7b

LineSync                     : true

Attenuation                  : Down: 2 V / Up: 20 V

I have created a template in my perl script as

my %TEMPLATE = (

        'Volt'                     => {  DownVal => 'unknown',
                                         UpVal   => 'unknown',
                                         Unit    => ''
                                                        },
        'Type2'                                         => 'unknown',
        'LineSync'                                      => 'unknown',

);

I am printing the output as :

print <<EOF;
Type2                      : $TEMPLATE{Type2}

LineSync                   : $TEMPLATE{LineSync}

Attenuation                 : Down: $TEMPLATE{'Volt'}->{DownVal} $TEMPLATE{'Volt'}->{Unit} / Up: $TEMPLATE{'Volt'}->{UpVal} $TEMPLATE{'Volt'}->{Unit}
EOF

The problem is this is only displaying the second value of the xml response. Not both the values. The output I am getting is only as follows:

#receivedOutput
Type2                        : non.7b

LineSync                     : true

Attenuation                  : Down: 2 V / Up: 20 V

I need output for both 8b and 7b to be displayed as mentioned in expectedOutput above. How do I achieve this?

Adi
  • 11
  • 3
  • 2
    Welcome to Stack Overflow and the Perl tag. Please include the program that you have already written. You are referring to this XML structure, but it's not clear what you are doing with it. Is it the input to your program? Are you reading it using an XML parser? Which one, and how? What are you struggling with? Please [edit] your question and add this information. – simbabque Oct 31 '16 at 11:59
  • I receive the XML response from an application on basis of the request URL I hit from my script to that application. – Adi Oct 31 '16 at 12:12
  • 1
    And then what? How does that relate to your `%TEMPLATE`? How do you output the output? Is that a large `print` statement? Please be _specific_! – simbabque Oct 31 '16 at 12:13
  • The input data you have shown us is not valid XML. There should be a single enclosing element in your XML document. None of Perl's XML-parsing tools will parse this data successfully. – Dave Cross Oct 31 '16 at 12:58
  • I have edited the question. Please let me know if the question is clear now. Also I need a way to display the values for both Type 1 and Type 2 as shown in #expectedOutput. The code i have written only displays for Type 2. Can you please help? – Adi Nov 02 '16 at 10:24
  • Instead of trying to parse XML with a regex, you should use a XML parser library like [XML::Twig](https://metacpan.org/pod/XML::Twig) or [XML::LibXML](https://metacpan.org/pod/XML::LibXML). – nwellnhof Nov 02 '16 at 10:59
  • This is a pretty old code. I need to provide a fix for this issue. Isn't there a way to get the expected output via regex? I also read something about XML::Simple. Is using that recommended? – Adi Nov 02 '16 at 12:30
  • No, [XML::Simple is discouraged](http://stackoverflow.com/questions/33267765/why-is-xmlsimple-discouraged). – Sobrique Nov 02 '16 at 13:51

1 Answers1

1

You have fallen into one of the classic traps of XML. That if you 'hand parse' it, it gets very complicated because you make assumptions that are not valid.

It's actually very easy though, provided you use a parser. So here is an example of how to do that:

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;

my $twig = XML::Twig -> new -> parsefile ( 'your_file.xml' );

foreach my $lineinfo ( $twig -> get_xpath ('//LineInfo') ) {
   my $conf = $lineinfo -> get_xpath ('./LineConfigInfo',0); 
   my $param = $lineinfo -> get_xpath ( './ParameterInfo/Parameter', 0);

   print "Type2: ", $conf -> get_xpath ( './Type2', 0 ) -> text,"\n";
   print "LineSync: ", $conf -> get_xpath ( './LineSync', 0 ) -> text,"\n";

   my $unit = $param -> get_xpath('./Unit',0) ->text;
   print "Attentuation: ", 
         "Down: ", $param -> get_xpath('./DownVal', 0 ) -> text," $unit / ",
         "Up: ", $param -> get_xpath('./UpVal', 0 ) -> text, " $unit\n";
}

You can probably go further still with templating this with xpath if you're so inclined, but hopefully you can see - this is easier than you think?

Sobrique
  • 52,974
  • 7
  • 60
  • 101
  • what if there is no .xml file ?I am hitting a request to some URL which is giving me an XML response. I cannot create a file for storing this XML. Say, i store it in a variable $response. How do i proceed then? – Adi Nov 11 '16 at 10:49
  • `$twig -> parse ( $response -> content );` or similar. – Sobrique Nov 11 '16 at 11:56