79 const XET_ALL =
"ALL";
80 const XET_CHOICE =
"CHOICE";
81 const XET_SEQUENCE =
"SEQUENCE";
84 const SOAP_11_ENV =
"http://schemas.xmlsoap.org/soap/envelope/";
86 const SOAP_12_ENV =
"http://www.w3.org/2003/05/soap-envelope";
89 const SOAP_12_NS =
"http://schemas.xmlsoap.org/wsdl/soap12/";
92 const XSD_NS =
"http://www.w3.org/2001/XMLSchema";
94 const XSI_NS =
"http://www.w3.org/2001/XMLSchema-instance";
97 const HTTP_NS =
"http://schemas.xmlsoap.org/wsdl/http/";
99 const MIME_NS =
"http://schemas.xmlsoap.org/wsdl/mime/";
103 (
"soapenv:Envelope" :
107 "xmlns:xsi" :
XSI_NS ) ) );
111 (
"soapenv:Envelope" :
115 "xmlns:xsi" :
XSI_NS ) ) );
122 ( Type::String :
"string",
124 Type::Boolean :
"boolean",
125 Type::Date :
"dateTime",
126 Type::Float :
"decimal",
127 Type::NothingType :
"string",
128 Type::NullType :
"string",
129 Type::Binary :
"base64Binary" );
132 const SOAP_SERIALIZATION_ERROR =
"SOAP-SERIALIZATION-ERROR";
133 const SOAP_DESERIALIZATION_ERROR =
"SOAP-DESERIALIZATION-ERROR";
134 const WSDL_ERROR =
"WSDL-ERROR";
161 #! retrieves a file from a URL with HTTP and returns the file's contents as a string
163 static string getHTTP(
string url, any path, any hc, any headers);
167 static binary
getFTP(
string $url,
string $path) {
168 my
string $file = basename($path);
170 throw "WSDL-LIB-ERROR", sprintf(
"missing file name in URL %n", $url);
172 my FtpClient $f($url);
175 my
string $dir = dirname($path);
179 return $f.getAsBinary($file);
182 #! retrieves a file from a URL
183 static any getFileFromURL(
string $url,
string $def_protocol, any $http_client, any $http_headers) {
184 my hash $u = parse_url($url);
186 if (!exists $u.protocol)
187 $u.protocol = exists $def_protocol ? $def_protocol :
"file";
189 switch ($u.protocol) {
200 throw "WSDL-LIB-ERROR", sprintf(
"do not know how to retrieve data with protocol %n given in URL %n", $u.protocol, $url);
204 #! returns the argument
205 static WebService getWSDL(WebService $wsdl) {
209 #! returns a WSDL string form a file name, optional HTTPClient object and optional header hash
210 static string getWSDL(
string $wsdl, *HTTPClient $http_client, *hash $http_headers) {
211 if (strlen($wsdl) > 256 && $wsdl !~ /^\w+:\/\/.*$/)
213 return WSDLLib::getFileFromURL($wsdl,
"file", $http_client, $http_headers);
216 #! takes a hash representation of a SOAP message and parses it to a Qore data structure; handles multipart messages, checks the content-type, and handles hrefs in the message
217 static hash parseSOAPMessage(hash $msg) {
218 if (exists $msg.
"_qore_multipart") {
219 if ($msg.
"_qore_multipart" !=
"related")
220 throw "SOAP-MESSAGE-ERROR", sprintf(
"don't understand multipart/%s messages, expected multipart/related", $msg.
"_qore_multipart");
222 my any $bdry = $msg.
"_qore_multipart_boundary";
224 throw "SOAP-MESSAGE-ERROR", sprintf(
"multipart message received without multipart boundary; headers=%n", $msg -
"body");
227 my list $l = split(
"\r\n--" + $bdry, $msg.body);
229 #printf("l=%N\n", $l);
230 #my File $f(); $f.open2("t.bin", O_CREAT|O_WRONLY|O_TRUNC); $f.write(binary($l[3])); exit();
231 #my File $f(); $f.open2("t.bin", O_CREAT|O_WRONLY|O_TRUNC); $f.write(binary($msg.body)); exit();
233 for (my
int $i = 1; $i < (elements $l - 1); ++$i) {
234 my
string $m = $l[$i];
236 my
int $ie = index($m,
"\r\n\r\n");
238 throw "SOAP-MESSAGE-ERROR", sprintf(
"part %d has no headers: %n", $i, $m);
241 foreach my
string $hl in (split(
"\r\n", substr($m, 2, $ie))) {
243 my (
string $hi, any $ignore,
string $ha) = $hl =~ x/^(.*):([ \t])*(.*)$/;
245 #printf("hl=%n hi=%n ha=%n\n", $hl, $hi, $ha);exit();
248 if (!exists $hh.
"content-id")
249 throw "SOAP-MESSAGE-ERROR", sprintf(
"expecting part header Content-ID in part %d; headers: %n", $i, $hh);
252 if ($hh.
"content-transfer-encoding" ==
"binary") {
253 # unfortunately we have to do some tricks to get the binary data out here
254 # FIXME: tricks probably not necessary with qore 0.8.1+
255 $m = force_encoding($m,
"ascii");
256 # recalculate byte offset
257 $ie = index($m,
"\r\n\r\n");
258 #printf("ie=%d m=%d\n", $ie, strlen($m));exit();
259 $b = binary(substr($m, $ie + 4));
261 #my File $f(); $f.open2("t.bin", O_CREAT|O_WRONLY|O_TRUNC); $f.write($b); exit();
264 $b = substr($m, $ie + 4);
266 if ($hh.
"content-type" =~ /charset=/) {
267 my
string $c = ($hh.
"content-type" =~ x/charset=([^;]+)/)[0];
268 $b = force_encoding($b, $c);
272 if ($hh.
"content-id" !~ /^\<.*\>$/)
273 throw "SOAP-MESSAGE-ERROR", sprintf(
"expected part ID to have the following format: <id>, instead got %s", $hh.
"content-id");
275 my hash $p = (
"hdr" : $hh,
278 if ((!exists $msg.
"_qore_multipart_start" && $i == 1)
279 @htmlonly <style><!-- td.qore { background-color: #5b9409; color: white; } --></style>
@endhtmlonly
283 <td>(exists $msg.
"_qore_multipart_start" && $msg.
"_qore_multipart_start" == $hh.
"content-id")) {</td>
289 my
string $id = substr($hh.
"content-id", 1, -1);
290 $mpmsg.part.$id = $p;
294 WSDLLib::checkSOAPContentType($mpmsg.body.hdr.
"content-type");
296 #printf("part %d hh=%N\nbody=%s (%d)\n", $i, $hh, type($b), elements($b)); #exit();
297 my hash $xmldata = parseXMLAsData($mpmsg.body.body);
299 # parse entire data structure to find "href"s or href attributes
300 WSDLLib::substHref(\$xmldata, $mpmsg.part);
304 WSDLLib::checkSOAPContentType($msg.
"content-type");
306 return parseXMLAsData($msg.body);
309 private static checkSOAPContentType(
string $ct) {
311 if (bindex($ct, $sct) != -1)
315 throw "SOAP-MESSAGE-ERROR", sprintf(
"don't know how to handle content-type %n (expecting one of: %y)", $ct,
SoapMimeTypes);
318 private static processHref(reference $xmldata,
string $hr, hash $parts) {
320 throw "SOAP-MESSAGE-ERROR", sprintf(
"messages references non-local part %n; cannot handle non-local parts", $hr);
321 $hr = substr($hr, 4);
322 if (!exists $parts.$hr)
323 throw "SOAP-MESSAGE-ERROR", sprintf(
"message references non-existent part %n", $hr);
324 $xmldata = $parts.$hr.body;
327 private static substHref(reference $xmldata, hash $parts) {
328 foreach my
string $k in (keys $xmldata) {
329 if (exists $xmldata.$k.
"^attributes^".href)
330 WSDLLib::processHref(\$xmldata.$k, $xmldata.$k.
"^attributes^".href, $parts);
331 else if (exists $xmldata.$k.href)
332 WSDLLib::processHref(\$xmldata.$k, $xmldata.$k.href, $parts);
333 else if ($xmldata.$k.typeCode() == NT_LIST) {
334 foreach my any $e in (\$xmldata.$k)
335 WSDLLib::substHref(\$e, $parts);
337 else if ($xmldata.$k.typeCode() == NT_HASH)
338 WSDLLib::substHref(\$xmldata.$k, $parts);
343 # abstract class providing helper methods to subclasses
344 public class WSDL::XSDBase {
345 static private hash doType(
string $t) {
346 #printf("DEBUG: XSDBase::doType(%n, %n)\n", $t, $nsinfo);
347 my (*
string $ns, *
string $type) = $t =~ x/(\w+):(\w+)/;
348 return !exists $type ? (
"val": $t) : (
"ns": $ns,
"val": $type);
351 static private any doType(
string $t, hash $nsinfo) {
352 #printf("DEBUG: XSDBase::doType(%n, %n)\n", $t, $nsinfo);
353 my (*
string $ns, *
string $type) = $t =~ x/(\w+):(\w+)/;
355 return (
"val" : $t );
357 # if this is in the XML Schema namespace, then it's a base type
358 if ($nsinfo.xml_schema.$ns)
359 return new XSDBaseType($type);
365 static removeNS(reference $h) {
366 foreach my
string $k in (keys $h) {
367 my (*
string $ns, *
string $name) = $k =~ x/(\w+):(\w+)/;
369 if ($h.$k.typeCode() == NT_HASH)
377 static removeNS2(reference $h) {
378 foreach my
string $k in (keys $h) {
379 my (*
string $ns, *
string $name) = $k =~ x/(\w+):(\w+)/;
381 if ($h.$k.typeCode() == NT_HASH)
390 # abstract type common to all XSD classes
391 public class WSDL::XSDData inherits XSDBase {
392 any getValue(any $mrh, any $val) {
393 if (exists $val.
"^attributes^".href) {
394 my
string $href = substr($val.
"^attributes^".href, 1);
396 if (!exists $mrh.$href)
397 throw "INVALID-REFERENCE", sprintf(
"multiRef id=%n does not exist", $href);
405 # abstract type common to all XSD classes with a "name" attribute
406 public class WSDL::XSDNamedData inherits XSDData {
411 constructor(reference $e) {
412 WSDL::XSDBase::removeNS(\$e);
414 $.name = $e.
"^attributes^".name;
418 return exists $.name ? $.name :
"<unnamed type>";
426 # class for XSD base types
427 public class WSDL::XSDBaseType inherits XSDData {
432 constructor(
string $t) {
434 $.nstype =
"xsd:" + $t;
437 any serialize(any $val, *softbool $omit_type, *softbool $omit_ns) {
438 my (any $type,
string $nstype);
439 # set type according to Qore type if xsd type is anyType
440 if ($.type ==
"anyType") {
441 # we have to specify the type in this case
444 $nstype =
"xsd:" + $type;
446 throw SOAP_SERIALIZATION_ERROR, sprintf(
"cannot serialize xsd type anyType from Qore type %n", type($val));
455 my
int $v = int($val);
456 if (($v & 0xff) != $v)
457 throw SOAP_SERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $v, $type);
462 my
int $v = int($val);
464 throw SOAP_SERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $v, $type);
469 my
int $v = int($val);
471 throw SOAP_SERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $v, $type);
475 case "unsignedByte": {
476 my
int $v = int($val);
477 if (($v & 0xff) != $v)
478 throw SOAP_SERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $v, $type);
480 throw SOAP_SERIALIZATION_ERROR, sprintf(
"type %n does not accept negative values (value supplied: %d)", $type, $v);
484 case "unsignedShort": {
485 my
int $v = int($val);
487 throw SOAP_SERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $v, $type);
491 case "unsignedInt": {
492 my
int $v = int($val);
494 throw SOAP_SERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $v, $type);
498 case "unsignedLong": {
499 my
int $v = int($val);
501 throw SOAP_SERIALIZATION_ERROR, sprintf(
"type %n does not accept negative values (value supplied: %d)", $type, $v);
505 case "positiveInteger":
507 throw SOAP_SERIALIZATION_ERROR, sprintf(
"type %n only accepts positive values (value supplied: %d)", $type, $val);
511 $val = format_date(
"YYYY-MM-DD", date($val));
515 $val = format_date(
"YYYY-MM-DDTHH:mm:SS", date($val));
519 $val = $val ?
"true" :
"false";
523 $val = format_date(
"hh:mm:ss.ms", date($val));
527 $val = makeBase64String($val);
531 $val = makeHexString($val);
535 #printf("DEBUG: FORCE: type=%n, nstype=%n, val=%n\n", $type, $.nstype, $val);
536 if ($omit_type ==
"ns")
537 return (
"^attributes^" : (
"xmlns:xsi" :
XSI_NS,
"xsi:type" : $nstype ),
"^value^" : $val );
538 return $omit_type ? $val : (
"^attributes^" : (
"xsi:type" : $nstype ),
"^value^" : $val );
541 any deserialize(any $types, any $mrh, any $val) {
543 if ($val.typeCode() == NT_HASH) {
544 $type = $val.
"^attributes^".
"xsi:type";
545 my
string $t = ($type =~ x/\w+:(\w+)/)[0];
549 if ($.type !=
"anyType" && $type != $.type)
550 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"expecting base type %n, got %n", $.type, $val.
"^attributes^".
"xsi:type");
551 if (exists $val.
"^value^")
552 $val = $val.
"^value^";
560 # note that we do not convert xsd:integer to a qore integer to avoid losing precision
566 if (($val & 0xff) != $val)
567 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $val, $.type);
573 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $val, $.type);
579 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $val, $.type);
587 if (($val & 0xff) != $val)
588 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $val, $.type);
590 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"type %n does not accept negative values (value supplied: %d)", $.type, $val);
593 case "unsignedShort":
595 if (($val & 0xffff) != $val)
596 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $val, $.type);
598 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"type %n does not accept negative values (value supplied: %d)", $.type, $val);
603 if (($val & 0xffffffff) != $val)
604 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"value %d is out of range for type %n", $val, $.type);
606 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"type %n does not accept negative values (value supplied: %d)", $.type, $val);
611 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"type %n does not accept negative values (value supplied: %d)", $.type, $val);
614 case "positiveInteger":
616 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"type %n only accepts positive values (value supplied: %d)", $.type, $val);
620 # remove dashes from date
625 return date(substr($val, 0, 4) + substr($val, 5, 2) + substr($val, 8, 2) +
626 substr($val, 11, 2) + substr($val, 14, 2) + substr($val, 17, 2));
629 return date(
"19700101" + substr($val, 0, 2) + substr($val, 3, 2) + substr($val, 6, 2)) +
630 milliseconds(substr($val, 9, 3));
635 if ($val =~ /
false/i)
637 return boolean($val);
643 return parseBase64String($val);
646 return parseHexString($val);
649 if ($.type ==
"anyType") {
650 if (exists $types.$type)
651 return $types.$type.deserialize($types, $mrh, $val);
653 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"don't know how to handle type %n", $.type);
662 string getNameWithNS() {
667 # class for XSD array types; currently only supports "binary"; used, for example with HTTP MultiPart messages
668 public class WSDL::XSDArrayType inherits XSDData {
672 constructor(
string $t) {
676 throw "XSD-ARRAYTYPE-ERROR", sprintf(
"don't know how to handle arrays of type %n", $t);
678 any serialize(any $val, any $omit_type) {
681 my
int $t = $val.typeCode();
682 if ($t === NT_STRING)
684 else if ($t !== NT_BINARY)
685 throw SOAP_SERIALIZATION_ERROR, sprintf(
"cannot serialize type %n from type %n; requires string or binary", $.type, $t);
690 throw SOAP_SERIALIZATION_ERROR, sprintf(
"don't know how to handle type %n", $.type);
694 any deserialize(any $types, any $mrh, any $val) {
697 if ($val.typeCode() != NT_BINARY)
698 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"cannot deserialize type %n from type %n; requires binary", $.type, $val.typeName());
703 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"don't know how to handle type %n", $.type);
710 public class WSDL::XSDElement inherits XSDNamedData {
715 bool $.nillable = False;
717 constructor(hash $e, any $nsinfo, XSDLateResolverHelper $unresolved) : XSDNamedData(\$e) {
718 if ($nsinfo instanceof XSDData) {
723 my any $a = $e.
"^attributes^";
725 if (exists $a.minOccurs)
726 $.minOccurs = int($a.minOccurs);
728 if (exists $a.maxOccurs)
729 if ($a.maxOccurs ==
"unbounded")
732 $.maxOccurs = int($a.maxOccurs);
734 if ($.maxOccurs != -1 && $.minOccurs > $.maxOccurs)
735 throw "XSD-ELEMENT-ERROR", sprintf(
"minOccurs (%d) > maxOccurs (%d) for element %s", $.minOccurs, $.maxOccurs, $.name);
737 if ($a.nillable ==
"true")
740 if (exists $a.type) {
741 $.type = WSDL::XSDBase::doType($a.type, $nsinfo);
743 # add self to unresolved list if element type cannot be resolved
744 if (!($.type instanceof XSDData)) {
745 #printf("DEBUG: self=%n\n", $self);
746 $unresolved.add($self);
749 else if (exists $e.simpleType)
750 $.type =
new XSDSimpleType($e.simpleType, $nsinfo, $unresolved);
751 else if (exists $e.complexType)
752 $.type =
new XSDComplexType($e.complexType, $nsinfo, $unresolved);
754 #printf("DEBUG: XSDElement self=%N\n", $self);
757 any serialize(any $h, *softbool $omit_type, *softbool $omit_ns, any $key, any $typename) {
758 #printf("DEBUG: XSDElement::serialize() name=%y h=%y key=%y typename=%y\n", $.name, $h, $key, $typename);
763 my hash $rh = (
"xsi:nil" :
"true");
765 $rh += (
"xsi:type" : $.type.getNameWithNS());
766 return (
"^attributes^" : $rh);
769 if (exists $key && exists $typename)
770 throw SOAP_SERIALIZATION_ERROR, sprintf(
"missing value for %s.%s (minOccurs=%d, type %n)", $typename, $key, $.minOccurs, $.type.getName());
772 throw SOAP_SERIALIZATION_ERROR, sprintf(
"missing element value (minOccurs=%d, type %n)", $.minOccurs, $.type.getName());
778 if ($h.typeCode() == NT_LIST) {
779 if (elements $h == 1)
782 if ($.maxOccurs == 1)
783 throw SOAP_SERIALIZATION_ERROR, sprintf(
"cannot serialize element %n of type %n from a list because maxOccurs = 1", $.name, $.type.getName());
784 if (elements $h > $.maxOccurs && $.maxOccurs > 0)
785 throw SOAP_SERIALIZATION_ERROR, sprintf(
"list for element %n of type %n has %d element%s, but maxOccurs = %d", $.name, $.type.getName(), elements $h, elements $h == 1 ?
"" :
"s", $.maxOccurs);
786 if (elements $h < $.minOccurs)
787 throw SOAP_SERIALIZATION_ERROR, sprintf(
"list for element %n of type %n has %d element%s, but minOccurs = %d", $.name, $.type.getName(), elements $h, elements $h == 1 ?
"" :
"s", $.minOccurs);
790 foreach my any $e in ($h) {
791 $l += $.type.serialize($e, $omit_type, $omit_ns);
797 throw SOAP_SERIALIZATION_ERROR, sprintf(
"only one element passed to element %n of type $n, but minOccurs = %d", $.name, $.type.getName(), $.minOccurs);
798 #printf("DEBUG: element %n omit_type=%n omit_ns=%n\n", $.name, $omit_type, $omit_ns);
799 #printf("DEBUG: type=%N\n", $.type);
800 return $.type.serialize($h, $omit_type, $omit_ns);
803 any deserialize(any $types, any $mrh, any $val) {
804 my any $a = $val.
"^attributes^";
805 WSDL::XSDBase::removeNS(\$a);
807 if (!exists $val || $a.nil ==
"true") {
808 if ($.nillable || !$.minOccurs)
810 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"NOTHING passed for element %n, but nillable=False and minOccurs=%d", $.name, $.minOccurs);
813 if ($val.typeCode() == NT_LIST) {
814 my
int $el = elements $val;
815 if ($.maxOccurs != -1 && $el > $.maxOccurs)
816 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"error deserializing element %n, maxOccurs=%d but list is %d elements long", $.name, $.maxOccurs, $el);
817 if ($el < $.minOccurs)
818 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"error deserializing element %n, minOccurs=%d but list is %d elements long", $.name, $.minOccurs, $el);
821 foreach my any $e in ($val)
822 $l[elements $l] = $.type.deserialize($types, $mrh, $.getValue($mrh, $e));
827 throw SOAP_DESERIALIZATION_ERROR, sprintf("single value passed for element %n, but minOccurs=%d", $.name, $.minOccurs);
829 return $.type.deserialize($types, $mrh, $.getValue($mrh, $val));
833 # XSD simple type class
834 public class WSDL::XSDSimpleType inherits XSDNamedData {
841 constructor(hash $st, any $nsinfo, XSDLateResolverHelper $unresolved) : XSDNamedData(\$st) {
843 #my any $a = $st."^attributes^";
844 delete $st.
"^attributes^";
846 WSDL::XSDBase::removeNS(\$st);
848 if (exists $st.restriction) {
849 my any $r = $st.restriction;
851 my any $base = $r.
"^attributes^".base;
853 throw "XSD-SIMPLETYPE-ERROR", sprintf(
"missing 'base' attribute in simpleType %n restriction", $.name);
855 $.type = WSDL::XSDBase::doType($base, $nsinfo);
857 # add base type to unresolved list if type cannot be resolved
858 if (!($.type instanceof XSDData))
859 $unresolved.add($self);
861 WSDL::XSDBase::removeNS(\$r);
863 if (exists $r.enumeration)
864 $.enum = map $1.
"^attributes^".value, $r.enumeration;
866 throw "XSD-SIMPLETYPE-ERROR", sprintf(
"missing enumeration element in simpleType %n restriction", $.name);
869 throw "XSD-SIMPLETYPE-ERROR", sprintf(
"missing restriction element in simpleType %n", $.name);
871 #printf("DEBUG: st=%N\n", $self); exit();
874 any serialize(any $val, *softbool $omit_type, *softbool $omit_ns) {
875 if (!inlist($val, $.
enum))
876 throw "SOAP-SERIALIZATION-ERROR", sprintf(
"value %n passed to simpleType %n is not in the enumeration list (%n)", $val, $.name, $.
enum);
878 return $.type.serialize($val, $omit_type, $omit_ns);
881 any deserialize(any $types, any $mrh, any $val) {
882 my any $v = $.type.deserialize($types, $mrh, $val);
884 if (!inlist($v, $.
enum))
885 throw "SOAP-DESERIALIZATION-ERROR", sprintf(
"value %n passed to simpleType %n is not in the enumeration list (%n)", $v, $.name, $.
enum);
890 string getNameWithNS() {
891 return "ns1:" + $.name;
895 # XSD complex type class
896 public class WSDL::XSDComplexType inherits XSDNamedData {
905 bool $.anyAttribute = False;
907 constructor(any $ct, any $nsinfo, XSDLateResolverHelper $unresolved) : XSDNamedData(\$ct) {
909 #my any $a = $ct."^attributes^";
910 delete $ct.
"^attributes^";
912 my any $d = $ct.complexContent;
914 WSDL::XSDBase::removeNS(\$d);
915 if (exists $d.restriction) {
916 WSDL::XSDBase::removeNS(\$d.restriction);
918 my any $base = $d.restriction.
"^attributes^".base;
920 # FIXME: handle namespace
921 my (any $ns, any $tn) = $base =~ x/(\w+):(\w+)/;
923 if ($tn ==
"Array") {
924 # FIXME check that namespace is SOAP encoding
925 my any $aa = $d.restriction.attribute.
"^attributes^";
926 WSDL::XSDBase::removeNS(\$aa);
927 if (!exists $aa.arrayType)
928 throw WSDL_ERROR, sprintf(
"cannot parse complexType restriction: %n", $d.restriction);
930 # FIXME: handle multiple dimensions?
931 my (any $ans, any $atn) = $aa.arrayType =~ x/(\w+):(\w+)\[\]$/;
937 $.array.val = $aa.arrayType;
939 delete $d.restriction.attribute;
940 #printf("DEBUG: ans=%n atn=%n aa=%N\n", $ans, $atn, $aa);
948 delete $d.restriction.
"^attributes^";
950 $.parseData($d.restriction, $unresolved);
952 else if (exists $d.extension) {
953 $.extension = $d.extension.
"^attributes^".base;
955 # FIXME: check for soap encoding namespace
956 $.extension =~ s/(.*:)(.*)/$2/;
957 delete $d.extension.
"^attributes^";
958 WSDL::XSDBase::removeNS(\$d.extension);
960 $.parseData($d.extension, $unresolved);
963 throw "XSD-COMPLEXCONTENT-ERROR", sprintf(
"can't parse complexContent %n information", $d.firstKey());
966 $.parseData($ct, $unresolved);
969 private parseData(any $d, XSDLateResolverHelper $unresolved) {
971 my list $el = keys $d;
972 if (inlist(
"anyAttribute", $el)) {
973 $.anyAttribute = True;
974 delete $d.anyAttribute;
979 throw WSDL_ERROR, sprintf(
"%s: expecting a single element in the complexType hash, got: %n", $.name, $el);
981 my
string $k = $el[0];
983 $.hash_type = XET_ALL;
984 WSDL::XSDBase::removeNS(\$d.all);
985 $.elements = $.parseElements($d.all.element, $unresolved);
987 else if ($k ==
"choice") {
988 $.hash_type = XET_CHOICE;
989 WSDL::XSDBase::removeNS(\$d.choice);
990 $.elements = $.parseElements($d.choice.element, $unresolved);
992 else if ($k ==
"sequence") {
993 $.hash_type = XET_SEQUENCE;
994 WSDL::XSDBase::removeNS(\$d.sequence);
995 if (exists $d.sequence.element)
996 $.elements = $.parseElements($d.sequence.element, $unresolved);
1001 throw "XSD-COMPLEXTYPE-ERROR", sprintf(
"unknown keys in %n", $d);
1004 private hash parseElements(any $el, XSDLateResolverHelper $unresolved) {
1005 #printf("DEBUG: XSDComplexType::parseElements(%n)\n", $el);
1007 foreach my any $e in ($el) {
1008 my XSDElement $elem($e, $.nsinfo, $unresolved);
1009 $h.($elem.name) = $elem;
1014 any serialize(any $h, *softbool $omit_type, *softbool $omit_ns) {
1016 return $.array.serialize($h, $omit_type, $omit_ns);
1018 if ($h.typeCode() != NT_HASH)
1019 throw SOAP_SERIALIZATION_ERROR, sprintf(
"expecting hash argument to serialize from complexType %n (got %n, type %n)", $.getName(), $h, type($h));
1023 if ($.hash_type == XET_SEQUENCE || $.hash_type == XET_ALL) {
1024 foreach my
string $p in (keys $.elements) {
1025 #printf("DEBUG element=%s=%y\nvalue=%y\n", $p, $.elements.$p, $h.$p);
1026 my any $e = $.elements.$p.serialize($h.$p, $omit_type, $omit_ns, $p, $.name);
1028 my any $key = $omit_ns ? $p : (
"ns1:" + $p);
1034 throw SOAP_SERIALIZATION_ERROR, sprintf(
"%n %s of type %n (valid elements: %n)", (my
string $kl = keys $h), elements $kl == 1 ?
"is an invalid member" :
"are invalid members", $.getName(), keys $.elements);
1036 else { #
"choice" -
union
1037 if (elements $h > 1)
1038 throw SOAP_SERIALIZATION_ERROR, sprintf(
"cannot serialize type %s with more than 1 member (%n)", $.getName(), keys $h);
1039 my *
string $key = keys $h.firstKey();
1040 if (!exists $.elements.$key)
1041 throw SOAP_SERIALIZATION_ERROR, sprintf(
"%n is an invalid member of type %n", $key, $.getName());
1043 # add namespace if necessary
1044 my
string $nskey = $omit_ns ? $key : (
"ns1:" + $key);
1045 $rh.$nskey = $.elements.$key.serialize($h.$key, $omit_type, $omit_ns, $key, $.name);
1048 if (exists $.name && !$omit_type)
1049 $rh.
"^attributes^" = (
"xsi:type" :
"ns1:" + $.name );
1050 #printf("complex type %s returning %n from %n\n", $.name, $rh, $h);
1054 hash deserialize(any $types, any $mrh, any $val) {
1056 return $.array.deserialize($types, $mrh, $val);
1058 if ($val.typeCode() != NT_HASH)
1059 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"cannot deserialize type %n from qore type %n (expecting hash)", $.getName(), type($val));
1063 my any $attr = $val.
"^attributes^";
1064 delete $val.
"^attributes^";
1066 # ensure types match
1067 my any $tn = $attr.
"xsi:type";
1069 my (any $ns, any $name) = $tn =~ x/(.*):(.*)/;
1073 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"expecting ComplexType type %n, got %n", $.getName(), $tn);
1076 WSDL::XSDBase::removeNS2(\$val);
1078 #my any $ns = $val.".ns";
1081 if ($.hash_type == XET_SEQUENCE || $.hash_type == XET_ALL) {
1082 foreach my
string $p in (keys $.elements) {
1083 #printf("element %n\n", $p);
1084 $rh.$p = $.elements.$p.deserialize($types, $mrh, $.getValue($mrh, $val.$p));
1087 delete $val.
"^attributes^";
1089 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"invalid element %n passed in type %n (expecting %n)", (keys $val)[0], $.getName(), keys $.elements);
1091 else { #
"choice" -
union
1092 my any $kl = keys $val;
1093 if (elements $kl > 1)
1094 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"too many elements supplied for union type %n (%n)", $.getName(), $kl);
1096 if (!exists $.elements.$kl)
1097 throw SOAP_DESERIALIZATION_ERROR, sprintf(
"element %n is not a valid element for union type %n", $kl, $.getName());
1099 $rh.$kl = $.elements.$kl.deserialize($types, $mrh, $.getValue($mrh, $val.$kl));
1104 string getNameWithNS() {
1105 return "ns1:" + $.name;
1109 #! web service operation class
1110 public class WSDL::WSOperation inherits XSDNamedData {
1116 bool $.soap12 = False;
1117 bool $.usedocns = False;
1118 *
string $.soapAction;
1119 *
string $.request_name;
1122 bool $.docstyle = False;
1124 # info about soap header requirements
1129 constructor(any $p, any $types,
string $targetns, any $messages,
bool $soap12 = False,
bool $usedocns = False) : XSDNamedData(\$p) {
1131 $.targetns = $targetns;
1133 $.usedocns = $usedocns;
1135 my any $msghash = $.processNSValue($p.input.
"^attributes^");
1137 my *WSMessage $msg = $messages.($msghash.message.val);
1139 throw WSDL_ERROR, sprintf(
"missing definition for input message %n required by operation %n", $msghash.name.val, $.name);
1142 if (exists $p.output) {
1143 $msghash = $.processNSValue($p.output.
"^attributes^");
1145 $msg = $messages.($msghash.message.val);
1147 throw WSDL_ERROR, sprintf(
"missing definition for output message %n required by operation %n", $msghash.name.val, $.name);
1152 my *
string $op_ns = $.targetns;
1153 if (exists $op_ns && $op_ns !~ /\/$/)
1155 $.soapAction = exists $op_ns ? $op_ns + $.name : $.name;
1158 setDocStyle(reference $idocmap) {
1161 if (elements $.input.args > 1)
1162 throw WSDL_ERROR, sprintf(
"don't know how to handle document-style messages for operation %n that has more than one top-level part (%n)",
1163 $.name, keys $.input.args);
1165 my any $arg = ($.input.args).firstKey();
1166 my any $element = $.input.args.$arg.element.name;
1167 $.request_name = $element;
1168 $idocmap.$element = $.input.args.$arg.element;
1171 setTopLevelRequestElement(
string $name) {
1172 $.request_name = $name;
1175 string getTopLevelRequestName() {
1176 return exists $.request_name ? $.request_name : $.name;
1179 #! serializes a request to an XML string for the operation
1187 hash serializeRequest(any h, any header, *
string enc);
1197 hash serializeResponse(any h, *
string enc);
1202 list processMultiRef(hash body);
1210 any deserializeRequest(hash o);
1217 any deserializeResponse(hash o);
1222 hash processNSValue(hash h);
1235 string getTargetNS();
1238 setOutputMultipart(any v);
1243 parsePart(reference msg, any part);
1247 addOutputPart(any part);
1250 setInputMultipart(any v);
1253 addInputPart(any part);
1256 setInputHeader(
string part, WSMessage msg,
bool encoded);
1261 class WSDL::WSMessage :
public XSDNamedData {
1266 bool encoded = False;
1269 constructor(any m, any element_map);
1272 hash serialize(any msginfo, any mpm, any name, any h);
1275 hash serializeDocument(any msginfo, any mpm, any h,
bool force_ns);
1278 any deserialize(any types, any mrh, any val);
1281 any deserializeDocument(any types, any mrh, any val);
1286 class WSDL::XSDLateResolverHelper {
1304 class WSDL::XSDImportHelper {
1313 constructor(WebService ws, any xsd);
1320 class WSDL::Binding :
public XSDNamedData {
1324 bool docStyle = False;
1328 constructor(hash data, hash opmap, reference idocmap, *hash messages);
1335 class WSDL::WebService :
public XSDBase {
1341 bool soap12 = False;
1344 list wsdl_services = ();
1351 bool usedocns = False;
1362 constructor(
string str, *hash opts);
1368 *hash getOperationMap(any name);
1373 getNSPrefixes(any a);
1379 XSDBaseType getBaseType(any t);
1385 any resolveType(hash v);
1392 parseTypes(any data, any http_client, any http_headers);
1398 parseMessage(any message);
1404 parseService(any svc);
1410 parsePortType(any data);
1416 parseBinding(any bindings);