http://qs321.pair.com?node_id=701466

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

New Monk seeking wisdom about parsing a soap response. I have a soap response from a VB Script that saves as XML. I would like to grab this file with PERL, parse it and store it in a database, either in full XML string or parsed by element. My problem is that the output I'm getting from XML::Parse is not very friendly. I think its an encoding issue but I'm not sure how to get around it.
<?xml version='1.0' encoding='UTF-8'?> <SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <SOAP-ENV:Body> <ns1:VHIResponse xmlns:ns1="http://tempuri.org/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" +> <return xsi:type="xsd:string"> &lt;Vehicles&gt; &lt;Vehicle vin=&quot;1FMFU17L94LB04622&quot;&gt; &lt;Status desc=&quot;Vehicle status OK&quot; id=&quot;VI1000&quot;/&g +t; &lt;VehicleAttributes&gt; &lt;VehicleAttribute type=&quot;Year&quot; typeid=&quot;14&quot; value +=&quot;2004&quot; valueid=&quot;3043&quot;/&gt; &lt;VehicleAttribute type=&quot;Make&quot; typeid=&quot;1&quot; value= +&quot;Ford&quot; valueid=&quot;184&quot;/&gt; &lt;VehicleAttribute type=&quot;Model&quot; typeid=&quot;2&quot; value +=&quot;Expedition&quot; valueid=&quot;30&quot;/&gt; &lt;VehicleAttribute type=&quot;Series&quot; typeid=&quot;3&quot; valu +e=&quot;Eddie Bauer&quot; valueid=&quot;117&quot;/&gt; &lt;/VehicleAttributes&gt; &lt;/Vehicle&gt; &lt;/Vehicles&gt; </return> </ns1:VHIResponse> </SOAP-ENV:Body> </SOAP-ENV:Envelope>
Thanks for the responses, I spaced out on posting the PERL code. Ultimately I would like to see something like:
<FCSDServicesResponse country="USA" language="ENG" marketid="1"> <Status desc="Web service status OK" id="VI2000"/> <Vehicles> <Vehicle vin="1FMFU17L94LB04622"> <Status desc="Vehicle status OK" id="VI1000"/> <VehicleAttributes> <VehicleAttribute type="Year" typeid="14" value="2004" valueid="3043"/ +> <VehicleAttribute type="Make" typeid="1" value="Ford" valueid="184"/> <VehicleAttribute type="Model" typeid="2" value="Expedition" valueid=" +30"/> <VehicleAttribute type="Series" typeid="3" value="Eddie Bauer" valueid +="117"/> </VehicleAttributes> </Vehicle> </Vehicles> </FCSDServicesResponse>
All I really need extracted is the VIN/Make/Model/Year and Series from the resulting response. I am relatively new to this so I'm starting out slow with the basics:
# use module use XML::Simple; use Data::Dumper; # create object $xml = new XML::Simple; # read XML file $data = $xml->XMLin("Elvis1.xml"); # print output print Dumper($data);
What I get from this is:
$VAR1 = { 'country' => 'USA', 'language' => 'ENG', 'Status' => { 'desc' => 'Web service status OK', 'id' => 'VI2000' }, 'Vehicles' => { 'Vehicle' => { 'VehicleAttributes' => { 'VehicleAt +tribute' => [ + { + 'typeid' => '14', + 'value' => '2004', + 'valueid' => '3043', + 'type' => 'Year' + }, + { + 'typeid' => '1', + 'value' => 'Ford', + 'valueid' => '184', + 'type' => 'Make' + }, + { + 'typeid' => '2', + 'value' => 'Expedition', + 'valueid' => '30', + 'type' => 'Model' + }, + { + 'typeid' => '3', + 'value' => 'Eddie Bauer', + 'valueid' => '117', + 'type' => 'Series' + } + ] }, 'Status' => { 'desc' => 'Vehicle st +atus OK', 'id' => 'VI1000' }, 'vin' => '1FMFU17L94LB04622' } }, 'marketid' => '1' };
Many Thanks in advance. Darren

