Loading ...
Sorry, an error occurred while loading the content.

Root element with child data?

Expand Messages
  • bluesterror
    Hi, I am using document-literal messaging in my web service. Quoting from the WS-I basic profile 1.0, a document-literal binding MUST be represented on the
    Message 1 of 3 , Dec 27, 2004
    • 0 Attachment
      Hi,

      I am using document-literal messaging in my web service. Quoting from
      the WS-I basic profile 1.0, "a document-literal binding MUST be
      represented on the wire as a MESSAGE with a soap:Body whose child
      element is an instance of the global element declaration referenced by
      the corresponding wsdl:message part."

      In other words, rather than the name of the service, the toplevel
      element of an XML document is used. In my case, the service takes as
      parameter a string and returns an XML document fragment, so the
      request message ideally would look something like:

      <soap:Body>
      <Query xmlns="http://example.com">FOO</Query>
      </soap:Body>

      However I cannot make SOAP::Lite generate such a fragment. The
      following code:

      my $method = SOAP::Data
      ->name('Query' => 'Foo')
      ->attr({'xmlns' => 'http://example.com'});

      my $som = $soap->call($method);

      sends a request like:

      <soap:Body>
      <Query xmlns="http://example.com" xsi:nil="true" />
      </soap:Body>

      It seems SOAP::Lite disregards the value of the root XML node unless
      it is also a SOAP::Data element. Using $method=>'FOO' as the
      parameter to call() results in FOO being the child of some gensym
      element. What is the proper way to do this?

      Aside: My understanding is that a "wrapped" style includes the
      operation name as well, but I'd rather not resort to that in keeping
      with the BP. The other workaround is to make the document fragment
      have a param child element but that would needlessly complicate my
      server-side implementation.
    • Gavin Alexander
      Hi, From what I can see, its got do with the way that the SOAP::Serializer handles the root element as a method . If you check out the SOAP::Lite source, you
      Message 2 of 3 , Dec 29, 2004
      • 0 Attachment
        Hi,

        From what I can see, its got do with the way that the
        SOAP::Serializer handles the root element as a
        "method".
        If you check out the SOAP::Lite source, you can see
        that the SOAP::Data::set_value method will always
        overide the root elements' values with null data,
        (unless its explicitly supplied in the ->call() method
        as parameters, in which case it generates a new
        symbol, such as 'gensym-xx', etc)

        There are a couple of things you can try.
        Redefine the SOAP::Data::set_value method to look
        something like this.

        sub SOAP::Data::set_value
        {
        $self = UNIVERSAL::isa($_[0] => 'SOAP::Data') ?
        shift->new : SOAP::Data->new;
        $self->{_value} = [@_] if ! @{$self->{_value}} and
        @_;
        $self;
        }

        and use it like this:
        my $request = SOAP::Data
        ->name('Query'=>'Foo')
        ->attr({'xmlns' => 'http://example.com'});
        $soap->call($request);

        Another work-around would be to add your own
        serializer overiding the envelope method. By default
        SOAP::Lite calls envelope with a 'method' type. If
        you change this to 'freeform' the parameters don't get
        treated as a seperate 'method', 'body' elements

        Something like this should work.

        package My::Serializer;

        use strict;
        use base 'SOAP::Serializer';
        use vars qw/@freeforms/;
        BEGIN { @freeforms = qw/Query/; }

        sub envelope
        {
        my $self = shift;
        my $type = shift;
        my $root = shift;
        UNIVERSAL::isa($root => 'SOAP::Data') and grep
        /^$root->name$/, @freeforms ?
        return $self->SUPER::envelope('freeform', $root,
        @_):
        return $self->SUPER::envelope($type, $root, @_);
        }

        1;

        and
        SOAP::Lite->proxy(...)->serializer(My::Serializer->new)
        should work fine.

        I'm not a 100% sure if these will break anything. Can
        someone please verify this?
        Also this might have been fixed in the the latest
        version of S::L, but I haven't checked.

        Can anyone else out there suggest a less intrusive
        way to do this using SOAP::Lite?

        Cheers.

        --gavin

        --- bluesterror <yahoo@...> wrote:

        ---------------------------------

        Hi,

        I am using document-literal messaging in my web
        service. Quoting from
        the WS-I basic profile 1.0, "a document-literal
        binding MUST be
        represented on the wire as a MESSAGE with a soap:Body
        whose child
        element is an instance of the global element
        declaration referenced by
        the corresponding wsdl:message part."

        In other words, rather than the name of the service,
        the toplevel
        element of an XML document is used. In my case, the
        service takes as
        parameter a string and returns an XML document
        fragment, so the
        request message ideally would look something like:

        <soap:Body>
        <Query xmlns="http://example.com">FOO</Query>
        </soap:Body>

        However I cannot make SOAP::Lite generate such a
        fragment. The
        following code:

        my $method = SOAP::Data
        ->name('Query' => 'Foo')
        ->attr({'xmlns' => 'http://example.com'});

        my $som = $soap->call($method);

        sends a request like:

        <soap:Body>
        <Query xmlns="http://example.com" xsi:nil="true" />
        </soap:Body>

        It seems SOAP::Lite disregards the value of the root
        XML node unless
        it is also a SOAP::Data element. Using $method=>'FOO'
        as the
        parameter to call() results in FOO being the child of
        some gensym
        element. What is the proper way to do this?

        Aside: My understanding is that a "wrapped" style
        includes the
        operation name as well, but I'd rather not resort to
        that in keeping
        with the BP. The other workaround is to make the
        document fragment
        have a param child element but that would needlessly
        complicate my
        server-side implementation.





        Yahoo! Groups SponsorADVERTISEMENT


        ---------------------------------
        Yahoo! Groups Links

        To visit your group on the web, go to:
        http://groups.yahoo.com/group/soaplite/

        To unsubscribe from this group, send an email to:
        soaplite-unsubscribe@yahoogroups.com

        Your use of Yahoo! Groups is subject to the Yahoo!
        Terms of Service.


        Find local movie times and trailers on Yahoo! Movies.
        http://au.movies.yahoo.com
      • bluesterror
        Thanks, this bit did the trick! FWIW I am using SOAP::Lite 0.65-beta2.1. -Bob
        Message 3 of 3 , Dec 29, 2004
        • 0 Attachment
          Thanks, this bit did the trick!

          FWIW I am using SOAP::Lite 0.65-beta2.1.

          -Bob

          --- In soaplite@yahoogroups.com, Gavin Alexander <gc_alexander@y...>
          wrote:
          > There are a couple of things you can try.
          > Redefine the SOAP::Data::set_value method to look
          > something like this.
          >
          > sub SOAP::Data::set_value
          > {
          > $self = UNIVERSAL::isa($_[0] => 'SOAP::Data') ?
          > shift->new : SOAP::Data->new;
          > $self->{_value} = [@_] if ! @{$self->{_value}} and
          > @_;
          > $self;
          > }
          >
          > and use it like this:
          > my $request = SOAP::Data
          > ->name('Query'=>'Foo')
          > ->attr({'xmlns' => 'http://example.com'});
          > $soap->call($request);
        Your message has been successfully submitted and would be delivered to recipients shortly.