File: OutputStream.pm

package info (click to toggle)
libsoap-perl 0.23-1.1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 192 kB
  • ctags: 158
  • sloc: perl: 1,886; makefile: 35
file content (290 lines) | stat: -rw-r--r-- 8,852 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
package SOAP::OutputStream;

use strict;
use vars qw($VERSION);
use SOAP::Defs;

$VERSION = '0.23';

########################################################################
# constructor
########################################################################
sub new {
    my ($class) = @_;
    my $self = {
        tag             => undef,   # the closing tag we write at term
        packager        => undef,   # if we're not a package, this points to an ancestor who is
                                    # and implements the functions for maintaining objrefs
        soap_prefix     => '',      # this allows us to turn on/off namespace support
        envelope        => 0,       # manages ids and namespaces
        depth           => 1,       # use a one-based depth simply for consistency
                                    # with expat on the other side
        print_fcn       => undef,
        seal_package    => undef,   # do we need to seal our package on term or not?
    };
    bless $self, $class;
}

########################################################################
# interface ISoapStream
########################################################################
sub simple_accessor {
#   my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $content) = @_;
    &_simple_accessor;
}

sub compound_accessor {
#    my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $is_package) = @_;
    &_compound_accessor;
}

sub reference_accessor {
#    my ($self, $accessor_uri, $accessor_name, $object) = @_;
    &_reference_accessor;
}

sub term {
#   my ($self) = @_;
    &_term;
}

########################################################################
# implementation
########################################################################
sub _simple_accessor {
    my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $content) = @_;

    my $attrs = '';

    my $nsprefix = '';
    if (defined $accessor_uri) {
        (my $nsdecl, $nsprefix) = $self->{envelope}->_get_ns_decl_and_prefix($accessor_uri);
        $attrs .= $nsdecl if $nsdecl;
    }
    my $tag = $nsprefix . $accessor_name;

    if (defined $typename) {
        my $nsprefix = '';
        if (defined $typeuri) {
            (my $nsdecl, $nsprefix) = $self->{envelope}->_get_ns_decl_and_prefix($typeuri);
        
            $attrs .= $nsdecl if $nsdecl;
        }
        $attrs .= qq[ xsi:type="$nsprefix$typename"];
    }

    $self->_print(qq[<$tag$attrs>$content</$tag>]);
}

sub _compound_accessor {
    my ($self, $accessor_uri, $accessor_name, $typeuri, $typename, $is_package) = @_;

    my $sp = $self->{soap_prefix};

    my $attrs = '';

    my $packager = $is_package ? $self->_create_new_package() : $self->{packager};
    my $envelope = $self->{envelope};

    my $new_depth = $self->{depth} + 1;

    my $stream = SOAP::OutputStream->new();
    $stream->{packager}       = $packager;
    $stream->{envelope}       = $self->{envelope};
    $stream->{depth}          = $new_depth;
    $stream->{print_fcn}      = $self->{print_fcn};
    $stream->{soap_prefix}    = $self->{soap_prefix};
    $stream->{seal_package}   = $is_package;

    my $nsprefix = '';
    if (defined $accessor_uri) {
        (my $nsdecl, $nsprefix) = $self->{envelope}->_push_ns_decl_and_prefix($accessor_uri, $new_depth);
        $attrs .= $nsdecl if $nsdecl;
    }
    my $tag = $nsprefix . $accessor_name;

    $stream->{tag} = $tag;

    if (defined $typename) {
        my $nsprefix = '';
        if (defined $typeuri) {
            (my $nsdecl, $nsprefix) = $self->{envelope}->_push_ns_decl_and_prefix($typeuri, $new_depth);
        
            $attrs .= $nsdecl if $nsdecl;
        }
        $attrs .= qq[ xsi:type="$nsprefix$typename"];
    }

    $self->_print(qq[<$tag$attrs>]);

    $stream;
}

sub _reference_accessor {
    my ($self, $accessor_uri, $accessor_name, $object) = @_;

    my $sp = $self->{soap_prefix};

    my $attrs = '';
    if (defined $object) {
        my $id = $self->{packager}->register($self->{envelope}, $object);

        $attrs = qq[ ${sp}$soap_href="#$id"];
    }
    else {
        $attrs .= ' xsi:null="1"';
    }

    my $nsprefix = '';
    if (defined $accessor_uri) {
        (my $nsdecl, $nsprefix) = $self->{envelope}->_get_ns_decl_and_prefix($accessor_uri);
        $attrs .= $nsdecl if $nsdecl;
    }
    my $tag = $nsprefix . $accessor_name;

    if ($accessor_uri) {
        $self->_clean_up_namespace_dictionary($self->{depth} + 1);
    }

    $self->_print(qq[<$tag$attrs />]);
}