Replies are listed 'Best First'.
Re: XML SOAP Response
by ambrus (Abbot) on Jul 31, 2008 at 16:56 UTC
Re: XML SOAP Response
by psini (Deacon) on Jul 31, 2008 at 16:59 UTC

    I don't see encoding problem in the response, the strange thing is that your SOAP response contains only one <return> tag which, in turn contains an XML stream.

    If you want to use the contents of the "inner" XML, you should parse it twice: parse the SOAP response and get the contents of the <return> tag in a var, then parse the var to get the values.

    Update: perhaps your problem is elsewhere. The format of your SOAP packet is really unusual, for there's no need to encapsulate an XML stream into a SOAP packet (which is XML itself). So maybe is the script generating the response to blame: it should not embed the response into the <return> tag as a string but as pure XML.

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

      Thank you, I'm looking into the script that generates the response to see if it can be changed. The owner of the web service said the following as I was building the call to the web service.
      There is a single element in the request which accepts a string, but the string is XML, and as such needs to be encoded
      I think that is why its embedded within on <return> element. Unfortunately that is not something I can avoid, if that is indeed the case. Here is the soap envelope that makes the call:
      requestbody = requestbody & "<SOAP-ENV:Body><ns1:VehicleInfo >" requestbody = requestbody & "<xmlRequest xmlns:xsi=""http://www.w3.org +/2001/XMLSchema-instance"" xsi:type=""xsd:string"">" requestbody = requestbody & "<FCSDServicesRequest marketid=""1"" langu +age=""ENG"" country=""USA"" xmlns:xsi=""http://www.w3.org/2001/XMLSch +ema-instance"" xsi:noNamespaceSchemaLocation=""FCSDServices.xsd"">" requestbody = requestbody & "<Vehicles>" requestbody = requestbody & "<Vehicle vin=""1FMFU17L94LB04622""/>" requestbody = requestbody & "<Vehicle vin=""1FTRX12W88KD10648""/>" requestbody = requestbody & "<Vehicle vin=""2MEHM75W26X618474""/>" requestbody = requestbody & "</Vehicles>" requestbody = requestbody & "<ServiceRequests>" requestbody = requestbody & "<VINDecodeService>" requestbody = requestbody & "<Attribute typeid=""14"" type=""Year""/>" requestbody = requestbody & "<Attribute typeid=""1"" type=""Make""/>" requestbody = requestbody & "<Attribute typeid=""2"" type=""Model""/>" requestbody = requestbody & "<Attribute typeid=""3"" type=""Series""/> +" requestbody = requestbody & "</VINDecodeService>" requestbody = requestbody & "</ServiceRequests>" requestbody = requestbody & "</FCSDServicesRequest>" requestbody = requestbody & "</xmlRequest>" requestbody = requestbody & "</ns1:VehicleInfo>" requestbody = requestbody & "</SOAP-ENV:Body>" requestbody = requestbody & "</SOAP-ENV:Envelope>"
Re: XML SOAP Response
by moritz (Cardinal) on Jul 31, 2008 at 16:54 UTC
    Show us some code that exhibits the problems.

    Update: Ok, not a character encoding problem at all, please ignore the rest.

    I'd expect XML::Parser to return decoded text strings, so you'd have to encode them in the character encoding you want before printing. This might be as simple as adding

    binmode STDOUT, ':encoding(UTF-8)';

    at the start of your program.

    See also: character encodings and perl, Encode, perluniintro, perlunicode.

Re: XML SOAP Response
by olus (Curate) on Jul 31, 2008 at 16:54 UTC

    Welcome to the Monastery mitchismoney

    In order for you to get the most relevant replies to your questions you should also show the code you've written so far and examples of the unfriendly outputs you're getting. Also, the output you would like to see.

    Please read How (Not) To Ask A Question

Re: XML SOAP Response
by psini (Deacon) on Jul 31, 2008 at 17:30 UTC

    Try adding this at the end of your program.

    my @vehicles; foreach (@{$data->{Vehicles}->{Vehicle}}) { my %vehicle; $vehicle{vin}=$_->{vin}; foreach(@{$_->{VehicleAttributes}->{VehicleAttribute}}) { $vehicle{$_->{type}}=$_->{value}; } push(@vehicles,\%vehicle); } print Dumper(\@vehicles);

    Updated: corrected several errors, now it works. You have to replace the initialization of $xml with

    my $xml = new XML::Simple( ForceArray => ["Vehicle"]);

    to force the "Vehicle" tag in your XML to became an array in the generated tree.

    Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

      Adding the code changed the output to:
      $VAR1 = [];
      Is it a matter of double parsing the file? Or is this were XML::Twig comes in? I've only written some pretty basic Perl so bare with me as I try to learn/understand. I greatly appreciate it!

        Probably just a couple of typos:

        (1) print Dumper(\@vehicles); # plural (2) push(@vehicles,\%vehicle); # hashref (3) $vehicle{$_->{type}}=$_->{value}; # not veihcle

      No, it's a matter of untested code too complex to work at first go. Give me five minutes and I'll try to debug it

      Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."