I am dealing with a XML schema that has several name spaces and the same element name
in each namespace (Yes, yes, I know this is bad practice).

In the XML::SOAP::Server.pm, version 2.38, you have the compileFilter() routine:

sub compileFilter(@)
{   my ($self, %args) = @_;
    my $nodetype;
    if(my $first    = $args{body}{parts}[0])
    {   $nodetype = $first->{element}
#           or panic "cannot handle type parameter in server filter";
            || $args{body}{procedure};  # rpc-literal "type"
    }

    # called with (XML, INFO)
      defined $nodetype
    ? sub { my $f =  $_[1]->{body}[0]; defined $f && $f eq $nodetype }
    : sub { !defined $_[1]->{body}[0] };  # empty body
}

During generation of the Server code, the compileFilter routine is called with
$nodetype = '{http://www.specsol.com/rmisatmsdata}errorReportMsg'

Notice that this has the namespace prefix. It is used to generate a CODE object:

sub { my $f =  $_[1]->{body}[0]; defined $f && $f eq $nodetype }

When you have a SoapAction header, then the code in XML::SOAP::Daemon.pm, the
process() routine ends doing:

    # Try to resolve operation via soapAction
    my $sa = $self->{sa_input_rev};
    if(defined $soapaction)
    {   if(my $name = $sa->{$soapaction})
        {   my $handler = $handlers->{$name};
            local $info->{selected_by} = 'soap-action';
my ($rc, $msg, $xmlout) = $handler->($name, $xmlin, $info, $req); <<<<< XXX
            if($xmlout)
{ trace "data ready for $version $name, via sa '$soapaction'";
                return ($rc, $msg, $xmlout);
            }
        }
    }
The $name value is 'GetFaultRequest', $xmlin is the parsed XML( an XML::LibXML::Element object),
and $info is a hash with:
   'body' => ARRAY(0x82d7d330)
0 'errorReportMsg'<<<<<<< this is the element name - notice no namespace
   'header' => ARRAY(0x82d7d300)
        empty array
   'selected_by' => 'soap-action'
   'soap_version' => 'SOAP11'
   'wsa_action' => undef

The $handler is a CODE object generated by the XML::Compile::SOAP::Server.pm compileHandler() routine.
See about line 49 in XML/Compile/SOAP/Server.pm, where you have:

    sub
    {   my ($name, $xmlin, $info, $session) = @_;
        # info is used to help determine if the xmlin is of the type for
        # this call. $session is passed in by the server and is in turn
        # passed to the handlers
        $selector->($xmlin, $info) or return;
        trace __x"procedure {name} selected", name => $name;


Here we have the $name,$xmlin, $info as before. We call the $selector, which is the code generated by compileFilter, which is what we started this discussion with:

     sub { my $f =  $_[1]->{body}[0]; defined $f && $f eq $nodetype }

$_[0] is the $xmlin value
$_[1] is the $info value
   $_[1]{body}[0] is 'errorReportMsg'
$nodetype is the value passed to compileFilter -
       $nodetype = '{http://www.specsol.com/rmisatmsdata}errorReportMsg'


Now in the routine $f = 'errorReportMsg', $nodetype = '{http://www.specsol.com/rmisatmsdata}errorReportMsg'
Comparison: $f eq $nodetype

The comparison fails, the call to $selector->($xmlin, $info) returns a 'tests False' value, and the code trying to determine that handler moves on to the next method, which is to use the object type to determine a match against the input message element.

It turns out that the same test (sub { my $f = $_[1]->{body}[0]; defined $f && $f eq $nodetype }) and values for the $nodetype and $body are used, and the test fails. You get the Fault message:

<faultstring>SOAP11 body element errorReportMsg (soapAction GetFaultRequest) not recognized, available ports are GenerateUpdateDataRequest GetDataRequest GetFaultRequest GetMetaRequest GetOPLDSRequest GetStatusRequest OPLDSMsg UpdateDataRequest</faultstring>

Solution to the problem  Version 1 (Brutal and Incorrect):
Replace:
sub { my $f =  $_[1]->{body}[0]; defined $f && $f eq $nodetype }
with
sub { my $f =  $_[1]->{body}[0];
my $nons = $nodetype; $nons =~ s/.*\}//; <<< I think there is a utility function to do this
 defined $f && ($f eq $nodetype or $f eq $nons) }

Solution to the problem Version 2 (More correct, but I have no idea how to do this):

The problem seems to be with the $info information. The {body} value does not have a namespace.
Perhaps another hash entry can be added, say
{ns => ['{http://www.specsol.com/rmisatmsdata}errorReportMsg'] }.

This could be done during the xmlin parsing.  Now you can do:

my $f =  $_[1]->{body}[0];
my $ns = $_[1]->{ns}[0];   <<< body element with namespace?
defined $f && ($f eq $nodetype or $ns eq $nodetype)


I have a funny feeling that this may not be the only place where is problem occurs.

_______________________________________________
Xml-compile mailing list
[email protected]
http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/xml-compile

Reply via email to