sub _term {
    my ($self) = @_;

    if ($self->{seal_package}) {
        $self->{packager}->seal($self->{envelope});
    }

    my $tag = $self->{tag};
    $self->_print(qq[</$tag>]);

    $self->_clean_up_namespace_dictionary($self->{depth});
}

########################################################################
# misc
########################################################################
sub _create_new_package {
    my ($self) = @_;
    SOAP::Packager->new($self->{soap_prefix},
                        $self->{depth},
                        $self->{print_fcn});
}

sub _clean_up_namespace_dictionary {
    my ($self, $depth) = @_;
    $self->{envelope}->_clean_up_namespace_dictionary($depth);
}

sub _print {
    my ($self, $s) = @_;
    
    $self->{print_fcn}->($s);
}

1;
__END__


=head1 NAME

SOAP::OutputStream - Writes SOAP fragments

=head1 SYNOPSIS

    # note that we need SOAP::Envelope to bootstrap
    use SOAP::Envelope;

    sub output_fcn {
        my $string = shift;
        print $string;
    }

    my $namespaces_to_preload = ["urn:foo", "urn:bar"];
    my $env = SOAP::Envelope->new(\&output_fcn,
                                  $namespaces_to_preload);
    my $body = $env->body();
    
    # here is where we actually use SOAP::OutputStream
    my $child = $body->compound_accessor("urn:quux", "reverse_string", undef, undef, 0);

    $child->simple_accessor(undef, "s", undef, undef, "dlrow olleH");

    $child->term();
    $body->term();
    $env->term();

This creates the following XML:

<s:Envelope xmlns:s="urn:schemas-xmlsoap-org:soap.v1" 
            xmlns:xsi="http://www.w3.org/1999/XMLSchema" 
            xmlns:n1="urn:foo" 
            xmlns:n2="urn:bar">
  <s:Body>
    <n3:reverse_string xmlns:n3="urn:quux">
      <s>dlrow olleH</s>
    </n3:reverse_string>
  </s:Body>
</s:Envelope>


=head1 DESCRIPTION

SOAP::OutputStream encapsulates the details of writing SOAP packets into a few easy
to use functions. In order to bootstrap a SOAP stream (and get your first
SOAP::OutputStream reference), you'll need to use SOAP::Envelope, as shown in
the example above.

=head2 The simple_accessor function

This function writes a simple accessor (e.g., a string or number, as opposed
to a compound type). It takes two sets of URI/typenames, one for the accessor
and one for the optional xsd:type attribute. At a minimum, you must specify the
accessor_name and content.

=head2 The compound_accessor function

This function opens a new compound accessor (by writing an open XML tag), and
returns a new SOAP::OutputStream that you should use to write the contents of that
accessor. This function always creates nested elements. If you want to create
an independent element, call reference_accessor instead. The is_package parameter
allows you to open a new package at this node; the OutputStream will write all
further independent elements at this level in the XML document, creating a
standalone XML fragment within the SOAP envelope. The OutputStream will complain
if all references within the package cannot be resolved when this node is closed.
See the SOAP spec for details on packages.

=head2 The reference_accessor function

This function creates a reference (SOAP:href) node, and stores the specified
object until the current package is closed, at which time a serializer is obtained
for the object (based on its type) and is asked to serialize itself to
a new stream at the level of the package. Note that if you're not using
packages explicitly, then the system will perform this resolution and
serialization when you switch from creating Headers to creating the Body,
and once again when the Body is terminated. The object referenced is guaranteed
to only be serialized once (assuming you've obeyed the SOAP rules for packages
and Header/Body object reference sharing).

=head2 The term function

Call this function when you want to close the node you're working with.
This does several things - it seals the package if the node you're using
was created as a package, and it writes an end tag (along with doing some
other internal bookeeping that's pretty important). Don't forget to call
this function before opening a new sibling node.

=head1 DEPENDENCIES

SOAP::Defs

=head1 AUTHOR

Keith Brown

=head1 SEE ALSO

SOAP::Envelope

=cut