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

I am having all sorts of troubles with this. I cannot seem to get this to work.

I send data to a website and it responds with something similar to this:

<?xml version = "1.0"?> <response> <custid>101010101</custid> <status>success</status> <responsecode>11</responsecode> <kf></kf> <cn>1111222233334444555</cn> <neta>7.00</neta> <prid>X111111111111111</prid> <ano>22222222</ano> <trxid>33333333</trxid> <description>Transfer Completed</description> </response>


I built a parser that goes through there and strips out this line: <?xml version = "1.0"?> then it gets all the data between the response tags, then I go parse out all the tags and I make a hash with the value being the data between the tags and the field being the name in the first tag, so the result should be something like this:

%_xml_response_data = ( 'custid' => "101010101", 'status' => "success", 'responsecode' => "11", 'kf' => "", 'cn' => "1111222233334444555", 'neta' => "7.00", 'prid' => "X111111111111111", 'ano' => "22222222", 'trxid' => "33333333", 'description' => "Transfer Completed", );

So that way I can use the data like a hash, for instance to see the status:

if($_xml_response_data{status} eq "success") { # True so do whatever... } else { # false so do whatever else... }

It was working, then I don't know something changed, and now even when the result is success, it seems to not recognize it. I figure, why re-invent the wheel, there MUST be something in cpan that works better, but there are sooooo many xml programs, I am completely lost... The more I search the more complex they get.

Does anyone know of a easy to learn simple solution to get this working? It is not a lot of data, just a simple response.

Thanks,
Richard

Replies are listed 'Best First'.
Re: parsing a simple xml response
by BrowserUk (Patriarch) on Jul 07, 2010 at 02:12 UTC

    You want to do something simple with XML. How about XML::Simple? and one line of code:

    #! perl -slw use strict; use Data::Dump qw[ pp ]; use XML::Simple; my $xml = XMLin( do{ local $/; <DATA> } ); pp $xml; __DATA__ <?xml version = "1.0"?> <response> <custid>101010101</custid> <status>success</status> <responsecode>11</responsecode> <kf></kf> <cn>1111222233334444555</cn> <neta>7.00</neta> <prid>X111111111111111</prid> <ano>22222222</ano> <trxid>33333333</trxid> <description>Transfer Completed</description> </response>

    Output:

    c:\test>junk4 { ano => 22222222, cn => "1111222233334444555", custid => 101010101, description => "Transfer Completed", kf => {}, neta => "7.00", prid => "X111111111111111", responsecode => 11, status => "success", trxid => 33333333, }

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: parsing a simple xml response
by toolic (Bishop) on Jul 07, 2010 at 02:12 UTC
    It is a good decision to migrate to a CPAN XML parser. If you are sure the reposonse data is as simple as you have shown, then XML::Simple is appropriate.
    use warnings; use strict; use Data::Dumper; use XML::Simple; my $xmlin = <<XML; <?xml version = "1.0"?> <response> <custid>101010101</custid> <status>success</status> <responsecode>11</responsecode> <kf></kf> <cn>1111222233334444555</cn> <neta>7.00</neta> <prid>X111111111111111</prid> <ano>22222222</ano> <trxid>33333333</trxid> <description>Transfer Completed</description> </response> XML my $xml = XMLin($xmlin); print Dumper($xml); if ($xml->{status} eq 'success') { print 'yes' } else { print 'no' } __END__ $VAR1 = { 'kf' => {}, 'cn' => '1111222233334444555', 'status' => 'success', 'custid' => '101010101', 'neta' => '7.00', 'description' => 'Transfer Completed', 'trxid' => '33333333', 'ano' => '22222222', 'responsecode' => '11', 'prid' => 'X111111111111111' }; yes

    By default, with your data, it returns a reference to a hash.

    If your data is more complex than what you've shown, XML::Twig would be a better choice.

Re: parsing a simple xml response
by ikegami (Patriarch) on Jul 07, 2010 at 02:36 UTC

    Using XML::LibXML (Fast!):

    use strict; use warnings; use XML::LibXML qw( ); my $xml = <<'__EOI__'; <?xml version = "1.0"?> <response> <custid>101010101</custid> <status>success</status> <responsecode>11</responsecode> <kf></kf> <cn>1111222233334444555</cn> <neta>7.00</neta> <prid>X111111111111111</prid> <ano>22222222</ano> <trxid>33333333</trxid> <description>Transfer Completed</description> </response> __EOI__ my $root = XML::LibXML->new->parse_string($xml)->documentElement; my %data = map { $_->nodeName => $_->textContent } $root->findnodes('/*/*');

    Using XML::Simple (a little less code in this situation, but doesn't work if the elements can have attributes):

    use strict; use warnings; use XML::Simple qw( :strict ); my $xml = <<'__EOI__'; <?xml version = "1.0"?> <response> <custid>101010101</custid> <status>success</status> <responsecode>11</responsecode> <kf></kf> <cn>1111222233334444555</cn> <neta>7.00</neta> <prid>X111111111111111</prid> <ano>22222222</ano> <trxid>33333333</trxid> <description>Transfer Completed</description> </response> __EOI__ $XML::Simple::PREFERRED_PARSER = 'XML::Parser'; # Fastest backend my $parser = XML::Simple->new( ForceArray => [], KeyAttr => {} ); my $data = $parser->XMLin($xml);

    Update: Actually, looks like XML::Simple is not shorter. It's just slower and more fragile.

      Actually, looks like XML::Simple is not shorter.

      Of course it is. my $xml = XMLin( ... ); No one but you would bother to wrap it up in all that unnecessary verbiage.

      It's just slower and more fragile.

      I wonder. How much less time than 0.2 seconds (0.4 if we include the time taken to load perl and the libraries) does LibXML take?

      And given this is being read back from a website, will it make a Gnat's cock of difference?

      c:\test>timeit \perl64\bin\perl.exe junk4.pl Took 0.168277 seconds { ano => 22222222, cn => "1111222233334444555", custid => 101010101, description => "Transfer Completed", kf => {}, neta => "7.00", prid => "X111111111111111", responsecode => 11, status => "success", trxid => 33333333, } Took: 0.381164000 seconds

      After XML::Simple, there's only one other XML::* module worth considering. XML::Twig. Because it's the only one that will deal effectively with bigger than memory XML files.

      And before you respond, realise that any sentence that start with "If...", doesn't mean damn thing.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.

        No one but you would bother to wrap it up in all that unnecessary verbiage.

        PREFERRED_PARSER ensures XML::Parser is used. It's *by far* the fastest backend for XML::Simple.

        And given this is being read back from a website, will it make a Gnat's cock of difference?

        Seriously? You're complaining that I gave a faster alternative? Had it come of at the cost of code readability or extra work, that would have been worth pointing out.

        The difference is significant where I use it (and yes, we pull the response from the web).

Re: parsing a simple xml response
by Anonymous Monk on Jul 07, 2010 at 02:07 UTC
    XML::Simple, XML::Simple site:perlmonks.org
    #!/usr/bin/perl -- use strict; use warnings; use XML::Simple; use Data::Dumper; print Dumper( XMLin(<<'__XML__')); <?xml version = "1.0"?> <response> <custid>101010101</custid> <status>success</status> <responsecode>11</responsecode> <kf></kf> <cn>1111222233334444555</cn> <neta>7.00</neta> <prid>X111111111111111</prid> <ano>22222222</ano> <trxid>33333333</trxid> <description>Transfer Completed</description> </response> __XML__ __END__ $VAR1 = { 'kf' => {}, 'cn' => '1111222233334444555', 'status' => 'success', 'custid' => '101010101', 'neta' => '7.00', 'description' => 'Transfer Completed', 'trxid' => '33333333', 'ano' => '22222222', 'responsecode' => '11', 'prid' => 'X111111111111111' };