From ec2950854aa4ac1a05c1108d1b50758bfe854bdf Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Thu, 22 Jan 2004 15:58:03 +0000 Subject: [PATCH] XML Schema support was improved support for content model (,,) support for top-level support for 'ref' attribute support for content model encoding/decoding (incomplete) support for attribute encoding/decoding (incomplete) support for with inline anonymous --- ext/soap/TODO | 48 ++-- ext/soap/php_encoding.c | 224 ++++++++++++++--- ext/soap/php_schema.c | 515 +++++++++++++++++++++++++++++++--------- ext/soap/php_schema.h | 1 + ext/soap/php_sdl.c | 118 ++++----- ext/soap/php_sdl.h | 60 +++-- 6 files changed, 708 insertions(+), 258 deletions(-) diff --git a/ext/soap/TODO b/ext/soap/TODO index d6f2e97a12..1e73c31665 100644 --- a/ext/soap/TODO +++ b/ext/soap/TODO @@ -20,7 +20,7 @@ SOAP Encoding -------- -- full support for standard simple types ( +? full support for standard simple types ( + anyType + anyURI, + QName, @@ -39,7 +39,7 @@ Encoding ? ENTITIES, (list: ENTITY; minLength: 1) ? duration, + unsignedLong) -- full support for standard date/time types ( +? full support for standard date/time types ( ? dateTime, ? time, ? date, @@ -50,7 +50,7 @@ Encoding ? gMonth) ? proper encoding of standard hexBinary type ? proper encoding of standard base64Binary type -- full support for arrays +? full support for arrays + arrayType attribute + offset attribute + position attribute @@ -60,7 +60,9 @@ Encoding + SOAP 1.1 - arrayType="xsd:ur-type[]", SOAP 1.2 - itemType="xsd:anyType" - SOAP 1.1 encoding of arrays with holes (partially transmitted and sparse arrays) SOAP 1.2 doesn't support partially transmitted and sparse arrays -- full support for structures??? +? full support for structures + + support for attribute encoding/decoding + - full support for content model encoding/decoding + references (id,href) + SOAP 1.2 (enc:id,enc:ref) - references to external resources @@ -78,7 +80,7 @@ WSDL + support for portType operation input/output name attribute + support for without - support for portType operation parameterOrder attribute -- support for binding operation input/output name attribute +- support for binding operation input/output name attribute (part of overloading) - support for + support for style "rpc"/"document" encoding (client part) - support for style "rpc"/"document" encoding (server part) @@ -98,8 +100,8 @@ WSDL Schema ------ -- , , -- support for user defined simple types +- +? support for user defined simple types ? restiction + base + enumeration @@ -116,30 +118,20 @@ Schema - fractionDigits (for decimal) ? list ? union -- support for user defined complex types - - simpleContent restriction +? support for user defined complex types + ? full support for content model encoding/decoding + ? simpleContent restriction - simpleContent extension - - complexContent restriction + ? complexContent restriction - complexContent extension - + base - - all - - element - - choice - - element - - group - - choice - - sequence - - any ??? - - sequence - - element - - group - - choice - - sequence - - any ??? - - group - ? attribute + + all + + choice + + sequence + + group + + element + + attribute + attributeGroup - - anyAttribute + - SOAP 1.2 array encoding/decoding (itemType, arraySize) Error Handling -------------- diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 16b2470282..9bb904716c 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -678,37 +678,162 @@ zval *to_zval_object(encodeType type, xmlNodePtr data) } object_init(ret); - trav = data->children; - - while (trav != NULL) { - if (trav->type == XML_ELEMENT_NODE) { - sdlTypePtr *element; - encodePtr enc = NULL; - zval *tmpVal; - - xmlAttrPtr typeAttr = get_attribute(trav->properties,"type"); - if (typeAttr != NULL && typeAttr->children && typeAttr->children->content) { - enc = get_encoder_from_prefix(sdl, trav, typeAttr->children->content); - } - if (enc == NULL && sdlType != NULL && sdlType->elements != NULL && trav->name != NULL && - zend_hash_find(sdlType->elements, (char*)trav->name, strlen(trav->name)+1,(void **)&element) == SUCCESS) { - enc = (*element)->encode; + if (type.sdl_type) { + if (type.sdl_type->elements) { + sdlTypePtr *tmpType; + zend_hash_internal_pointer_reset(type.sdl_type->elements); + while (zend_hash_get_current_data(type.sdl_type->elements, (void**)&tmpType) == SUCCESS) { + if ((*tmpType)->name) { + xmlNodePtr node = get_node(data->children, (*tmpType)->name); + if (node) { + xmlAttrPtr typeAttr = get_attribute(node->properties,"type"); + encodePtr enc = NULL; + zval *val; + + if (typeAttr != NULL && typeAttr->children && typeAttr->children->content) { + enc = get_encoder_from_prefix(sdl, node, typeAttr->children->content); + } + if (enc == NULL) { + enc = (*tmpType)->encode; + } + val = master_to_zval(enc, node); + if ((node = get_node(node->next, (*tmpType)->name)) != NULL) { + zval *array; + MAKE_STD_ZVAL(array); + array_init(array); + add_next_index_zval(array, val); + do { + typeAttr = get_attribute(node->properties,"type"); + enc = NULL; + if (typeAttr != NULL && typeAttr->children && typeAttr->children->content) { + enc = get_encoder_from_prefix(sdl, node, typeAttr->children->content); + } + if (enc == NULL) { + enc = (*tmpType)->encode; + } + val = master_to_zval(enc, node); + add_next_index_zval(array, val); + } while ((node = get_node(node->next, (*tmpType)->name)) != NULL); + val = array; + } +#ifdef ZEND_ENGINE_2 + val->refcount--; +#endif + add_property_zval(ret, (*tmpType)->name, val); + } + } + zend_hash_move_forward(type.sdl_type->elements); } - if (enc == NULL) { - enc = get_conversion(UNKNOWN_TYPE); + } + if (type.sdl_type->attributes) { + sdlAttributePtr *attr; + + zend_hash_internal_pointer_reset(type.sdl_type->attributes); + while (zend_hash_get_current_data(type.sdl_type->attributes, (void**)&attr) == SUCCESS) { + if ((*attr)->name) { + xmlAttrPtr val = get_attribute(data->properties, (*attr)->name); + if (val && val->children && val->children->content) { + add_property_string(ret, (*attr)->name, val->children->content, 1); + } + } + zend_hash_move_forward(type.sdl_type->attributes); } + } + } else { + trav = data->children; - tmpVal = master_to_zval(enc, trav); + while (trav != NULL) { + if (trav->type == XML_ELEMENT_NODE) { + encodePtr enc = NULL; + zval *tmpVal; + + xmlAttrPtr typeAttr = get_attribute(trav->properties,"type"); + if (typeAttr != NULL && typeAttr->children && typeAttr->children->content) { + enc = get_encoder_from_prefix(sdl, trav, typeAttr->children->content); + } + tmpVal = master_to_zval(enc, trav); #ifdef ZEND_ENGINE_2 - tmpVal->refcount--; + tmpVal->refcount--; #endif - add_property_zval(ret, (char *)trav->name, tmpVal); + add_property_zval(ret, (char *)trav->name, tmpVal); + } + trav = trav->next; } - trav = trav->next; } return ret; } +static int model_to_xml_object(xmlNodePtr node, sdlContentModelPtr model, HashTable *prop, int style, int strict) +{ + switch (model->kind) { + case XSD_CONTENT_ELEMENT: { + zval **data; + xmlNodePtr property; + encodePtr enc; + + if (zend_hash_find(prop, model->u.element->name, strlen(model->u.element->name)+1, (void**)&data) == SUCCESS) { + enc = model->u.element->encode; + if ((model->max_occurs == -1 || model->max_occurs > 1) && Z_TYPE_PP(data) == IS_ARRAY) { + HashTable *ht = Z_ARRVAL_PP(data); + zval **val; + + zend_hash_internal_pointer_reset(ht); + while (zend_hash_get_current_data(ht,(void**)&val) == SUCCESS) { + property = master_to_xml(enc, *val, style); + xmlNodeSetName(property, model->u.element->name); + xmlAddChild(node, property); + zend_hash_move_forward(ht); + } + } else { + property = master_to_xml(enc, *data, style); + xmlNodeSetName(property, model->u.element->name); + xmlAddChild(node, property); + } + return 1; + } else if (model->min_occurs == 0) { + return 1; + } else { + if (strict) { + php_error(E_ERROR, "object hasn't '%s' property",model->u.element->name); + } + return 0; + } + break; + } + case XSD_CONTENT_SEQUENCE: + case XSD_CONTENT_ALL: { + sdlContentModelPtr *tmp; + + zend_hash_internal_pointer_reset(model->u.content); + while (zend_hash_get_current_data(model->u.content, (void**)&tmp) == SUCCESS) { + if (!model_to_xml_object(node, *tmp, prop, style, model->min_occurs > 0)) { + return 0; + } + zend_hash_move_forward(model->u.content); + } + return 1; + } + case XSD_CONTENT_CHOICE: { + sdlContentModelPtr *tmp; + + zend_hash_internal_pointer_reset(model->u.content); + while (zend_hash_get_current_data(model->u.content, (void**)&tmp) == SUCCESS) { + if (model_to_xml_object(node, *tmp, prop, style, 0)) { + return 1; + } + zend_hash_move_forward(model->u.content); + } + return 0; + } + case XSD_CONTENT_GROUP: { + return model_to_xml_object(node, model->u.group, prop, style, model->min_occurs > 0); + } + default: + break; + } + return 1; +} + xmlNodePtr to_xml_object(encodeType type, zval *data, int style) { xmlNodePtr xmlParam; @@ -756,36 +881,67 @@ xmlNodePtr to_xml_object(encodeType type, zval *data, int style) smart_str_free(ns); efree(ns); } - } else { + } else if (type.sdl_type) { xmlParam = xmlNewNode(NULL, "BOGUS"); FIND_ZVAL_NULL(data, xmlParam, style); + prop = NULL; if (Z_TYPE_P(data) == IS_OBJECT) { - sdlTypePtr sdl_type = type.sdl_type; + prop = Z_OBJPROP_P(data); + } else if (Z_TYPE_P(data) == IS_ARRAY) { + prop = Z_ARRVAL_P(data); + } + if (prop != NULL) { + if (type.sdl_type->model) { + model_to_xml_object(xmlParam, type.sdl_type->model, prop, style, 1); + } + if (type.sdl_type->attributes) { + sdlAttributePtr *attr; + zval **data; + + zend_hash_internal_pointer_reset(type.sdl_type->attributes); + while (zend_hash_get_current_data(type.sdl_type->attributes, (void**)&attr) == SUCCESS) { + if ((*attr)->name) { + if (zend_hash_find(prop, (*attr)->name, strlen((*attr)->name)+1, (void**)&data) == SUCCESS) { + xmlNodePtr dummy; + + dummy = master_to_xml((*attr)->encode, *data, SOAP_LITERAL); + if (dummy->children && dummy->children->content) { + xmlSetProp(xmlParam, (*attr)->name, dummy->children->content); + } + xmlFreeNode(dummy); + } + } + zend_hash_move_forward(type.sdl_type->attributes); + } + } + } + if (style == SOAP_ENCODED) { + set_ns_and_type(xmlParam, type); + } + } else { + xmlParam = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, xmlParam, style); + prop = NULL; + if (Z_TYPE_P(data) == IS_OBJECT) { prop = Z_OBJPROP_P(data); + } else if (Z_TYPE_P(data) == IS_ARRAY) { + prop = Z_ARRVAL_P(data); + } + if (prop != NULL) { i = zend_hash_num_elements(prop); zend_hash_internal_pointer_reset(prop); for (;i > 0;i--) { xmlNodePtr property; - encodePtr enc = NULL; zval **zprop; char *str_key; zend_hash_get_current_key(prop, &str_key, NULL, FALSE); zend_hash_get_current_data(prop, (void **)&zprop); - if (sdl_type && sdl_type->elements) { - sdlTypePtr *el_type; - if (zend_hash_find(sdl_type->elements, str_key, strlen(str_key) + 1, (void **)&el_type) == SUCCESS) { - enc = (*el_type)->encode; - } - } - if (enc == NULL) { - enc = get_conversion((*zprop)->type); - } - property = master_to_xml(enc, (*zprop), style); + property = master_to_xml(get_conversion((*zprop)->type), (*zprop), style); xmlNodeSetName(property, str_key); xmlAddChild(xmlParam, property); diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c index 7f4f7124bd..200db31be7 100644 --- a/ext/soap/php_schema.c +++ b/ext/soap/php_schema.c @@ -2,7 +2,6 @@ static int schema_simpleType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr simpleType, sdlTypePtr cur_type); static int schema_complexType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr compType, sdlTypePtr cur_type); -static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTypePtr cur_type); static int schema_list(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr listType, sdlTypePtr cur_type); static int schema_union(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr unionType, sdlTypePtr cur_type); static int schema_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr simpCompType, sdlTypePtr cur_type); @@ -10,18 +9,22 @@ static int schema_restriction_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodeP static int schema_restriction_complexContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type); static int schema_extension_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type); static int schema_extension_complexContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type); -static int schema_all(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type); -static int schema_group(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTypePtr cur_type); -static int schema_choice(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlTypePtr cur_type); -static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTypePtr cur_type); +static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTypePtr cur_type, sdlContentModelPtr model); +static int schema_all(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type, sdlContentModelPtr model); +static int schema_choice(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlTypePtr cur_type, sdlContentModelPtr model); +static int schema_group(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTypePtr cur_type, sdlContentModelPtr model); +static int schema_any(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type, sdlContentModelPtr model); +static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTypePtr cur_type, sdlContentModelPtr model); static int schema_attribute(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr attrType, sdlTypePtr cur_type); -static int schema_any(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type); static int schema_attributeGroup(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr attrType, sdlTypePtr cur_type); static int schema_restriction_var_int(xmlNodePtr val, sdlRestrictionIntPtr *valptr); static int schema_restriction_var_char(xmlNodePtr val, sdlRestrictionCharPtr *valptr); +static void schema_type_fixup(sdlPtr sdl, sdlTypePtr type); + +static void delete_model(void *handle); static int is_blank(const char* str) { @@ -182,6 +185,13 @@ int load_schema(sdlPtr sdl,xmlNodePtr schema) } } else if (node_is_equal(trav,"annotation")) { /* TODO: support */ +/* annotation cleanup + xmlNodePtr tmp = trav; + trav = trav->next; + xmlUnlinkNode(tmp); + xmlFreeNode(tmp); + continue; +*/ } else { break; } @@ -194,11 +204,11 @@ int load_schema(sdlPtr sdl,xmlNodePtr schema) } else if (node_is_equal(trav,"complexType")) { schema_complexType(sdl, tns, trav, NULL); } else if (node_is_equal(trav,"group")) { - schema_group(sdl, tns, trav, NULL); + schema_group(sdl, tns, trav, NULL, NULL); } else if (node_is_equal(trav,"attributeGroup")) { schema_attributeGroup(sdl, tns, trav, NULL); } else if (node_is_equal(trav,"element")) { - schema_element(sdl, tns, trav, NULL); + schema_element(sdl, tns, trav, NULL, NULL); } else if (node_is_equal(trav,"attribute")) { schema_attribute(sdl, tns, trav, NULL); } else if (node_is_equal(trav,"notation")) { @@ -671,19 +681,16 @@ static int schema_restriction_complexContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNode } if (trav != NULL) { if (node_is_equal(trav,"group")) { - schema_group(sdl, tsn, trav, cur_type); + schema_group(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"all")) { - cur_type->kind = XSD_TYPEKIND_ALL; - schema_all(sdl, tsn, trav, cur_type); + schema_all(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"choice")) { - cur_type->kind = XSD_TYPEKIND_CHOICE; - schema_choice(sdl, tsn, trav, cur_type); + schema_choice(sdl, tsn, trav, cur_type, NULL); trav = trav->next; - cur_type->kind = XSD_TYPEKIND_SEQUENCE; } else if (node_is_equal(trav,"sequence")) { - schema_sequence(sdl, tsn, trav, cur_type); + schema_sequence(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } } @@ -846,19 +853,16 @@ static int schema_extension_complexContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePt } if (trav != NULL) { if (node_is_equal(trav,"group")) { - schema_group(sdl, tsn, trav, cur_type); + schema_group(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"all")) { - cur_type->kind = XSD_TYPEKIND_ALL; - schema_all(sdl, tsn, trav, cur_type); + schema_all(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"choice")) { - cur_type->kind = XSD_TYPEKIND_CHOICE; - schema_choice(sdl, tsn, trav, cur_type); + schema_choice(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"sequence")) { - cur_type->kind = XSD_TYPEKIND_SEQUENCE; - schema_sequence(sdl, tsn, trav, cur_type); + schema_sequence(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } } @@ -891,9 +895,38 @@ static int schema_extension_complexContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePt Content: (annotation?, element*) */ -static int schema_all(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr all, sdlTypePtr cur_type) +static int schema_all(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr all, sdlTypePtr cur_type, sdlContentModelPtr model) { xmlNodePtr trav; + xmlAttrPtr attr; + sdlContentModelPtr newModel; + + newModel = malloc(sizeof(sdlContentModel)); + newModel->kind = XSD_CONTENT_ALL; + newModel->u.content = malloc(sizeof(HashTable)); + zend_hash_init(newModel->u.content, 0, NULL, delete_model, 1); + if (model == NULL) { + cur_type->model = newModel; + } else { + zend_hash_next_index_insert(model->u.content,&newModel,sizeof(sdlContentModelPtr), NULL); + } + + newModel->min_occurs = 1; + newModel->max_occurs = 1; + + attr = get_attribute(all->properties, "minOccurs"); + if (attr) { + newModel->min_occurs = atoi(attr->children->content); + } + + attr = get_attribute(all->properties, "maxOccurs"); + if (attr) { + if (!strcmp(attr->children->content, "unbounded")) { + newModel->max_occurs = -1; + } else { + newModel->max_occurs = atoi(attr->children->content); + } + } trav = all->children; if (trav != NULL && node_is_equal(trav,"annotation")) { @@ -902,7 +935,7 @@ static int schema_all(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr all, sdlTypePtr cur } while (trav != NULL) { if (node_is_equal(trav,"element")) { - schema_element(sdl, tsn, trav, cur_type); + schema_element(sdl, tsn, trav, cur_type, newModel); } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in all)",trav->name); } @@ -913,18 +946,108 @@ static int schema_all(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr all, sdlTypePtr cur /* + name = NCName Content: (annotation?, (all | choice | sequence)) + + Content: (annotation?) + */ -static int schema_group(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTypePtr cur_type) +static int schema_group(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTypePtr cur_type, sdlContentModelPtr model) { xmlNodePtr trav; - xmlAttrPtr name; + xmlAttrPtr attr; + xmlAttrPtr ns, name, ref = NULL; + sdlContentModelPtr newModel; + + ns = get_attribute(groupType->properties, "targetNamespace"); + if (ns == NULL) { + ns = tsn; + } name = get_attribute(groupType->properties, "name"); - if (name != NULL) { - /*FIXME*/ + if (name == NULL) { + name = ref = get_attribute(groupType->properties, "ref"); + } + + if (name) { + smart_str key = {0}; + + if (ref) { + char *type, *ns; + xmlNsPtr nsptr; + + parse_namespace(ref->children->content, &type, &ns); + nsptr = xmlSearchNs(groupType->doc, groupType, ns); + if (nsptr != NULL) { + smart_str_appends(&key, nsptr->href); + smart_str_appendc(&key, ':'); + } + smart_str_appends(&key, type); + smart_str_0(&key); + + newModel = malloc(sizeof(sdlContentModel)); + newModel->kind = XSD_CONTENT_GROUP_REF; + newModel->u.group_ref = estrdup(key.c); + + if (type) {efree(type);} + if (ns) {efree(ns);} + } else { + newModel = malloc(sizeof(sdlContentModel)); + newModel->kind = XSD_CONTENT_SEQUENCE; /* will be redefined */ + newModel->u.content = malloc(sizeof(HashTable)); + zend_hash_init(newModel->u.content, 0, NULL, delete_model, 1); + + smart_str_appends(&key, ns->children->content); + smart_str_appendc(&key, ':'); + smart_str_appends(&key, name->children->content); + smart_str_0(&key); + } + + if (cur_type == NULL) { + sdlTypePtr newType; + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + + if (sdl->groups == NULL) { + sdl->groups = malloc(sizeof(HashTable)); + zend_hash_init(sdl->groups, 0, NULL, delete_type, 1); + } + if (zend_hash_add(sdl->groups, key.c, key.len+1, (void**)&newType, sizeof(sdlTypePtr), NULL) != SUCCESS) { + php_error(E_ERROR, "Error parsing schema (group '%s' already defined)",key.c); + } + + cur_type = newType; + } + smart_str_free(&key); + + if (model == NULL) { + cur_type->model = newModel; + } else { + zend_hash_next_index_insert(model->u.content, &newModel, sizeof(sdlContentModelPtr), NULL); + } + } else { + php_error(E_ERROR, "Error parsing schema (group has no 'name' nor 'ref' attributes)"); + } + + newModel->min_occurs = 1; + newModel->max_occurs = 1; + + attr = get_attribute(groupType->properties, "minOccurs"); + if (attr) { + newModel->min_occurs = atoi(attr->children->content); + } + + attr = get_attribute(groupType->properties, "maxOccurs"); + if (attr) { + if (!strcmp(attr->children->content, "unbounded")) { + newModel->max_occurs = -1; + } else { + newModel->max_occurs = atoi(attr->children->content); + } } trav = groupType->children; @@ -934,16 +1057,25 @@ static int schema_group(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTyp } if (trav != NULL) { if (node_is_equal(trav,"choice")) { - cur_type->kind = XSD_TYPEKIND_CHOICE; - schema_choice(sdl, tsn, trav, cur_type); + if (ref != NULL) { + php_error(E_ERROR, "Error parsing schema (group have both 'ref' attribute and subcontent)"); + } + newModel->kind = XSD_CONTENT_CHOICE; + schema_choice(sdl, tsn, trav, cur_type, newModel); trav = trav->next; } else if (node_is_equal(trav,"sequence")) { - cur_type->kind = XSD_TYPEKIND_SEQUENCE; - schema_sequence(sdl, tsn, trav, cur_type); + if (ref != NULL) { + php_error(E_ERROR, "Error parsing schema (group have both 'ref' attribute and subcontent)"); + } + newModel->kind = XSD_CONTENT_SEQUENCE; + schema_sequence(sdl, tsn, trav, cur_type, newModel); trav = trav->next; } else if (node_is_equal(trav,"all")) { - cur_type->kind = XSD_TYPEKIND_ALL; - schema_all(sdl, tsn, trav, cur_type); + if (ref != NULL) { + php_error(E_ERROR, "Error parsing schema (group have both 'ref' attribute and subcontent)"); + } + newModel->kind = XSD_CONTENT_ALL; + schema_all(sdl, tsn, trav, cur_type, newModel); trav = trav->next; } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in group)",trav->name); @@ -963,13 +1095,38 @@ static int schema_group(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTyp Content: (annotation?, (element | group | choice | sequence | any)*) */ -static int schema_choice(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlTypePtr cur_type) +static int schema_choice(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlTypePtr cur_type, sdlContentModelPtr model) { xmlNodePtr trav; + xmlAttrPtr attr; + sdlContentModelPtr newModel; + + newModel = malloc(sizeof(sdlContentModel)); + newModel->kind = XSD_CONTENT_CHOICE; + newModel->u.content = malloc(sizeof(HashTable)); + zend_hash_init(newModel->u.content, 0, NULL, delete_model, 1); + if (model == NULL) { + cur_type->model = newModel; + } else { + zend_hash_next_index_insert(model->u.content,&newModel,sizeof(sdlContentModelPtr), NULL); + } + + newModel->min_occurs = 1; + newModel->max_occurs = 1; + + attr = get_attribute(choiceType->properties, "minOccurs"); + if (attr) { + newModel->min_occurs = atoi(attr->children->content); + } - /* - cur_type->property_type = CHOICE; - */ + attr = get_attribute(choiceType->properties, "maxOccurs"); + if (attr) { + if (!strcmp(attr->children->content, "unbounded")) { + newModel->max_occurs = -1; + } else { + newModel->max_occurs = atoi(attr->children->content); + } + } trav = choiceType->children; if (trav != NULL && node_is_equal(trav,"annotation")) { @@ -978,19 +1135,15 @@ static int schema_choice(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlT } while (trav != NULL) { if (node_is_equal(trav,"element")) { - schema_element(sdl, tsn, trav, cur_type); - } else if (node_is_equal(trav,"grouop")) { - /*FIXME*/ - schema_group(sdl, tsn, trav, cur_type); + schema_element(sdl, tsn, trav, cur_type, newModel); + } else if (node_is_equal(trav,"group")) { + schema_group(sdl, tsn, trav, cur_type, newModel); } else if (node_is_equal(trav,"choice")) { - /*FIXME*/ - schema_choice(sdl, tsn, trav, cur_type); + schema_choice(sdl, tsn, trav, cur_type, newModel); } else if (node_is_equal(trav,"sequence")) { - /*FIXME*/ - schema_sequence(sdl, tsn, trav, cur_type); + schema_sequence(sdl, tsn, trav, cur_type, newModel); } else if (node_is_equal(trav,"any")) { - /*FIXME*/ - schema_any(sdl, tsn, trav, cur_type); + schema_any(sdl, tsn, trav, cur_type, newModel); } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in choice)",trav->name); } @@ -1008,9 +1161,38 @@ static int schema_choice(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlT Content: (annotation?, (element | group | choice | sequence | any)*) */ -static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTypePtr cur_type) +static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTypePtr cur_type, sdlContentModelPtr model) { xmlNodePtr trav; + xmlAttrPtr attr; + sdlContentModelPtr newModel; + + newModel = malloc(sizeof(sdlContentModel)); + newModel->kind = XSD_CONTENT_SEQUENCE; + newModel->u.content = malloc(sizeof(HashTable)); + zend_hash_init(newModel->u.content, 0, NULL, delete_model, 1); + if (model == NULL) { + cur_type->model = newModel; + } else { + zend_hash_next_index_insert(model->u.content,&newModel,sizeof(sdlContentModelPtr), NULL); + } + + newModel->min_occurs = 1; + newModel->max_occurs = 1; + + attr = get_attribute(seqType->properties, "minOccurs"); + if (attr) { + newModel->min_occurs = atoi(attr->children->content); + } + + attr = get_attribute(seqType->properties, "maxOccurs"); + if (attr) { + if (!strcmp(attr->children->content, "unbounded")) { + newModel->max_occurs = -1; + } else { + newModel->max_occurs = atoi(attr->children->content); + } + } trav = seqType->children; if (trav != NULL && node_is_equal(trav,"annotation")) { @@ -1019,19 +1201,15 @@ static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTy } while (trav != NULL) { if (node_is_equal(trav,"element")) { - schema_element(sdl, tsn, trav, cur_type); - } else if (node_is_equal(trav,"grouop")) { - /*FIXME*/ - schema_group(sdl, tsn, trav, cur_type); + schema_element(sdl, tsn, trav, cur_type, newModel); + } else if (node_is_equal(trav,"group")) { + schema_group(sdl, tsn, trav, cur_type, newModel); } else if (node_is_equal(trav,"choice")) { - /*FIXME*/ - schema_choice(sdl, tsn, trav, cur_type); + schema_choice(sdl, tsn, trav, cur_type, newModel); } else if (node_is_equal(trav,"sequence")) { - /*FIXME*/ - schema_sequence(sdl, tsn, trav, cur_type); + schema_sequence(sdl, tsn, trav, cur_type, newModel); } else if (node_is_equal(trav,"any")) { - /*FIXME*/ - schema_any(sdl, tsn, trav, cur_type); + schema_any(sdl, tsn, trav, cur_type, newModel); } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in sequence)",trav->name); } @@ -1040,7 +1218,7 @@ static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTy return TRUE; } -static int schema_any(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type) +static int schema_any(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr extType, sdlTypePtr cur_type, sdlContentModelPtr model) { /* TODO: support */ return TRUE; @@ -1153,11 +1331,6 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr compType, s cur_type = (*ptr); create_encoder(sdl, cur_type, ns->children->content, name->children->content); -/* - if (cur_type->encode == NULL) { - cur_type->encode = get_conversion(SOAP_ENC_OBJECT); - } -*/ } else { php_error(E_ERROR, "Error parsing schema (complexType has no 'name' attribute)"); return FALSE; @@ -1177,19 +1350,16 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr compType, s trav = trav->next; } else { if (node_is_equal(trav,"group")) { - schema_group(sdl, tsn, trav, cur_type); + schema_group(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"all")) { - cur_type->kind = XSD_TYPEKIND_ALL; - schema_all(sdl, tsn, trav, cur_type); + schema_all(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"choice")) { - cur_type->kind = XSD_TYPEKIND_CHOICE; - schema_choice(sdl, tsn, trav, cur_type); + schema_choice(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } else if (node_is_equal(trav,"sequence")) { - cur_type->kind = XSD_TYPEKIND_SEQUENCE; - schema_sequence(sdl, tsn, trav, cur_type); + schema_sequence(sdl, tsn, trav, cur_type, NULL); trav = trav->next; } while (trav != NULL) { @@ -1233,10 +1403,10 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr compType, s Content: (annotation?, ((simpleType | complexType)?, (unique | key | keyref)*)) */ -static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTypePtr cur_type) +static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTypePtr cur_type, sdlContentModelPtr model) { xmlNodePtr trav; - xmlAttrPtr attrs, curattr, ns, name, type, ref = NULL; + xmlAttrPtr attrs, attr, ns, name, type, ref = NULL; attrs = element->properties; ns = get_attribute(attrs, "targetNamespace"); @@ -1251,7 +1421,7 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp if (name) { HashTable *addHash; - sdlTypePtr newType, *tmp; + sdlTypePtr newType; smart_str key = {0}; newType = malloc(sizeof(sdlType)); @@ -1282,8 +1452,6 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp } newType->nillable = FALSE; - newType->min_occurs = 1; - newType->max_occurs = 1; if (cur_type == NULL) { addHash = sdl->elements; @@ -1300,33 +1468,46 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp } smart_str_0(&key); - zend_hash_update(addHash, key.c, key.len + 1, &newType, sizeof(sdlTypePtr), (void **)&tmp); - cur_type = (*tmp); + if (zend_hash_add(addHash, key.c, key.len + 1, &newType, sizeof(sdlTypePtr), NULL) != SUCCESS) { + php_error(E_ERROR, "Error parsing schema (element '%s' already defined)",key.c); + } smart_str_free(&key); - } else { - php_error(E_ERROR, "Error parsing schema (element has no 'name' nor 'ref' attributes)"); - } - curattr = get_attribute(attrs, "maxOccurs"); - if (curattr) { - if (!strcmp(curattr->children->content, "unbounded")) { - cur_type->max_occurs = -1; - } else { - cur_type->max_occurs = atoi(curattr->children->content); - } - } + if (model != NULL) { + sdlContentModelPtr newModel = malloc(sizeof(sdlContentModel)); + + newModel->kind = XSD_CONTENT_ELEMENT; + newModel->u.element = newType; + newModel->min_occurs = 1; + newModel->max_occurs = 1; - curattr = get_attribute(attrs, "minOccurs"); - if (curattr) { - cur_type->min_occurs = atoi(curattr->children->content); + attr = get_attribute(attrs, "maxOccurs"); + if (attr) { + if (!strcmp(attr->children->content, "unbounded")) { + newModel->max_occurs = -1; + } else { + newModel->max_occurs = atoi(attr->children->content); + } + } + + attr = get_attribute(attrs, "minOccurs"); + if (attr) { + newModel->min_occurs = atoi(attr->children->content); + } + + zend_hash_next_index_insert(model->u.content, &newModel, sizeof(sdlContentModelPtr), NULL); + } + cur_type = newType; + } else { + php_error(E_ERROR, "Error parsing schema (element has no 'name' nor 'ref' attributes)"); } /* nillable = boolean : false */ attrs = element->properties; - curattr = get_attribute(attrs, "nillable"); - if (curattr) { - if (!stricmp(curattr->children->content, "true") || - !stricmp(curattr->children->content, "1")) { + attr = get_attribute(attrs, "nillable"); + if (attr) { + if (!stricmp(attr->children->content, "true") || + !stricmp(attr->children->content, "1")) { cur_type->nillable = TRUE; } else { cur_type->nillable = FALSE; @@ -1353,12 +1534,6 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp if (cptype) {efree(cptype);} } -/* - if (cur_type->max_occurs == -1 || cur_type->max_occurs > 1) { - cur_type->encode = get_conversion(SOAP_ENC_ARRAY); - } -*/ - trav = element->children; if (trav != NULL && node_is_equal(trav, "annotation")) { /* TODO: support */ @@ -1474,12 +1649,32 @@ static int schema_attribute(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr attrType, sdl addHash = cur_type->attributes; } - zend_hash_update(addHash, key.c, key.len + 1, &newAttr, sizeof(sdlAttributePtr), NULL); + if (zend_hash_add(addHash, key.c, key.len + 1, &newAttr, sizeof(sdlAttributePtr), NULL) != SUCCESS) { + php_error(E_ERROR, "Error parsing schema (attribute '%s' already defined)", key.c); + } smart_str_free(&key); } else{ php_error(E_ERROR, "Error parsing schema (attribute has no 'name' nor 'ref' attributes)"); } + /* type = QName */ + type = get_attribute(attrType->properties, "type"); + if (type) { + char *cptype, *str_ns; + xmlNsPtr nsptr; + + if (ref != NULL) { + php_error(E_ERROR, "Error parsing schema (attribute have both 'ref' and 'type' attributes)"); + } + parse_namespace(type->children->content, &cptype, &str_ns); + nsptr = xmlSearchNs(attrType->doc, attrType, str_ns); + if (nsptr != NULL) { + newAttr->encode = get_create_encoder(sdl, cur_type, (char *)nsptr->href, (char *)cptype); + } + if (str_ns) {efree(str_ns);} + if (cptype) {efree(cptype);} + } + attr = attrType->properties; while (attr != NULL) { if (attr_is_equal_ex(attr, "default", SCHEMA_NAMESPACE)) { @@ -1493,10 +1688,9 @@ static int schema_attribute(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr attrType, sdl } else if (attr_is_equal_ex(attr, "name", SCHEMA_NAMESPACE)) { newAttr->name = strdup(attr->children->content); } else if (attr_is_equal_ex(attr, "ref", SCHEMA_NAMESPACE)) { - /*newAttr->ref= strdup(attr->children->content);*/ + /* already processed */ } else if (attr_is_equal_ex(attr, "type", SCHEMA_NAMESPACE)) { - type = attr; - newAttr->type = strdup(attr->children->content); + /* already processed */ } else if (attr_is_equal_ex(attr, "use", SCHEMA_NAMESPACE)) { newAttr->use = strdup(attr->children->content); } else { @@ -1528,13 +1722,19 @@ static int schema_attribute(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr attrType, sdl } if (trav != NULL) { if (node_is_equal(trav,"simpleType")) { + sdlTypePtr dummy_type; if (ref != NULL) { php_error(E_ERROR, "Error parsing schema (attribute have both 'ref' attribute and subtype)"); } else if (type != NULL) { php_error(E_ERROR, "Error parsing schema (attribute have both 'type' attribute and subtype)"); } - /*FIXME*/ - /*schema_simpleType(sdl, tsn, trav, cur_type);*/ + dummy_type = malloc(sizeof(sdlType)); + memset(dummy_type, 0, sizeof(sdlType)); + dummy_type->name = strdup("anonymous"); + dummy_type->namens = strdup(tsn->children->content); + schema_simpleType(sdl, tsn, trav, dummy_type); + newAttr->encode = dummy_type->encode; + delete_type(&dummy_type); trav = trav->next; } } @@ -1579,7 +1779,9 @@ static int schema_attributeGroup(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr attrGrou smart_str_appends(&key, newType->name); smart_str_0(&key); - zend_hash_update(sdl->attributeGroups, key.c, key.len + 1, &newType, sizeof(sdlTypePtr), NULL); + if (zend_hash_add(sdl->attributeGroups, key.c, key.len + 1, &newType, sizeof(sdlTypePtr), NULL) != SUCCESS) { + php_error(E_ERROR, "Error parsing schema (attributeGroup '%s' already defined)", key.c); + } cur_type = newType; smart_str_free(&key); } else if (ref) { @@ -1665,9 +1867,6 @@ static void schema_attribute_fixup(sdlPtr sdl, sdlAttributePtr attr) if ((*tmp)->form != NULL && attr->form == NULL) { attr->form = strdup((*tmp)->form); } - if ((*tmp)->type != NULL && attr->type == NULL) { - attr->type = strdup((*tmp)->type); - } if ((*tmp)->use != NULL && attr->use == NULL) { attr->use = strdup((*tmp)->use); } @@ -1679,6 +1878,7 @@ static void schema_attribute_fixup(sdlPtr sdl, sdlAttributePtr attr) zend_hash_init(attr->extraAttributes, 0, NULL, NULL, 1); zend_hash_copy(attr->extraAttributes, (*tmp)->extraAttributes, NULL, &node, sizeof(xmlNodePtr)); } + attr->encode = (*tmp)->encode; } } efree(attr->ref); @@ -1709,9 +1909,7 @@ static void schema_attributegroup_fixup(sdlPtr sdl, sdlAttributePtr attr, HashTa if (newAttr->def) {newAttr->def = strdup(newAttr->def);} if (newAttr->fixed) {newAttr->fixed = strdup(newAttr->fixed);} if (newAttr->form) {newAttr->form = strdup(newAttr->form);} - if (newAttr->name) {newAttr->fixed = strdup(newAttr->name);} if (newAttr->name) {newAttr->name = strdup(newAttr->name);} - if (newAttr->type) {newAttr->type = strdup(newAttr->type);} if (newAttr->use) {newAttr->use = strdup(newAttr->use);} if (newAttr->extraAttributes) { xmlNodePtr node; @@ -1742,6 +1940,39 @@ static void schema_attributegroup_fixup(sdlPtr sdl, sdlAttributePtr attr, HashTa } } +static void schema_content_model_fixup(sdlPtr sdl, sdlContentModelPtr model) +{ + switch (model->kind) { + case XSD_CONTENT_GROUP_REF: { + sdlTypePtr *tmp; + + if (sdl->groups && zend_hash_find(sdl->groups, model->u.group_ref, strlen(model->u.group_ref)+1, (void**)&tmp) == SUCCESS) { + schema_type_fixup(sdl,*tmp); + efree(model->u.group_ref); + model->kind = XSD_CONTENT_GROUP; + model->u.group = (*tmp)->model; + } else { + php_error(E_ERROR, "Error parsing schema (unresolved group 'ref' attribute)"); + } + break; + } + case XSD_CONTENT_SEQUENCE: + case XSD_CONTENT_ALL: + case XSD_CONTENT_CHOICE: { + sdlContentModelPtr *tmp; + + zend_hash_internal_pointer_reset(model->u.content); + while (zend_hash_get_current_data(model->u.content, (void**)&tmp) == SUCCESS) { + schema_content_model_fixup(sdl, *tmp); + zend_hash_move_forward(model->u.content); + } + break; + } + default: + break; + } +} + static void schema_type_fixup(sdlPtr sdl, sdlTypePtr type) { sdlTypePtr *tmp; @@ -1751,7 +1982,7 @@ static void schema_type_fixup(sdlPtr sdl, sdlTypePtr type) if (sdl->elements != NULL) { if (zend_hash_find(sdl->elements, type->ref, strlen(type->ref)+1, (void**)&tmp) == SUCCESS) { type->encode = (*tmp)->encode; - /* TODO: nillable minOccurs, maxOccurs */ + /* TODO: nillable */ } else { php_error(E_ERROR, "Error parsing schema (unresolved element 'ref' attribute)"); } @@ -1766,6 +1997,9 @@ static void schema_type_fixup(sdlPtr sdl, sdlTypePtr type) zend_hash_move_forward(type->elements); } } + if (type->model) { + schema_content_model_fixup(sdl, type->model); + } if (type->attributes) { zend_hash_internal_pointer_reset(type->attributes); while (zend_hash_get_current_data(type->attributes,(void**)&attr) == SUCCESS) { @@ -1809,6 +2043,13 @@ int schema_pass2(sdlPtr sdl) zend_hash_move_forward(sdl->elements); } } + if (sdl->groups) { + zend_hash_internal_pointer_reset(sdl->groups); + while (zend_hash_get_current_data(sdl->groups,(void**)&type) == SUCCESS) { + schema_type_fixup(sdl,*type); + zend_hash_move_forward(sdl->groups); + } + } if (sdl->types) { zend_hash_internal_pointer_reset(sdl->types); while (zend_hash_get_current_data(sdl->types,(void**)&type) == SUCCESS) { @@ -1818,3 +2059,43 @@ int schema_pass2(sdlPtr sdl) } return TRUE; } + +int schema_pass3(sdlPtr sdl) +{ + if (sdl->elements) { + zend_hash_destroy(sdl->elements); + free(sdl->elements); + sdl->elements = NULL; + } + if (sdl->attributes) { + zend_hash_destroy(sdl->attributes); + free(sdl->attributes); + sdl->attributes = NULL; + } + if (sdl->attributeGroups) { + zend_hash_destroy(sdl->attributeGroups); + free(sdl->attributeGroups); + sdl->attributeGroups = NULL; + } + return TRUE; +} + +static void delete_model(void *handle) +{ + sdlContentModelPtr tmp = *((sdlContentModelPtr*)handle); + switch (tmp->kind) { + case XSD_CONTENT_ELEMENT: + case XSD_CONTENT_GROUP: + break; + case XSD_CONTENT_SEQUENCE: + case XSD_CONTENT_ALL: + case XSD_CONTENT_CHOICE: + zend_hash_destroy(tmp->u.content); + free(tmp->u.content); + break; + case XSD_CONTENT_GROUP_REF: + efree(tmp->u.group_ref); + break; + } + free(tmp); +} diff --git a/ext/soap/php_schema.h b/ext/soap/php_schema.h index 74994485dd..c34b2e06f9 100644 --- a/ext/soap/php_schema.h +++ b/ext/soap/php_schema.h @@ -3,5 +3,6 @@ int load_schema(sdlPtr sdl, xmlNodePtr schema); int schema_pass2(sdlPtr sdl); +int schema_pass3(sdlPtr sdl); #endif diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index a014acfa34..a9696101e0 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -263,30 +263,33 @@ zval *sdl_guess_convert_zval(encodeType enc, xmlNodePtr data) php_error(E_WARNING,"Restriction: length is not equal to 'length'"); } } - if (type->encode) { - if (type->encode->details.type == IS_ARRAY || - type->encode->details.type == SOAP_ENC_ARRAY) { - return to_zval_array(enc, data); - } else if (type->encode->details.type == IS_OBJECT || - type->encode->details.type == SOAP_ENC_OBJECT) { - return to_zval_object(enc, data); - } else { - if (memcmp(&type->encode->details,&enc,sizeof(enc))!=0) { - return master_to_zval(type->encode, data); - } else { - TSRMLS_FETCH(); - return master_to_zval(get_conversion(UNKNOWN_TYPE), data); - } + if (type->kind == XSD_TYPEKIND_SIMPLE) { + if (type->encode && memcmp(&type->encode->details,&enc,sizeof(enc))!=0) { + return master_to_zval(type->encode, data); } } else if (type->kind == XSD_TYPEKIND_LIST) { return to_zval_list(enc, data); } else if (type->kind == XSD_TYPEKIND_UNION) { return to_zval_union(enc, data); - } else if (type->elements) { - return to_zval_object(enc, data); - } else { - return guess_zval_convert(enc, data); + } else if (type->kind == XSD_TYPEKIND_COMPLEX) { + if (type->encode && + (type->encode->details.type == IS_ARRAY || + type->encode->details.type == SOAP_ENC_ARRAY)) { + return to_zval_array(enc, data); + } + if (type->encode && + (type->encode->details.type == IS_OBJECT || + type->encode->details.type == SOAP_ENC_OBJECT)) { + return to_zval_array(enc, data); + } + if (type->model || type->attributes) { + return to_zval_object(enc, data); + } + if (type->encode && memcmp(&type->encode->details,&enc,sizeof(enc))!=0) { + return master_to_zval(type->encode, data); + } } + return guess_zval_convert(enc, data); } xmlNodePtr sdl_guess_convert_xml(encodeType enc, zval *data, int style) @@ -296,48 +299,51 @@ xmlNodePtr sdl_guess_convert_xml(encodeType enc, zval *data, int style) type = enc.sdl_type; - if (type && type->restrictions && Z_TYPE_P(data) == IS_STRING) { - if (type->restrictions->enumeration) { - if (!zend_hash_exists(type->restrictions->enumeration,Z_STRVAL_P(data),Z_STRLEN_P(data)+1)) { - php_error(E_WARNING,"Restriction: invalid enumeration value \"%s\".",Z_STRVAL_P(data)); + if (type) { + if (type->restrictions && Z_TYPE_P(data) == IS_STRING) { + if (type->restrictions->enumeration) { + if (!zend_hash_exists(type->restrictions->enumeration,Z_STRVAL_P(data),Z_STRLEN_P(data)+1)) { + php_error(E_WARNING,"Restriction: invalid enumeration value \"%s\".",Z_STRVAL_P(data)); + } + } + if (type->restrictions->minLength && + Z_STRLEN_P(data) < type->restrictions->minLength->value) { + php_error(E_WARNING,"Restriction: length less then 'minLength'"); + } + if (type->restrictions->maxLength && + Z_STRLEN_P(data) > type->restrictions->maxLength->value) { + php_error(E_WARNING,"Restriction: length greater then 'maxLength'"); + } + if (type->restrictions->length && + Z_STRLEN_P(data) != type->restrictions->length->value) { + php_error(E_WARNING,"Restriction: length is not equal to 'length'"); } - } - if (type->restrictions->minLength && - Z_STRLEN_P(data) < type->restrictions->minLength->value) { - php_error(E_WARNING,"Restriction: length less then 'minLength'"); - } - if (type->restrictions->maxLength && - Z_STRLEN_P(data) > type->restrictions->maxLength->value) { - php_error(E_WARNING,"Restriction: length greater then 'maxLength'"); - } - if (type->restrictions->length && - Z_STRLEN_P(data) != type->restrictions->length->value) { - php_error(E_WARNING,"Restriction: length is not equal to 'length'"); } } - - if (type->encode) { - if (type->encode->details.type == IS_ARRAY || - type->encode->details.type == SOAP_ENC_ARRAY) { - ret = to_xml_array(enc, data, style); - } else if (type->encode->details.type == IS_OBJECT || - type->encode->details.type == SOAP_ENC_OBJECT) { - ret = to_xml_object(enc, data, style); - } else { - if (memcmp(&type->encode->details,&enc,sizeof(enc))!=0) { - ret = master_to_xml(type->encode, data, style); - } else { - TSRMLS_FETCH(); - ret = master_to_xml(get_conversion(UNKNOWN_TYPE), data, style); - } + if (type->kind == XSD_TYPEKIND_SIMPLE) { + if (type->encode && memcmp(&type->encode->details,&enc,sizeof(enc))!=0) { + ret = master_to_xml(type->encode, data, style); } } else if (type->kind == XSD_TYPEKIND_LIST) { ret = to_xml_list(enc, data, style); } else if (type->kind == XSD_TYPEKIND_UNION) { ret = to_xml_union(enc, data, style); - } else if (type->elements) { - ret = to_xml_object(enc, data, style); - } else { + } else if (type->kind == XSD_TYPEKIND_COMPLEX) { + if (type->encode && + (type->encode->details.type == IS_ARRAY || + type->encode->details.type == SOAP_ENC_ARRAY)) { + ret = to_xml_array(enc, data, style); + } else if (type->encode && + (type->encode->details.type == IS_OBJECT || + type->encode->details.type == SOAP_ENC_OBJECT)) { + ret = to_xml_object(enc, data, style); + } else if (type->model || type->attributes) { + ret = to_xml_object(enc, data, style); + } else if (type->encode && memcmp(&type->encode->details,&enc,sizeof(enc))!=0) { + ret = master_to_xml(type->encode, data, style); + } + } + if (ret == NULL) { ret = guess_xml_convert(enc, data, style); } if (style == SOAP_ENCODED) { @@ -938,6 +944,7 @@ static sdlPtr load_wsdl(char *struri) php_error(E_ERROR, "Error parsing wsdl (\"Couldn't bind to service\")"); } + schema_pass3(ctx.root); zend_hash_destroy(&ctx.messages); zend_hash_destroy(&ctx.bindings); zend_hash_destroy(&ctx.portTypes); @@ -996,6 +1003,10 @@ void delete_sdl(void *handle) zend_hash_destroy(tmp->attributeGroups); free(tmp->attributeGroups); } + if (tmp->groups) { + zend_hash_destroy(tmp->groups); + free(tmp->groups); + } if (tmp->bindings) { zend_hash_destroy(tmp->bindings); free(tmp->bindings); @@ -1176,9 +1187,6 @@ void delete_attribute(void *attribute) if (attr->ref) { free(attr->ref); } - if (attr->type) { - free(attr->type); - } if (attr->use) { free(attr->use); } diff --git a/ext/soap/php_sdl.h b/ext/soap/php_sdl.h index fd072f27b5..68812cd0b5 100644 --- a/ext/soap/php_sdl.h +++ b/ext/soap/php_sdl.h @@ -24,6 +24,7 @@ struct _sdl { HashTable *requests; /* array of sdlFunction (references) */ HashTable *attributes; /* array of sdlAttributePtr */ HashTable *attributeGroups; /* array of sdlTypesPtr */ + HashTable *groups; /* array of sdlTypesPtr */ char *target_ns; char *source; }; @@ -44,8 +45,8 @@ struct _sdlSoapBinding { struct _sdlSoapBindingFunctionBody { char *ns; int use; - char *parts; /* not implemented yet */ - char *encodingStyle; /* not implemented yet */ + char *parts; /* not implemented yet */ + char *encodingStyle; /* not implemented yet */ }; struct _sdlSoapBindingFunction { @@ -57,14 +58,6 @@ struct _sdlSoapBindingFunction { sdlSoapBindingFunctionBody falut; }; -/* HTTP Binding Specfic stuff */ -/*********** not implemented yet ************ -struct _sdlHttpBinding -{ - int holder; -}; -*********************************************/ - struct _sdlRestrictionInt { int value; char fixed; @@ -78,7 +71,7 @@ struct _sdlRestrictionChar { }; struct _sdlRestrictions { - HashTable *enumeration; /* array of sdlRestrictionCharPtr */ + HashTable *enumeration; /* array of sdlRestrictionCharPtr */ sdlRestrictionIntPtr minExclusive; sdlRestrictionIntPtr minInclusive; sdlRestrictionIntPtr maxExclusive; @@ -92,15 +85,35 @@ struct _sdlRestrictions { sdlRestrictionCharPtr pattern; }; +typedef enum _sdlContentKind { + XSD_CONTENT_ELEMENT, + XSD_CONTENT_SEQUENCE, + XSD_CONTENT_ALL, + XSD_CONTENT_CHOICE, + XSD_CONTENT_GROUP_REF, + XSD_CONTENT_GROUP +} sdlContentKind; + + +typedef struct _sdlContentModel sdlContentModel, *sdlContentModelPtr; + +struct _sdlContentModel { + sdlContentKind kind; + int min_occurs; + int max_occurs; + union { + sdlTypePtr element; /* pointer to element */ + sdlContentModelPtr group; /* pointer to group */ + HashTable *content; /* array of sdlContentModel for sequnce,all,choice*/ + char *group_ref; /* reference to group */ + } u; +}; + typedef enum _sdlTypeKind { - XSD_TYPEKIND_UNKNOWN, XSD_TYPEKIND_SIMPLE, - XSD_TYPEKIND_COMPLEX, XSD_TYPEKIND_LIST, XSD_TYPEKIND_UNION, - XSD_TYPEKIND_ALL, - XSD_TYPEKIND_SEQUENCE, - XSD_TYPEKIND_CHOICE + XSD_TYPEKIND_COMPLEX } sdlTypeKind; struct _sdlType { @@ -108,13 +121,12 @@ struct _sdlType { char *name; char *namens; int nillable; - int min_occurs; - int max_occurs; - HashTable *elements; /* array of sdlTypePtr */ - HashTable *attributes; /* array of sdlAttributePtr */ + HashTable *elements; /* array of sdlTypePtr */ + HashTable *attributes; /* array of sdlAttributePtr */ sdlRestrictionsPtr restrictions; encodePtr encode; char *ref; + sdlContentModelPtr model; }; struct _sdlParam { @@ -127,10 +139,10 @@ struct _sdlFunction { char *functionName; char *requestName; char *responseName; - HashTable *requestParameters; /* array of sdlParamPtr */ - HashTable *responseParameters; /* array of sdlParamPtr (this should only be one) */ + HashTable *requestParameters; /* array of sdlParamPtr */ + HashTable *responseParameters; /* array of sdlParamPtr (this should only be one) */ struct _sdlBinding* binding; - void* bindingAttributes; /* sdlSoapBindingFunctionPtr */ + void* bindingAttributes; /* sdlSoapBindingFunctionPtr */ }; struct _sdlAttribute { @@ -140,9 +152,9 @@ struct _sdlAttribute { char *id; char *name; char *ref; - char *type; char *use; HashTable *extraAttributes; /* array of xmlNodePtr */ + encodePtr encode; }; sdlPtr get_sdl(char *uri); -- 2.50.1