From: Dmitry Stogov Date: Tue, 20 Jan 2004 16:30:38 +0000 (+0000) Subject: XML Schema support X-Git-Tag: php_ibase_before_split~76 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=67886b8321044d9ee04a4003206b9538bcc79219;p=php XML Schema support - support for 'ref' attibute was implemented - support for inline types - support for and (incompleate) --- diff --git a/ext/soap/TODO b/ext/soap/TODO index b8a27cfd37..9eb2d0d46a 100644 --- a/ext/soap/TODO +++ b/ext/soap/TODO @@ -100,7 +100,7 @@ Schema ------ - , , - support for user defined simple types - - restiction + ? restiction + base + enumeration + length (for string, anyURI, hexBinary, base64Binary and derived) @@ -114,8 +114,8 @@ Schema - maxInclusive (for numeric, date types) - totalDigits (for decimal) - fractionDigits (for decimal) - - list ??? - - union ??? + ? list + ? union - support for user defined complex types - simpleContent extension + base diff --git a/ext/soap/php_encoding.c b/ext/soap/php_encoding.c index 38d6114335..b4acf1001a 100644 --- a/ext/soap/php_encoding.c +++ b/ext/soap/php_encoding.c @@ -45,7 +45,6 @@ static int is_map(zval *array); static void get_array_type(xmlNodePtr node, zval *array, smart_str *out_type TSRMLS_DC); static void get_type_str(xmlNodePtr node, const char* ns, const char* type, smart_str* ret); -static void set_ns_and_type(xmlNodePtr node, encodeType type); static void set_ns_and_type_ex(xmlNodePtr node, char *ns, char *type); encode defaultEncoding[] = { @@ -179,6 +178,9 @@ xmlNodePtr master_to_xml(encodePtr encode, zval *data, int style) { xmlNodePtr node = NULL; + if (encode == NULL) { + encode = get_conversion(UNKNOWN_TYPE); + } if (encode->to_xml_before) { data = encode->to_xml_before(encode->details, data); } @@ -1598,7 +1600,7 @@ static xmlNodePtr to_xml_gmonth(encodeType type, zval *data, int style) return to_xml_datetime_ex(type, data, "--%m--", style); } -static void set_ns_and_type(xmlNodePtr node, encodeType type) +void set_ns_and_type(xmlNodePtr node, encodeType type) { set_ns_and_type_ex(node, type.ns, type.type_str); } @@ -1794,21 +1796,35 @@ static void get_type_str(xmlNodePtr node, const char* ns, const char* type, smar smart_str_appendl(ret, prefix, strlen(prefix)); smart_str_appendc(ret, ':'); } else if (node != NULL) { - smart_str* prefix = encode_new_ns(); - smart_str xmlns = {0}; + xmlAttrPtr attr = node->properties; - smart_str_appendl(&xmlns, "xmlns:", 6); - smart_str_append(&xmlns, prefix); - smart_str_0(&xmlns); + while (attr != NULL) { + if (strncmp(attr->name,"xmlns:",sizeof("xmlns:")-1) == 0 && + strcmp(attr->children->content,ns) == 0) { + break; + } + attr = attr->next; + } + if (attr == NULL) { + smart_str* prefix = encode_new_ns(); + smart_str xmlns = {0}; - xmlSetProp(node, xmlns.c, ns); + smart_str_appendl(&xmlns, "xmlns:", 6); + smart_str_append(&xmlns, prefix); + smart_str_0(&xmlns); - smart_str_append(ret, prefix); - smart_str_appendc(ret, ':'); + xmlSetProp(node, xmlns.c, ns); - smart_str_free(&xmlns); - smart_str_free(prefix); - efree(prefix); + smart_str_append(ret, prefix); + smart_str_appendc(ret, ':'); + + smart_str_free(&xmlns); + smart_str_free(prefix); + efree(prefix); + } else { + smart_str_appends(ret, attr->name + sizeof("xmlns:")-1); + smart_str_appendc(ret, ':'); + } } else { php_error(E_ERROR,"Unknown namespace '%s'",ns); } diff --git a/ext/soap/php_encoding.h b/ext/soap/php_encoding.h index 85b9989893..7b30f0a1fb 100644 --- a/ext/soap/php_encoding.h +++ b/ext/soap/php_encoding.h @@ -198,6 +198,7 @@ xmlNodePtr guess_xml_convert(encodeType type, zval *data, int style); void encode_reset_ns(); smart_str *encode_new_ns(); +void set_ns_and_type(xmlNodePtr node, encodeType type); encodePtr get_conversion_ex(HashTable *encoding, int encode); encodePtr get_conversion_from_type_ex(HashTable *encoding, xmlNodePtr node, const char *type); diff --git a/ext/soap/php_schema.c b/ext/soap/php_schema.c index bd42c64643..3ff2502b33 100644 --- a/ext/soap/php_schema.c +++ b/ext/soap/php_schema.c @@ -6,7 +6,7 @@ static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTy 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); -static int schema_restriction_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type); +static int schema_restriction_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type, int simpleType); 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); @@ -123,11 +123,44 @@ static int schema_simpleType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr simpleType, } name = get_attribute(simpleType->properties, "name"); - if (name != NULL) { + if (cur_type != NULL) { + /* Anonymous type inside or */ + sdlTypePtr newType, *ptr; + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + newType->kind = XSD_TYPEKIND_SIMPLE; + if (name != NULL) { + newType->name = strdup(name->children->content); + newType->namens = strdup(ns->children->content); + } else { + newType->name = strdup(cur_type->name); + newType->namens = strdup(cur_type->namens); + } + + zend_hash_next_index_insert(sdl->types, &newType, sizeof(sdlTypePtr), (void **)&ptr); + + if (sdl->encoders == NULL) { + sdl->encoders = malloc(sizeof(HashTable)); + zend_hash_init(sdl->encoders, 0, NULL, delete_encoder, 1); + } + cur_type->encode = malloc(sizeof(encode)); + memset(cur_type->encode, 0, sizeof(encode)); + cur_type->encode->details.ns = strdup(newType->namens); + cur_type->encode->details.type_str = strdup(newType->name); + cur_type->encode->details.sdl_type = *ptr; + cur_type->encode->to_xml = sdl_guess_convert_xml; + cur_type->encode->to_zval = sdl_guess_convert_zval; + zend_hash_next_index_insert(sdl->encoders, &cur_type->encode, sizeof(encodePtr), NULL); + + cur_type =*ptr; + + } else if (name != NULL) { sdlTypePtr newType, *ptr; newType = malloc(sizeof(sdlType)); memset(newType, 0, sizeof(sdlType)); + newType->kind = XSD_TYPEKIND_SIMPLE; newType->name = strdup(name->children->content); newType->namens = strdup(ns->children->content); @@ -143,17 +176,6 @@ static int schema_simpleType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr simpleType, cur_type = (*ptr); create_encoder(sdl, cur_type, ns->children->content, name->children->content); - } else if (cur_type != NULL) { - sdlTypePtr newType, *ptr; - - newType = malloc(sizeof(sdlType)); - memset(newType, 0, sizeof(sdlType)); - newType->name = strdup(cur_type->name); - newType->namens = strdup(cur_type->namens); - - zend_hash_next_index_insert(sdl->types, &newType, sizeof(sdlTypePtr), (void **)&ptr); - cur_type->encode = create_encoder(sdl, *ptr, (char *)(*ptr)->namens, (char *)(*ptr)->name); - cur_type =*ptr; } else { php_error(E_ERROR, "Error parsing schema (simpleType has no 'name' attribute)"); } @@ -171,17 +193,21 @@ static int schema_simpleType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr simpleType, } if (trav != NULL) { if (node_is_equal(trav,"restriction")) { - schema_restriction_simpleContent(sdl, tsn, trav, cur_type); + schema_restriction_simpleContent(sdl, tsn, trav, cur_type, 1); trav = trav->next; } else if (node_is_equal(trav,"list")) { + cur_type->kind = XSD_TYPEKIND_LIST; schema_list(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"union")) { + cur_type->kind = XSD_TYPEKIND_UNION; schema_union(sdl, tsn, trav, cur_type); trav = trav->next; } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in simpleType)",trav->name); } + } else { + php_error(E_ERROR, "Error parsing schema (expected , or in simpleType)"); } while (trav != NULL && trav->type != XML_ELEMENT_NODE) { trav = trav->next; @@ -208,7 +234,30 @@ static int schema_list(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr listType, sdlTypeP itemType = get_attribute(listType->properties, "itemType"); if (itemType != NULL) { - /*FIXME*/ + char *type, *ns; + xmlNsPtr nsptr; + + parse_namespace(itemType->children->content, &type, &ns); + nsptr = xmlSearchNs(listType->doc, listType, ns); + if (nsptr != NULL) { + sdlTypePtr newType, *tmp; + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + + newType->name = strdup(type); + newType->namens = strdup(nsptr->href); + + newType->encode = get_create_encoder(sdl, newType, (char *)nsptr->href, type); + + if (cur_type->elements == NULL) { + cur_type->elements = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); + } + zend_hash_next_index_insert(cur_type->elements, &newType, sizeof(sdlTypePtr), (void **)&tmp); + } + if (type) {efree(type);} + if (ns) {efree(ns);} } trav = listType->children; @@ -223,7 +272,25 @@ static int schema_list(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr listType, sdlTypeP trav = trav->next; } if (trav != NULL && node_is_equal(trav,"simpleType")) { - /*FIXME*/ + sdlTypePtr newType, *tmp; + + if (itemType != NULL) { + php_error(E_ERROR, "Error parsing schema (element have both 'itemType' attribute and subtype)"); + } + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + + newType->name = strdup("anonymous"); + newType->namens = strdup(tsn->children->content); + + if (cur_type->elements == NULL) { + cur_type->elements = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); + } + zend_hash_next_index_insert(cur_type->elements, &newType, sizeof(sdlTypePtr), (void **)&tmp); + + schema_simpleType(sdl, tsn, trav, newType); trav = trav->next; } while (trav != NULL && trav->type != XML_ELEMENT_NODE) { @@ -246,11 +313,51 @@ static int schema_list(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr listType, sdlTypeP static int schema_union(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr unionType, sdlTypePtr cur_type) { xmlNodePtr trav; - xmlAttrPtr itemType; + xmlAttrPtr memberTypes; - itemType = get_attribute(unionType->properties, "memberTypes"); - if (itemType != NULL) { - /*FIXME*/ + memberTypes = get_attribute(unionType->properties, "memberTypes"); + if (memberTypes != NULL) { + char *str, *start, *end, *next; + char *type, *ns; + xmlNsPtr nsptr; + + str = estrdup(memberTypes->children->content); + whiteSpace_collapse(str); + start = str; + while (start != NULL && *start != '\0') { + end = strchr(start,' '); + if (end == NULL) { + next = NULL; + } else { + *end = '\0'; + next = end+1; + } + + parse_namespace(start, &type, &ns); + nsptr = xmlSearchNs(unionType->doc, unionType, ns); + if (nsptr != NULL) { + sdlTypePtr newType, *tmp; + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + + newType->name = strdup(type); + newType->namens = strdup(nsptr->href); + + newType->encode = get_create_encoder(sdl, newType, (char *)nsptr->href, type); + + if (cur_type->elements == NULL) { + cur_type->elements = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); + } + zend_hash_next_index_insert(cur_type->elements, &newType, sizeof(sdlTypePtr), (void **)&tmp); + } + if (type) {efree(type);} + if (ns) {efree(ns);} + + start = next; + } + efree(str); } trav = unionType->children; @@ -264,7 +371,26 @@ static int schema_union(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr unionType, sdlTyp while (trav != NULL) { if (trav->type == XML_ELEMENT_NODE) { if (node_is_equal(trav,"simpleType")) { - /*FIXME*/ + sdlTypePtr newType, *tmp; + + if (memberTypes != NULL) { + php_error(E_ERROR, "Error parsing schema (union have both 'memberTypes' attribute and subtypes)"); + } + + newType = malloc(sizeof(sdlType)); + memset(newType, 0, sizeof(sdlType)); + + newType->name = strdup("anonymous"); + newType->namens = strdup(tsn->children->content); + + if (cur_type->elements == NULL) { + cur_type->elements = malloc(sizeof(HashTable)); + zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); + } + zend_hash_next_index_insert(cur_type->elements, &newType, sizeof(sdlTypePtr), (void **)&tmp); + + schema_simpleType(sdl, tsn, trav, newType); + } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in union)",trav->name); } @@ -304,7 +430,7 @@ static int schema_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr simpCompT } if (trav != NULL) { if (node_is_equal(trav, "restriction")) { - schema_restriction_simpleContent(sdl, tsn, trav, cur_type); + schema_restriction_simpleContent(sdl, tsn, trav, cur_type, 0); trav = trav->next; } else if (node_is_equal(trav, "extension")) { schema_extension_simpleContent(sdl, tsn, trav, cur_type); @@ -326,14 +452,20 @@ static int schema_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr simpCompT } /* - + Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)?) + +simpleContent: Content: (annotation?, (simpleType?, (minExclusive | minInclusive | maxExclusive | maxInclusive | totalDigits | fractionDigits | length | minLength | maxLength | enumeration | whiteSpace | pattern)*)?, ((attribute | attributeGroup)*, anyAttribute?)) */ -static int schema_restriction_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type) +static int schema_restriction_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr restType, sdlTypePtr cur_type, int simpleType) { xmlNodePtr trav; xmlAttrPtr base; @@ -350,6 +482,8 @@ static int schema_restriction_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodeP } if (type) {efree(type);} if (ns) {efree(ns);} + } else if (!simpleType) { + php_error(E_ERROR, "Error parsing schema (restriction has no 'base' attribute)"); } if (cur_type->restrictions == NULL) { @@ -411,21 +545,23 @@ static int schema_restriction_simpleContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodeP } trav = trav->next; } - while (trav != NULL) { - if (trav->type == XML_ELEMENT_NODE) { - if (node_is_equal(trav,"attribute")) { - schema_attribute(sdl, tsn, trav, cur_type); - } else if (node_is_equal(trav,"attributeGroup")) { - schema_attributeGroupRef(sdl, tsn, trav, cur_type); - } else if (node_is_equal(trav,"anyAttribute")) { - /* TODO: support */ - trav = trav->next; - break; - } else { - php_error(E_ERROR, "Error parsing schema (unexpected <%s> in restriction)",trav->name); + if (!simpleType) { + while (trav != NULL) { + if (trav->type == XML_ELEMENT_NODE) { + if (node_is_equal(trav,"attribute")) { + schema_attribute(sdl, tsn, trav, cur_type); + } else if (node_is_equal(trav,"attributeGroup")) { + schema_attributeGroupRef(sdl, tsn, trav, cur_type); + } else if (node_is_equal(trav,"anyAttribute")) { + /* TODO: support */ + trav = trav->next; + break; + } else { + php_error(E_ERROR, "Error parsing schema (unexpected <%s> in restriction)",trav->name); + } } + trav = trav->next; } - trav = trav->next; } while (trav != NULL && trav->type != XML_ELEMENT_NODE) { trav = trav->next; @@ -482,11 +618,14 @@ static int schema_restriction_complexContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNode schema_group(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"all")) { + cur_type->kind = XSD_TYPEKIND_ALL; schema_all(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"choice")) { + cur_type->kind = XSD_TYPEKIND_CHOICE; schema_choice(sdl, tsn, trav, cur_type); trav = trav->next; + cur_type->kind = XSD_TYPEKIND_SEQUENCE; } else if (node_is_equal(trav,"sequence")) { schema_sequence(sdl, tsn, trav, cur_type); trav = trav->next; @@ -673,12 +812,15 @@ static int schema_extension_complexContent(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePt schema_group(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"all")) { + cur_type->kind = XSD_TYPEKIND_ALL; schema_all(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"choice")) { + cur_type->kind = XSD_TYPEKIND_CHOICE; schema_choice(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"sequence")) { + cur_type->kind = XSD_TYPEKIND_SEQUENCE; schema_sequence(sdl, tsn, trav, cur_type); trav = trav->next; } @@ -772,20 +914,29 @@ static int schema_group(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr groupType, sdlTyp while (trav != NULL && trav->type != XML_ELEMENT_NODE) { trav = trav->next; } - while (trav != NULL) { - if (trav->type == XML_ELEMENT_NODE) { - if (node_is_equal(trav,"choice")) { - schema_choice(sdl, tsn, trav, cur_type); - } else if (node_is_equal(trav,"sequence")) { - schema_sequence(sdl, tsn, trav, cur_type); - } else if (node_is_equal(trav,"all")) { - schema_all(sdl, tsn, trav, cur_type); - } else { - php_error(E_ERROR, "Error parsing schema (unexpected <%s> in group)",trav->name); - } + if (trav != NULL) { + if (node_is_equal(trav,"choice")) { + cur_type->kind = XSD_TYPEKIND_CHOICE; + schema_choice(sdl, tsn, trav, cur_type); + trav = trav->next; + } else if (node_is_equal(trav,"sequence")) { + cur_type->kind = XSD_TYPEKIND_SEQUENCE; + schema_sequence(sdl, tsn, trav, cur_type); + trav = trav->next; + } else if (node_is_equal(trav,"all")) { + cur_type->kind = XSD_TYPEKIND_ALL; + schema_all(sdl, tsn, trav, cur_type); + trav = trav->next; + } else { + php_error(E_ERROR, "Error parsing schema (unexpected <%s> in group)",trav->name); } + } + while (trav != NULL && trav->type != XML_ELEMENT_NODE) { trav = trav->next; } + if (trav != NULL) { + php_error(E_ERROR, "Error parsing schema (unexpected <%s> in group)",trav->name); + } return TRUE; } /* @@ -821,12 +972,16 @@ static int schema_choice(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr choiceType, sdlT 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); } else if (node_is_equal(trav,"choice")) { + /*FIXME*/ schema_choice(sdl, tsn, trav, cur_type); } else if (node_is_equal(trav,"sequence")) { + /*FIXME*/ schema_sequence(sdl, tsn, trav, cur_type); } else if (node_is_equal(trav,"any")) { + /*FIXME*/ schema_any(sdl, tsn, trav, cur_type); } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in choice)",trav->name); @@ -866,12 +1021,16 @@ static int schema_sequence(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr seqType, sdlTy 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); } else if (node_is_equal(trav,"choice")) { + /*FIXME*/ schema_choice(sdl, tsn, trav, cur_type); } else if (node_is_equal(trav,"sequence")) { + /*FIXME*/ schema_sequence(sdl, tsn, trav, cur_type); } else if (node_is_equal(trav,"any")) { + /*FIXME*/ schema_any(sdl, tsn, trav, cur_type); } else { php_error(E_ERROR, "Error parsing schema (unexpected <%s> in sequence)",trav->name); @@ -959,42 +1118,59 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr compType, s } name = get_attribute(attrs, "name"); - if (name) { + if (cur_type != NULL) { + /* Anonymous type inside */ sdlTypePtr newType, *ptr; newType = malloc(sizeof(sdlType)); memset(newType, 0, sizeof(sdlType)); - newType->name = strdup(name->children->content); - newType->namens = strdup(ns->children->content); - - if (cur_type == NULL) { - zend_hash_next_index_insert(sdl->types, &newType, sizeof(sdlTypePtr), (void **)&ptr); + newType->kind = XSD_TYPEKIND_COMPLEX; + if (name != NULL) { + newType->name = strdup(name->children->content); + newType->namens = strdup(ns->children->content); } else { - if (cur_type->elements == NULL) { - cur_type->elements = malloc(sizeof(HashTable)); - zend_hash_init(cur_type->elements, 0, NULL, delete_type, 1); - } - zend_hash_update(cur_type->elements, newType->name, strlen(newType->name) + 1, &newType, sizeof(sdlTypePtr), (void **)&ptr); + newType->name = strdup(cur_type->name); + newType->namens = strdup(cur_type->namens); } - 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); + zend_hash_next_index_insert(sdl->types, &newType, sizeof(sdlTypePtr), (void **)&ptr); + + if (sdl->encoders == NULL) { + sdl->encoders = malloc(sizeof(HashTable)); + zend_hash_init(sdl->encoders, 0, NULL, delete_encoder, 1); } - } else if (cur_type != NULL) { + cur_type->encode = malloc(sizeof(encode)); + memset(cur_type->encode, 0, sizeof(encode)); + cur_type->encode->details.ns = strdup(newType->namens); + cur_type->encode->details.type_str = strdup(newType->name); + cur_type->encode->details.sdl_type = *ptr; + cur_type->encode->to_xml = sdl_guess_convert_xml; + cur_type->encode->to_zval = sdl_guess_convert_zval; + zend_hash_next_index_insert(sdl->encoders, &cur_type->encode, sizeof(encodePtr), NULL); + + cur_type =*ptr; + + } else if (name) { sdlTypePtr newType, *ptr; newType = malloc(sizeof(sdlType)); memset(newType, 0, sizeof(sdlType)); - newType->name = strdup(cur_type->name); - newType->namens = strdup(cur_type->namens); + newType->kind = XSD_TYPEKIND_COMPLEX; + newType->name = strdup(name->children->content); + newType->namens = strdup(ns->children->content); zend_hash_next_index_insert(sdl->types, &newType, sizeof(sdlTypePtr), (void **)&ptr); - cur_type->encode = create_encoder(sdl, *ptr, (char *)(*ptr)->namens, (char *)(*ptr)->name); - cur_type =*ptr; + + 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; } trav = compType->children; @@ -1020,12 +1196,15 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr compType, s schema_group(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"all")) { + cur_type->kind = XSD_TYPEKIND_ALL; schema_all(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"choice")) { + cur_type->kind = XSD_TYPEKIND_CHOICE; schema_choice(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"sequence")) { + cur_type->kind = XSD_TYPEKIND_SEQUENCE; schema_sequence(sdl, tsn, trav, cur_type); trav = trav->next; } @@ -1078,7 +1257,7 @@ static int schema_complexType(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr compType, s static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTypePtr cur_type) { xmlNodePtr trav; - xmlAttrPtr attrs, curattr, name, ns, type; + xmlAttrPtr attrs, curattr, ns, name, type, ref = NULL; attrs = element->properties; ns = get_attribute(attrs, "targetNamespace"); @@ -1087,8 +1266,8 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp } name = get_attribute(attrs, "name"); - if (!name) { - name = get_attribute(attrs, "ref"); + if (name == NULL) { + name = ref = get_attribute(attrs, "ref"); } if (name) { @@ -1099,8 +1278,30 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp newType = malloc(sizeof(sdlType)); memset(newType, 0, sizeof(sdlType)); - newType->name = strdup(name->children->content); - newType->namens = strdup(tsn->children->content); + if (ref) { + smart_str nscat = {0}; + char *type, *ns; + xmlNsPtr nsptr; + + parse_namespace(ref->children->content, &type, &ns); + nsptr = xmlSearchNs(element->doc, element, ns); + if (nsptr != NULL) { + smart_str_appends(&nscat, nsptr->href); + smart_str_appendc(&nscat, ':'); + newType->namens = strdup(nsptr->href); + } + smart_str_appends(&nscat, type); + newType->name = strdup(type); + smart_str_0(&nscat); + if (type) {efree(type);} + if (ns) {efree(ns);} + newType->ref = estrdup(nscat.c); + smart_str_free(&nscat); + } else { + newType->name = strdup(name->children->content); + newType->namens = strdup(ns->children->content); + } + newType->nillable = FALSE; newType->min_occurs = 1; newType->max_occurs = 1; @@ -1122,9 +1323,6 @@ 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); -/* - create_encoder(sdl, cur_type, ns->children->content, name->children->content); -*/ smart_str_free(&key); } else { php_error(E_ERROR, "Error parsing schema (element has no 'name' nor 'ref' attributes)"); @@ -1160,15 +1358,13 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp /* type = QName */ type = get_attribute(attrs, "type"); -/* - if (!curattr) { - curattr = name; - } -*/ if (type) { char *cptype, *str_ns; xmlNsPtr nsptr; + if (ref != NULL) { + php_error(E_ERROR, "Error parsing schema (element have both 'ref' and 'type' attributes)"); + } parse_namespace(type->children->content, &cptype, &str_ns); nsptr = xmlSearchNs(element->doc, element, str_ns); if (nsptr != NULL) { @@ -1190,9 +1386,19 @@ static int schema_element(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr element, sdlTyp } if (trav != NULL) { if (node_is_equal(trav,"simpleType")) { + if (ref != NULL) { + php_error(E_ERROR, "Error parsing schema (element have both 'ref' attribute and subtype)"); + } else if (type != NULL) { + php_error(E_ERROR, "Error parsing schema (element have both 'type' attribute and subtype)"); + } schema_simpleType(sdl, tsn, trav, cur_type); trav = trav->next; } else if (node_is_equal(trav,"complexType")) { + if (ref != NULL) { + php_error(E_ERROR, "Error parsing schema (element have both 'ref' attribute and subtype)"); + } else if (type != NULL) { + php_error(E_ERROR, "Error parsing schema (element have both 'type' attribute and subtype)"); + } schema_complexType(sdl, tsn, trav, cur_type); trav = trav->next; } @@ -1373,3 +1579,47 @@ static int schema_attributeGroupRef(sdlPtr sdl, xmlAttrPtr tsn, xmlNodePtr attrG } return TRUE; } + +static void schema_type_fixup(sdlPtr sdl, sdlTypePtr type) +{ + sdlTypePtr *tmp; + + if (type->ref != NULL) { + if (zend_hash_find(sdl->elements, type->ref, strlen(type->ref)+1, (void**)&tmp) == SUCCESS) { + type->encode = (*tmp)->encode; + /* TODO: nillable minOccurs, maxOccurs */ + } else { + php_error(E_ERROR, "Error parsing schema (unresolved element 'ref' attribute)"); + } + efree(type->ref); + type->ref = NULL; + } + if (type->elements) { + zend_hash_internal_pointer_reset(type->elements); + while (zend_hash_get_current_data(type->elements,(void**)&tmp) == SUCCESS) { + schema_type_fixup(sdl,*tmp); + zend_hash_move_forward(type->elements); + } + } +} + +int schema_pass2(sdlPtr sdl) +{ + sdlTypePtr *type; + + if (sdl->elements) { + zend_hash_internal_pointer_reset(sdl->elements); + while (zend_hash_get_current_data(sdl->elements,(void**)&type) == SUCCESS) { + schema_type_fixup(sdl,*type); + zend_hash_move_forward(sdl->elements); + } + } + if (sdl->types) { + zend_hash_internal_pointer_reset(sdl->types); + while (zend_hash_get_current_data(sdl->types,(void**)&type) == SUCCESS) { + schema_type_fixup(sdl,*type); + zend_hash_move_forward(sdl->types); + } + } + return TRUE; +} diff --git a/ext/soap/php_schema.h b/ext/soap/php_schema.h index ed7a9d8e78..74994485dd 100644 --- a/ext/soap/php_schema.h +++ b/ext/soap/php_schema.h @@ -2,5 +2,6 @@ #define PHP_SCHEMA_H int load_schema(sdlPtr sdl, xmlNodePtr schema); +int schema_pass2(sdlPtr sdl); #endif diff --git a/ext/soap/php_sdl.c b/ext/soap/php_sdl.c index 7f33427e8f..4d727b3e67 100644 --- a/ext/soap/php_sdl.c +++ b/ext/soap/php_sdl.c @@ -28,7 +28,7 @@ encodePtr get_encoder_from_prefix(sdlPtr sdl, xmlNodePtr data, const char *type) return enc; } -encodePtr get_encoder_from_element(sdlPtr sdl, xmlNodePtr node, const char *type) +static encodePtr get_encoder_from_element(sdlPtr sdl, xmlNodePtr node, const char *type) { encodePtr enc = NULL; TSRMLS_FETCH(); @@ -161,6 +161,75 @@ encodePtr create_encoder(sdlPtr sdl, sdlTypePtr cur_type, const char *ns, const return enc; } +static zval* to_zval_list(encodeType enc, xmlNodePtr data) { + zval *ret; + MAKE_STD_ZVAL(ret); + FIND_XML_NULL(data, ret); + if (data && data->children) { + if (data->children->type == XML_TEXT_NODE && data->children->next == NULL) { + whiteSpace_collapse(data->children->content); + ZVAL_STRING(ret, data->children->content, 1); + } else { + php_error(E_ERROR,"Violation of encoding rules"); + } + } else { + ZVAL_EMPTY_STRING(ret); + } + return ret; +} + +static xmlNodePtr to_xml_list(encodeType enc, zval *data, int style) { + xmlNodePtr ret; + + ret = xmlNewNode(NULL, "BOGUS"); + FIND_ZVAL_NULL(data, ret, style); + if (Z_TYPE_P(data) == IS_ARRAY) { + zval **tmp; + smart_str list = {0}; + HashTable *ht = Z_ARRVAL_P(data); + + zend_hash_internal_pointer_reset(ht); + while (zend_hash_get_current_data(ht, (void**)&tmp) == SUCCESS) { + if (list.len != 0) { + smart_str_appendc(&list, ' '); + } + if (Z_TYPE_PP(tmp) == IS_STRING) { + smart_str_appendl(&list, Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); + } else { + zval copy = **tmp; + zval_copy_ctor(©); + convert_to_string(©); + smart_str_appendl(&list, Z_STRVAL(copy), Z_STRLEN(copy)); + zval_dtor(©); + } + zend_hash_move_forward(ht); + } + smart_str_0(&list); + xmlNodeSetContentLen(ret, list.c, list.len); + smart_str_free(&list); + } else if (Z_TYPE_P(data) == IS_STRING) { + xmlNodeSetContentLen(ret, Z_STRVAL_P(data), Z_STRLEN_P(data)); + } else { + zval tmp = *data; + + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + xmlNodeSetContentLen(ret, Z_STRVAL(tmp), Z_STRLEN(tmp)); + zval_dtor(&tmp); + } + return ret; +} + +static zval* to_zval_union(encodeType enc, xmlNodePtr data) { + /*FIXME*/ + return to_zval_list(enc, data); +} + +static xmlNodePtr to_xml_union(encodeType enc, zval *data, int style) { + /*FIXME*/ + return to_xml_list(enc,data,style); +} + zval *sdl_guess_convert_zval(encodeType enc, xmlNodePtr data) { sdlTypePtr type; @@ -209,6 +278,10 @@ zval *sdl_guess_convert_zval(encodeType enc, xmlNodePtr data) return master_to_zval(get_conversion(UNKNOWN_TYPE), 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 { @@ -258,12 +331,18 @@ xmlNodePtr sdl_guess_convert_xml(encodeType enc, zval *data, int style) ret = master_to_xml(get_conversion(UNKNOWN_TYPE), data, style); } } - } - else if (type->elements) { + } 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 { ret = guess_xml_convert(enc, data, style); } + if (style == SOAP_ENCODED) { + set_ns_and_type(ret, enc); + } return ret; } @@ -428,6 +507,8 @@ static sdlPtr load_wsdl(char *struri) load_wsdl_ex(struri,&ctx, 0); + schema_pass2(ctx.root); + n = zend_hash_num_elements(&ctx.services); if (n > 0) { zend_hash_internal_pointer_reset(&ctx.services); @@ -688,6 +769,7 @@ static sdlPtr load_wsdl(char *struri) sdlParamPtr param; param = malloc(sizeof(sdlParam)); + memset(param,0,sizeof(sdlParam)); param->order = 0; name = get_attribute(part->properties, "name"); @@ -783,6 +865,7 @@ static sdlPtr load_wsdl(char *struri) xmlAttrPtr element, type, name; param = malloc(sizeof(sdlParam)); + memset(param, 0, sizeof(sdlParam)); param->order = 0; name = get_attribute(part->properties, "name"); diff --git a/ext/soap/php_sdl.h b/ext/soap/php_sdl.h index 06c0a83274..ae6a90be6b 100644 --- a/ext/soap/php_sdl.h +++ b/ext/soap/php_sdl.h @@ -90,7 +90,19 @@ struct _sdlRestrictions { sdlRestrictionCharPtr pattern; }; +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 +} sdlTypeKind; + struct _sdlType { + sdlTypeKind kind; char *name; char *namens; int nillable; @@ -100,6 +112,7 @@ struct _sdlType { HashTable *attributes; /* array of sdlAttributePtr */ sdlRestrictionsPtr restrictions; encodePtr encode; + char *ref; }; struct _sdlParam { diff --git a/ext/soap/soap.c b/ext/soap/soap.c index b7b060fcd7..f69c131b77 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -1200,7 +1200,6 @@ PHP_METHOD(soapserver, handle) zval_dtor(&function_name); xmlFreeDoc(doc_return); - efree(fn_name); php_write(buf, size TSRMLS_CC); xmlFree(buf); @@ -1981,7 +1980,11 @@ static xmlDocPtr seralize_response_call(sdlFunctionPtr function, char *function_ } if (function != NULL) { - param_count = zend_hash_num_elements(function->responseParameters); + if (function->responseParameters) { + param_count = zend_hash_num_elements(function->responseParameters); + } else { + param_count = 0; + } } else { param_count = 1; } @@ -2219,9 +2222,8 @@ static xmlNodePtr seralize_zval(zval *val, sdlParamPtr param, char *paramName, i if (param != NULL) { enc = param->encode; } else { - enc = get_conversion(val->type); + enc = get_conversion(val->type); } - xmlParam = master_to_xml(enc, val, style); if (!strcmp(xmlParam->name, "BOGUS")) { xmlNodeSetName(xmlParam, paramName);