问题
If I write this SOAP::Data::Builder code (where $sb
is a SOAP::Data::Builder Object)
$sb->add_elem(
attributes => { run => 'true' },
name => 'ccAuthService',
# value => ' ', # hack to prevent cs side unparseable xml
);
it generates the following
<ccAuthService xsi:nil="true" run="true" />
Which is unacceptable because the xsi:nil causes problems on the the receiving end. However if I uncomment the commented out line, I get
<ccAuthService run="true"> </ccAuthService>
Technically this works, so it's a workaround. But what I'd like to ultimately have is
<ccAuthService run="true" />
Which I know works, I just can't figure out how to have it generated.
回答1:
This is a solution for fixing this issue with SOAP::Lite (which SOAP::Data::Builder uses).
Define the following somewhere in your code:
sub SOAP::Serializer::as_nonil
{
my ($self, $value, $name, $type, $attr) = @_;
delete $attr->{'xsi:nil'};
return [ $name, $attr, $value ];
}
To use this type:
SOAP::Data->new(
type => 'nonil',
name => 'ping',
prefix => '',
uri => 'http://myschema.domain/',
);
Some hints on this are in SOAP::Serializer.
回答2:
$sb is taking your element and feeding it through an xslt processor to generate a SOAP message. Can you interject 'middle-man' logic into this process?
In my case, I used wsdl to generate a .Net 4 C# SoapHttpClientProtocol object which has a virtual method I was able to override called GetWriterForMessage. This method returns an XmlWriter object used to write out the SOAP message (in essence, the xslt processor). I was able to created a custom XmlWriter that ignored the 'write out attributes whose local name was nil' commands.
What's great about THIS solution is it's generic. So, now it's part of my library I can use whenever I want to 'filter' any Xml output. And it only took one custom class.
It looks like your code is c?? Maybe $sb has a pointer you can set to redirect it's 'xml writer' to a custom method.
Hope this helps someone.
回答3:
You could leave XML generation in SOAP as is, parse the code generated with a parser such as XML::Twig
on the sending end, and print it out with the same library, applying the options you need for it to be successfully handled at the receiving end.
回答4:
I too had the same problem, and this is how I got it solved, maybe it may help others too.
The 'xsi:nil= true' is set if the soap data object's value is undef, set it to arrayref to solve the problem.
Please see below code for reference:
Soap format:
< m:clHotelIdInfo>< m:HotelIdInfo xsi:nil=true id="1219615" />< /m:clHotelIdInfo>
Soap Object structure
*bless( {
'_name' => 'clHotelIdInfo',
'_signature' => [],
'_value' => [
\bless( {
'_signature' => [],
'_value' => [
bless( {
'_name' => 'HotelIdInfo',
'_signature' => [],
**'_value' => [
undef
],**
'_prefix' => 'm',
'_attr' => {
'id' => '1219615'
}
}, 'SOAP::Data' )
],
'_attr' => {}
}, 'SOAP::Data' )
],
'_prefix' => 'm',
'_attr' => {}
}, 'SOAP::Data' )*
Expected Soap format :
< m:clHotelIdInfo>< m:HotelIdInfo id="1219615" /></ m:clHotelIdInfo>
So Soap Object structure must be:
*bless( {
'_name' => 'clHotelIdInfo',
'_signature' => [],
'_value' => [
\bless( {
'_signature' => [],
'_value' => [
bless( {
'_name' => 'HotelIdInfo',
'_signature' => [],
**'_value' => [],**
'_prefix' => 'm',
'_attr' => {
'id' => '1219615'
}
}, 'SOAP::Data' )
],
'_attr' => {}
}, 'SOAP::Data' )
],
'_prefix' => 'm',
'_attr' => {}
}, 'SOAP::Data' )*
If you observe the objects carefully the value of HotelIdInfo was undef earlier, which when changed to arrayref, helped me to get rid of 'xsi:nil = true'.
I didn't have to change any of the existing modules of cpan. Just set the value arrayref instead of undef. This is a solution in perl language.
来源:https://stackoverflow.com/questions/7070553/soapdatabuilder-remove-xsinil-true-when-no-value-provided