I'm trying to write a simple SOAP client using SOAP::Lite. After making a request, the response only seems to be parsed into perl data structure a couple levels down. After that it's just a string of the remaining XML. I feel like it would be really kludgy to take that string and parse it manually with another XML parser.
my $response = $soap->getVersionInfo;
my $data = $response->dataof('//getVersionInfoResponse');
The SOAP response looks like this in the SOAP::Lite trace:
<?xml version='1.0' encoding='utf-8'?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<ns:getVersionInfoResponse xmlns:ns="http://webservice.jchem.chemaxon">
<ns:return>
<Info>
<JChem>
<Version>5.2.6</Version>
</JChem>
<Java>
<Vendor>Sun Microsystems Inc.</Vendor>
<VmName>Java HotSpot(TM) Client VM</VmName>
<Version>1.6.0_05</Version>
</Java>
<Os>
<Arch>x86</Arch>
<Name>Windows XP</Name>
<Version>5.1</Version>
</Os>
</Info>
</ns:return>
</ns:getVersionInfoResponse>
</soapenv:Body>
</soapenv:Envelope>
But what gets parsed into $data
looks like this (from Data::Dumper::Concise):
\bless( {
_attr => {},
_name => "getVersionInfoResponse",
_prefix => "ns",
_signature => [],
_uri => "http://webservice.jchem.chemaxon",
_value => [
{
return => "<Info>\n<JChem>\n<Version>5.2.6</Version>\n</JChem>\n<Java>\n<Vendor>Sun Microsystems Inc.</Vendor>\n<VmName>Java HotSpot(TM) Client VM</VmName>\n<Version>1.6.0_05</Version>\n</Java>\n<Os>\n<Arch>x86</Arch>\n<Name>Windows XP</Name>\n<Version>5.1</Version>\n</Os>\n</Inf开发者_开发技巧o>\n"
}
]
}, 'SOAP::Data' )
This is a simple example, but for more complex responses, it could become a huge hassle to have to parse out that XML.
I found this post on the SOAP::Lite mailing list (from 2003!) that had a worrisome quote on it:
Keep in mind the requirement that any attributes not natively known to SOAP must be namespace-qualified.
And I noticed that everything that wasn't getting parsed was not namespaced. Is there a way to force SOAP::Lite to parse that non-namespaced xml? Is that even the problem?
UPDATE:
It turns out SOAP::Lite was Doing The Right Thing. I'd overlooked a note in the service docs that that saidNote: The special characters inside
<ns:return>
tag are encoded to entities. (e.g. an xml return value will contain < characters, which will be encoded to<
entities) Therefore entity decoding is needed on the client side.
What I thought was just a trace output inconsistency was actually the problem. SOAP::Lite being nice and unescaping the entities before they ended up in the Dumper confused me as well. I originally included the documentation's example because it was already formatted nicely. Now the actual output is shown. Plus, everyone knows <
is the same as <, right? Right? ;_;
As of now I'm parsing the string with XML::LibXML, so the question still stands. Can I force SOAP::Lite to parse that interior XML string, even though it's been escaped?
Works fine for me; $response->result
gives the Info element with all children:
{
Info => {
JChem => {
Version => "5.2.1"
},
Java => {
Vendor => "Sun Microsystems Inc.",
Version => "1.6.0_06",
VmName => "Java HotSpot(TM) Server VM"
},
Os => {
Arch => "x86",
Name => "Windows XP",
Version => "5.1"
}
}
}
And $response->dataof('//getVersionInfoResponse')
returns a full-depth tree.
What version of Soap::Lite are you running? I'm using 0.710.10:
$sudo perl -MCPAN -e shell
cpan[6]> i SOAP:Lite
...
INST_VERSION 0.710.10
From what I learned on the SOAP::Lite mailing list (post), SOAP::Lite's intention is to only handle the protocol and envelope, not the interior of the message. I ended up using XML::Simple to parse the content of the response.
精彩评论