简体   繁体   中英

SOAP::Data::Builder, remove xsi:nil=“true” when no value provided

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.

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 .

$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.

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM