| /* | |
| * XDR (XML-Data Reduced) -> XSD (XML Schema Document) conversion | |
| * | |
| * Copyright 2010 Adam Martinson for CodeWeavers | |
| * | |
| * This library is free software; you can redistribute it and/or | |
| * modify it under the terms of the GNU Lesser General Public | |
| * License as published by the Free Software Foundation; either | |
| * version 2.1 of the License, or (at your option) any later version. | |
| * | |
| * This library is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
| * Lesser General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Lesser General Public | |
| * License along with this library; if not, write to the Free Software | |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |
| */ | |
| #include "config.h" | |
| #include <assert.h> | |
| #ifdef HAVE_LIBXML2 | |
| # include <libxml/tree.h> | |
| #endif | |
| #include "wine/debug.h" | |
| /* Both XDR and XSD are valid XML | |
| * We just convert the doc tree, no need for a parser. | |
| */ | |
| #ifdef HAVE_LIBXML2 | |
| WINE_DEFAULT_DEBUG_CHANNEL(msxml); | |
| static const xmlChar DT_prefix[] = "dt"; | |
| static const xmlChar DT_href[] = "urn:schemas-microsoft-com:datatypes"; | |
| static const xmlChar XDR_href[] = "urn:schemas-microsoft-com:xml-data"; | |
| static const xmlChar XSD_prefix[] = "xsd"; | |
| static const xmlChar XSD_href[] = "http://www.w3.org/2001/XMLSchema"; | |
| static const xmlChar xs_all[] = "all"; | |
| static const xmlChar xs_annotation[] = "annotation"; | |
| static const xmlChar xs_any[] = "any"; | |
| static const xmlChar xs_anyAttribute[] = "anyAttribute"; | |
| static const xmlChar xs_attribute[] = "attribute"; | |
| static const xmlChar xs_AttributeType[] = "AttributeType"; | |
| static const xmlChar xs_base[] = "base"; | |
| static const xmlChar xs_choice[] = "choice"; | |
| static const xmlChar xs_complexType[] = "complexType"; | |
| static const xmlChar xs_content[] = "content"; | |
| static const xmlChar xs_datatype[] = "datatype"; | |
| static const xmlChar xs_default[] = "default"; | |
| static const xmlChar xs_description[] = "description"; | |
| static const xmlChar xs_documentation[] = "documentation"; | |
| static const xmlChar xs_element[] = "element"; | |
| static const xmlChar xs_ElementType[] = "ElementType"; | |
| static const xmlChar xs_eltOnly[] = "eltOnly"; | |
| static const xmlChar xs_enumeration[] = "enumeration"; | |
| static const xmlChar xs_extension[] = "extension"; | |
| static const xmlChar xs_group[] = "group"; | |
| static const xmlChar xs_lax[] = "lax"; | |
| static const xmlChar xs_length[] = "length"; | |
| static const xmlChar xs_many[] = "many"; | |
| static const xmlChar xs_maxOccurs[] = "maxOccurs"; | |
| static const xmlChar xs_minOccurs[] = "minOccurs"; | |
| static const xmlChar xs_mixed[] = "mixed"; | |
| static const xmlChar xs_model[] = "model"; | |
| static const xmlChar xs_name[] = "name"; | |
| static const xmlChar xs_namespace[] = "namespace"; | |
| static const xmlChar xs_no[] = "no"; | |
| static const xmlChar xs_open[] = "open"; | |
| static const xmlChar xs_optional[] = "optional"; | |
| static const xmlChar xs_order[] = "order"; | |
| static const xmlChar xs_processContents[] = "processContents"; | |
| static const xmlChar xs_ref[] = "ref"; | |
| static const xmlChar xs_required[] = "required"; | |
| static const xmlChar xs_restriction[] = "restriction"; | |
| static const xmlChar xs_schema[] = "schema"; | |
| static const xmlChar xs_seq[] = "seq"; | |
| static const xmlChar xs_sequence[] = "sequence"; | |
| static const xmlChar xs_simpleContent[] = "simpleContent"; | |
| static const xmlChar xs_simpleType[] = "simpleType"; | |
| static const xmlChar xs_strict[] = "strict"; | |
| static const xmlChar xs_targetNamespace[] = "targetNamespace"; | |
| static const xmlChar xs_textOnly[] = "textOnly"; | |
| static const xmlChar xs_true[] = "true"; | |
| static const xmlChar xs_type[] = "type"; | |
| static const xmlChar xs_unbounded[] = "unbounded"; | |
| static const xmlChar xs_use[] = "use"; | |
| static const xmlChar xs_value[] = "value"; | |
| static const xmlChar xs_values[] = "values"; | |
| static const xmlChar xs_xsd_string[] = "xsd:string"; | |
| typedef enum _CONTENT_TYPE | |
| { | |
| CONTENT_EMPTY, | |
| CONTENT_TEXTONLY, | |
| CONTENT_ELTONLY, | |
| CONTENT_MIXED | |
| } CONTENT_TYPE; | |
| typedef enum _ORDER_TYPE | |
| { | |
| ORDER_SEQ, | |
| ORDER_MANY, | |
| ORDER_ONE | |
| } ORDER_TYPE; | |
| #define FOREACH_CHILD(node, child) \ | |
| for (child = node->children; child != NULL; child = child->next) \ | |
| if (child->type == XML_ELEMENT_NODE) | |
| #define FOREACH_ATTR(node, attr) \ | |
| for (attr = node->properties; attr != NULL; attr = attr->next) | |
| #define FOREACH_NS(node, ns) \ | |
| for (ns = node->nsDef; ns != NULL; ns = ns->next) | |
| static inline xmlNodePtr get_schema(xmlNodePtr node) | |
| { | |
| return xmlDocGetRootElement(node->doc); | |
| } | |
| static inline xmlNodePtr get_child(xmlNodePtr node, xmlChar const* name) | |
| { | |
| xmlNodePtr child = NULL; | |
| if (node) | |
| { | |
| FOREACH_CHILD(node, child) | |
| { | |
| if (xmlStrEqual(child->name, name)) | |
| break; | |
| } | |
| } | |
| return child; | |
| } | |
| static inline xmlNodePtr get_child_with_attr(xmlNodePtr node, xmlChar const* name, | |
| xmlChar const* attr_ns, xmlChar const* attr_name, | |
| xmlChar const* attr_val) | |
| { | |
| xmlChar* str; | |
| if (node) | |
| { | |
| FOREACH_CHILD(node, node) | |
| { | |
| if (xmlStrEqual(node->name, name)) | |
| { | |
| str = (attr_ns != NULL)? xmlGetNsProp(node, attr_name, attr_ns) : | |
| xmlGetProp(node, attr_name); | |
| if (str) | |
| { | |
| if (xmlStrEqual(str, attr_val)) | |
| { | |
| xmlFree(str); | |
| return node; | |
| } | |
| xmlFree(str); | |
| } | |
| } | |
| } | |
| } | |
| return NULL; | |
| } | |
| static inline xmlNsPtr get_dt_ns(xmlNodePtr node) | |
| { | |
| xmlNsPtr ns; | |
| node = get_schema(node); | |
| assert(node != NULL); | |
| FOREACH_NS(node, ns) | |
| { | |
| if (xmlStrEqual(ns->href, DT_href)) | |
| break; | |
| } | |
| return ns; | |
| } | |
| static inline xmlChar* get_dt_type(xmlNodePtr xdr) | |
| { | |
| xmlChar* str = xmlGetNsProp(xdr, xs_type, DT_href); | |
| if (!str) | |
| { | |
| xmlNodePtr datatype = get_child(xdr, xs_datatype); | |
| if (datatype) | |
| str = xmlGetNsProp(datatype, xs_type, DT_href); | |
| } | |
| return str; | |
| } | |
| static inline xmlChar* get_attr_val(xmlAttrPtr attr) | |
| { | |
| return xmlNodeGetContent((xmlNodePtr)attr); | |
| } | |
| static inline xmlNodePtr add_any_child(xmlNodePtr parent, BOOL set_occurs) | |
| { | |
| xmlNodePtr child = xmlNewChild(parent, NULL, xs_any, NULL); | |
| if (set_occurs) | |
| { | |
| xmlSetProp(child, xs_minOccurs, BAD_CAST "0"); | |
| xmlSetProp(child, xs_maxOccurs, xs_unbounded); | |
| } | |
| xmlSetProp(child, xs_processContents, xs_strict); | |
| return child; | |
| } | |
| static inline xmlNodePtr add_anyAttribute_child(xmlNodePtr parent) | |
| { | |
| xmlNodePtr child = xmlNewChild(parent, NULL, xs_anyAttribute, NULL); | |
| xmlSetProp(child, xs_processContents, xs_lax); | |
| return child; | |
| } | |
| static inline xmlAttrPtr copy_prop_ignore_ns(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| xmlChar* str = get_attr_val(xdr_attr); | |
| xmlAttrPtr attr = xmlSetProp(node, xdr_attr->name, str); | |
| xmlFree(str); | |
| return attr; | |
| } | |
| static inline xmlAttrPtr XDR_A_default(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| TRACE("(%p, %p)\n", xdr_attr, node); | |
| return copy_prop_ignore_ns(xdr_attr, node); | |
| } | |
| static inline xmlAttrPtr XDR_A_dt_type(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| xmlChar* str = get_attr_val(xdr_attr); | |
| xmlAttrPtr attr; | |
| TRACE("(%p, %p)\n", xdr_attr, node); | |
| if (xmlStrEqual(str, xs_enumeration)) | |
| attr = NULL; | |
| else | |
| attr = xmlSetNsProp(node, get_dt_ns(node), DT_prefix, str); | |
| xmlFree(str); | |
| return attr; | |
| } | |
| static xmlAttrPtr XDR_A_maxOccurs(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| xmlChar* str = get_attr_val(xdr_attr); | |
| xmlAttrPtr attr; | |
| TRACE("(%p, %p)\n", xdr_attr, node); | |
| if (xmlStrEqual(str, BAD_CAST "*")) | |
| attr = xmlSetProp(node, xs_maxOccurs, xs_unbounded); | |
| else | |
| attr = copy_prop_ignore_ns(xdr_attr, node); | |
| xmlFree(str); | |
| return attr; | |
| } | |
| static inline xmlAttrPtr XDR_A_minOccurs(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| TRACE("(%p, %p)\n", xdr_attr, node); | |
| return copy_prop_ignore_ns(xdr_attr, node); | |
| } | |
| static inline xmlAttrPtr XDR_A_name(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| TRACE("(%p, %p)\n", xdr_attr, node); | |
| return copy_prop_ignore_ns(xdr_attr, node); | |
| } | |
| static xmlAttrPtr XDR_A_type(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| xmlChar* str = get_attr_val(xdr_attr); | |
| xmlAttrPtr attr = xmlSetProp(node, xs_ref, str); | |
| TRACE("(%p, %p)\n", xdr_attr, node); | |
| xmlFree(str); | |
| return attr; | |
| } | |
| static xmlAttrPtr XDR_A_required(xmlAttrPtr xdr_attr, xmlNodePtr node) | |
| { | |
| xmlChar* str = get_attr_val(xdr_attr); | |
| xmlAttrPtr attr; | |
| TRACE("(%p, %p)\n", xdr_attr, node); | |
| if (xmlStrEqual(str, xs_no)) | |
| attr = xmlSetProp(node, xs_use, xs_optional); | |
| else /* yes */ | |
| attr = xmlSetProp(node, xs_use, xs_required); | |
| xmlFree(str); | |
| return attr; | |
| } | |
| static xmlNodePtr XDR_E_description(xmlNodePtr xdr, xmlNodePtr parent) | |
| { | |
| xmlNodePtr xsd_node = xmlNewChild(parent, NULL, xs_annotation, NULL); | |
| xmlAttrPtr xdr_attr; | |
| TRACE("(%p, %p)\n", xdr, parent); | |
| xmlNewChild(xsd_node, NULL, xs_documentation, xdr->content); | |
| FOREACH_ATTR(xdr, xdr_attr) | |
| { | |
| xmlCopyProp(xsd_node, xdr_attr); | |
| } | |
| return xsd_node; | |
| } | |
| static xmlNodePtr XDR_E_AttributeType(xmlNodePtr xdr, xmlNodePtr parent) | |
| { | |
| xmlChar *str, *type = get_dt_type(xdr); | |
| xmlNodePtr xsd_node, xsd_child, xdr_child; | |
| xmlAttrPtr xdr_attr; | |
| TRACE("(%p, %p)\n", xdr, parent); | |
| xsd_node = xmlNewChild(parent, NULL, xs_attribute, NULL); | |
| if (type && xmlStrEqual(type, xs_enumeration)) | |
| { | |
| xmlChar *tmp, *tokBegin, *tokEnd = NULL; | |
| xmlNodePtr xsd_enum; | |
| xsd_child = xmlNewChild(xsd_node, NULL, xs_simpleType, NULL); | |
| xsd_child = xmlNewChild(xsd_child, NULL, xs_restriction, NULL); | |
| xmlSetProp(xsd_child, xs_base, xs_xsd_string); | |
| tokBegin = str = xmlGetNsProp(xdr, xs_values, DT_href); | |
| while (tokBegin && *tokBegin) | |
| { | |
| while (*tokBegin && isspace(*tokBegin)) | |
| ++tokBegin; | |
| tokEnd = tokBegin; | |
| while (*tokEnd && !isspace(*tokEnd)) | |
| ++tokEnd; | |
| if (tokEnd == tokBegin) | |
| break; | |
| xsd_enum = xmlNewChild(xsd_child, NULL, xs_enumeration, NULL); | |
| tmp = xmlStrndup(tokBegin, tokEnd-tokBegin); | |
| xmlSetProp(xsd_enum, xs_value, tmp); | |
| xmlFree(tmp); | |
| tokBegin = tokEnd; | |
| } | |
| xmlFree(str); | |
| } | |
| else if (type) | |
| { | |
| str = xmlStrdup(DT_prefix); | |
| str = xmlStrcat(str, BAD_CAST ":"); | |
| str = xmlStrcat(str, type); | |
| xmlSetProp(xsd_node, xs_type, str); | |
| xmlFree(str); | |
| } | |
| xmlFree(type); | |
| FOREACH_ATTR(xdr, xdr_attr) | |
| { | |
| if (xmlStrEqual(xdr_attr->name, xs_default)) | |
| XDR_A_default(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_name)) | |
| XDR_A_name(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_type) && xdr_attr->ns == get_dt_ns(xdr)) | |
| XDR_A_dt_type(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_values) && xdr_attr->ns == get_dt_ns(xdr)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_attr->name, xs_required)) | |
| XDR_A_required(xdr_attr, xsd_node); | |
| else | |
| xmlCopyProp(xsd_node, xdr_attr); | |
| } | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_datatype)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_child->name, xs_description)) | |
| XDR_E_description(xdr_child, xsd_node); | |
| else | |
| FIXME("unexpected child <%s>\n", xdr_child->name); | |
| } | |
| return xsd_node; | |
| } | |
| static xmlNodePtr XDR_E_attribute(xmlNodePtr xdr, xmlNodePtr parent) | |
| { | |
| xmlChar* str = xmlGetProp(xdr, xs_type); | |
| xmlNodePtr xsd_node, xdr_child, xdr_attrType; | |
| xmlAttrPtr xdr_attr; | |
| TRACE("(%p, %p)\n", xdr, parent); | |
| xdr_attrType = get_child_with_attr(xdr->parent, xs_AttributeType, NULL, xs_name, str); | |
| xmlFree(str); | |
| if (xdr_attrType) | |
| xsd_node = XDR_E_AttributeType(xdr_attrType, parent); | |
| else | |
| xsd_node = xmlNewChild(parent, NULL, xs_attribute, NULL); | |
| FOREACH_ATTR(xdr, xdr_attr) | |
| { | |
| if (xmlStrEqual(xdr_attr->name, xs_default)) | |
| XDR_A_default(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_type) && !xdr_attrType) | |
| XDR_A_type(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_required)) | |
| XDR_A_required(xdr_attr, xsd_node); | |
| else | |
| xmlCopyProp(xsd_node, xdr_attr); | |
| } | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| FIXME("unexpected child <%s>\n", xdr_child->name); | |
| } | |
| return xsd_node; | |
| } | |
| static xmlNodePtr XDR_E_element(xmlNodePtr xdr, xmlNodePtr parent) | |
| { | |
| xmlNodePtr xdr_child, xsd_node = xmlNewChild(parent, NULL, xs_element, NULL); | |
| xmlAttrPtr xdr_attr; | |
| FOREACH_ATTR(xdr, xdr_attr) | |
| { | |
| if (xmlStrEqual(xdr_attr->name, xs_type)) | |
| XDR_A_type(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_maxOccurs)) | |
| XDR_A_maxOccurs(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_minOccurs)) | |
| XDR_A_minOccurs(xdr_attr, xsd_node); | |
| else | |
| xmlCopyProp(xsd_node, xdr_attr); | |
| } | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| FIXME("unexpected child <%s>\n", xdr_child->name); | |
| } | |
| return xsd_node; | |
| } | |
| static xmlNodePtr XDR_E_group(xmlNodePtr xdr, xmlNodePtr parent) | |
| { | |
| xmlNodePtr xdr_child, xsd_node; | |
| xmlChar* str = xmlGetProp(xdr, xs_order); | |
| xmlAttrPtr xdr_attr; | |
| TRACE("(%p, %p)\n", xdr, parent); | |
| if (!str || xmlStrEqual(str, xs_seq)) | |
| xsd_node = xmlNewChild(parent, NULL, xs_sequence, NULL); | |
| else if (xmlStrEqual(str, xs_many)) | |
| xsd_node = xmlNewChild(parent, NULL, xs_choice, NULL); | |
| else /* one */ | |
| xsd_node = xmlNewChild(parent, NULL, xs_all, NULL); | |
| xmlFree(str); | |
| FOREACH_ATTR(xdr, xdr_attr) | |
| { | |
| if (xmlStrEqual(xdr_attr->name, xs_order)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_attr->name, xs_model)) | |
| ; /* ignored */ | |
| else if (xmlStrEqual(xdr_attr->name, xs_maxOccurs)) | |
| XDR_A_maxOccurs(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_minOccurs)) | |
| XDR_A_minOccurs(xdr_attr, xsd_node); | |
| else | |
| xmlCopyProp(xsd_node, xdr_attr); | |
| } | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_description)) | |
| XDR_E_description(xdr_child, xsd_node); | |
| else if (xmlStrEqual(xdr_child->name, xs_element)) | |
| XDR_E_element(xdr_child, xsd_node); | |
| } | |
| return xsd_node; | |
| } | |
| static xmlNodePtr XDR_E_ElementType(xmlNodePtr xdr, xmlNodePtr parent) | |
| { | |
| xmlChar *str, *type = get_dt_type(xdr); | |
| BOOL is_open = TRUE; | |
| int n_attributes = 0, n_elements = 0, n_groups = 0; | |
| CONTENT_TYPE content; | |
| ORDER_TYPE order; | |
| xmlNodePtr xsd_node, xsd_type, xsd_child, xdr_child; | |
| xmlAttrPtr xdr_attr; | |
| xmlNsPtr dt_ns = get_dt_ns(parent); | |
| TRACE("(%p, %p)\n", xdr, parent); | |
| str = xmlGetProp(xdr, xs_model); | |
| if (str && !xmlStrEqual(str, xs_open)) | |
| is_open = FALSE; | |
| xmlFree(str); | |
| if (type) | |
| { | |
| content = CONTENT_TEXTONLY; | |
| } | |
| else | |
| { | |
| str = xmlGetProp(xdr, xs_content); | |
| if (!str || xmlStrEqual(str, xs_mixed)) | |
| content = CONTENT_MIXED; | |
| else if (xmlStrEqual(str, xs_eltOnly)) | |
| content = CONTENT_ELTONLY; | |
| else if (xmlStrEqual(str, xs_textOnly)) | |
| content = CONTENT_TEXTONLY; | |
| else /* empty */ | |
| content = CONTENT_EMPTY; | |
| xmlFree(str); | |
| } | |
| str = xmlGetProp(xdr, xs_order); | |
| if (!str || xmlStrEqual(str, xs_seq)) | |
| { | |
| order = ORDER_SEQ; | |
| } | |
| else if (xmlStrEqual(str, xs_many)) | |
| { | |
| order = ORDER_MANY; | |
| } | |
| else /* one */ | |
| { | |
| order = ORDER_ONE; | |
| is_open = FALSE; | |
| } | |
| xmlFree(str); | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_element)) | |
| ++n_elements; | |
| else if (xmlStrEqual(xdr_child->name, xs_group)) | |
| ++n_groups; | |
| else if (xmlStrEqual(xdr_child->name, xs_attribute)) | |
| ++n_attributes; | |
| } | |
| xsd_node = xmlNewChild(parent, NULL, xs_element, NULL); | |
| assert(xsd_node != NULL); | |
| switch (content) | |
| { | |
| case CONTENT_MIXED: | |
| case CONTENT_ELTONLY: | |
| { | |
| xmlNodePtr xsd_base; | |
| xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL); | |
| if (content == CONTENT_MIXED) | |
| xmlSetProp(xsd_type, xs_mixed, xs_true); | |
| if (is_open) | |
| xsd_base = xmlNewChild(xsd_type, NULL, xs_sequence, NULL); | |
| else | |
| xsd_base = xsd_type; | |
| if (is_open && n_elements < 2 && !n_groups) | |
| {/* no specific sequence of elements we need, | |
| just has to start with the right one, if any */ | |
| if ((xdr_child = get_child(xdr, xs_element))) | |
| { | |
| xsd_child = XDR_E_element(xdr_child, xsd_base); | |
| xmlUnsetProp(xsd_child, xs_maxOccurs); | |
| } | |
| } | |
| else | |
| { | |
| switch (order) | |
| { | |
| case ORDER_SEQ: | |
| xsd_child = xmlNewChild(xsd_base, NULL, xs_sequence, NULL); | |
| break; | |
| case ORDER_MANY: | |
| xsd_child = xmlNewChild(xsd_base, NULL, xs_choice, NULL); | |
| xmlSetProp(xsd_child, xs_maxOccurs, xs_unbounded); | |
| break; | |
| case ORDER_ONE: | |
| xsd_child = xmlNewChild(xsd_base, NULL, xs_all, NULL); | |
| break; | |
| } | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_element)) | |
| XDR_E_element(xdr_child, xsd_child); | |
| else if (xmlStrEqual(xdr_child->name, xs_group)) | |
| XDR_E_group(xdr_child, xsd_child); | |
| } | |
| } | |
| if (n_attributes) | |
| { | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_attribute)) | |
| XDR_E_attribute(xdr_child, xsd_type); | |
| } | |
| } | |
| if (is_open) | |
| { | |
| add_any_child(xsd_base, TRUE); | |
| add_anyAttribute_child(xsd_type); | |
| } | |
| } | |
| break; | |
| case CONTENT_TEXTONLY: | |
| { | |
| if (is_open) | |
| { | |
| xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL); | |
| if (type) | |
| { | |
| xsd_child = xmlNewChild(xsd_type, NULL, xs_simpleContent, NULL); | |
| xsd_child = xmlNewChild(xsd_child, NULL, xs_extension, NULL); | |
| str = xmlStrdup(DT_prefix); | |
| str = xmlStrcat(str, BAD_CAST ":"); | |
| str = xmlStrcat(str, type); | |
| xmlSetProp(xsd_child, xs_base, str); | |
| xmlFree(str); | |
| assert(dt_ns != NULL); | |
| xmlSetNsProp(xsd_node, dt_ns, DT_prefix, type); | |
| } | |
| else | |
| { | |
| xmlSetProp(xsd_type, xs_mixed, xs_true); | |
| xsd_child = xmlNewChild(xsd_type, NULL, xs_choice, NULL); | |
| xmlSetProp(xsd_child, xs_minOccurs, BAD_CAST "0"); | |
| xmlSetProp(xsd_child, xs_maxOccurs, xs_unbounded); | |
| xsd_child = add_any_child(xsd_child, FALSE); | |
| xmlSetProp(xsd_child, xs_namespace, BAD_CAST "##other"); | |
| xsd_child = xsd_type; | |
| } | |
| if (n_attributes) | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_attribute)) | |
| XDR_E_attribute(xdr_child, xsd_child); | |
| } | |
| xmlNewChild(xsd_child, NULL, xs_anyAttribute, NULL); | |
| } | |
| else if (!n_attributes) | |
| { | |
| if (type) | |
| { | |
| str = xmlStrdup(DT_prefix); | |
| str = xmlStrcat(str, BAD_CAST ":"); | |
| str = xmlStrcat(str, type); | |
| xmlSetProp(xsd_node, xs_type, str); | |
| xmlFree(str); | |
| str = NULL; | |
| xmlSetNsProp(xsd_node, dt_ns, DT_prefix, type); | |
| } | |
| else | |
| { | |
| xmlSetProp(xsd_node, xs_type, xs_xsd_string); | |
| } | |
| } | |
| else | |
| { | |
| xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL); | |
| xsd_child = xmlNewChild(xsd_type, NULL, xs_simpleContent, NULL); | |
| xsd_child = xmlNewChild(xsd_child, NULL, xs_extension, NULL); | |
| xmlSetProp(xsd_child, xs_base, xs_xsd_string); | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_attribute)) | |
| XDR_E_attribute(xdr_child, xsd_child); | |
| } | |
| } | |
| } | |
| break; | |
| case CONTENT_EMPTY: /* not allowed with model="open" */ | |
| { | |
| if (n_attributes) | |
| { | |
| xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL); | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_attribute)) | |
| XDR_E_attribute(xdr_child, xsd_type); | |
| } | |
| } | |
| else | |
| { | |
| xsd_type = xmlNewChild(xsd_node, NULL, xs_simpleType, NULL); | |
| xsd_child = xmlNewChild(xsd_type, NULL, xs_restriction, NULL); | |
| xmlSetProp(xsd_child, xs_base, xs_xsd_string); | |
| xsd_child = xmlNewChild(xsd_child, NULL, xs_length, NULL); | |
| xmlSetProp(xsd_child, xs_value, BAD_CAST "0"); | |
| } | |
| } | |
| break; | |
| } | |
| xmlFree(type); | |
| FOREACH_ATTR(xdr, xdr_attr) | |
| { | |
| if (xmlStrEqual(xdr_attr->name, xs_content)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_attr->name, xs_name)) | |
| XDR_A_name(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_type) && xdr_attr->ns == get_dt_ns(xdr)) | |
| XDR_A_dt_type(xdr_attr, xsd_node); | |
| else if (xmlStrEqual(xdr_attr->name, xs_model)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_attr->name, xs_order)) | |
| ; /* already handled */ | |
| else | |
| xmlCopyProp(xsd_node, xdr_attr); | |
| } | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_attribute)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_child->name, xs_AttributeType)) | |
| ; /* handled through XDR_E_attribute when parent is not <Schema> */ | |
| else if (xmlStrEqual(xdr_child->name, xs_datatype)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_child->name, xs_description)) | |
| XDR_E_description(xdr_child, xsd_node); | |
| else if (xmlStrEqual(xdr_child->name, xs_element)) | |
| ; /* already handled */ | |
| else if (xmlStrEqual(xdr_child->name, xs_group)) | |
| ; /* already handled */ | |
| else | |
| FIXME("unexpected child <%s>\n", xdr_child->name); | |
| } | |
| return xsd_node; | |
| } | |
| static xmlNodePtr XDR_E_Schema(xmlNodePtr xdr, xmlNodePtr parent, xmlChar const* nsURI) | |
| { | |
| xmlNodePtr xsd_node, xdr_child; | |
| xmlNsPtr ns, xdr_ns; | |
| xmlAttrPtr xdr_attr; | |
| TRACE("(%p, %p)\n", xdr, parent); | |
| xsd_node = xmlNewDocNode((xmlDocPtr)parent, NULL, xs_schema, NULL); | |
| xmlDocSetRootElement((xmlDocPtr)parent, xsd_node); | |
| assert(xsd_node != NULL); | |
| if (nsURI && *nsURI) xmlNewNs(xsd_node, nsURI, NULL); | |
| ns = xmlNewNs(xsd_node, XSD_href, XSD_prefix); | |
| assert(ns != NULL); | |
| xmlSetNs(xsd_node, ns); | |
| if (nsURI && *nsURI) xmlSetProp(xsd_node, xs_targetNamespace, nsURI); | |
| FOREACH_NS(xdr, xdr_ns) | |
| { | |
| /* TODO: special handling for dt namespace? */ | |
| assert(xdr_ns->href != NULL); | |
| if (xmlStrEqual(xdr_ns->href, XDR_href)) | |
| ; /* ignored */ | |
| else if (xdr_ns->prefix != NULL) | |
| xmlNewNs(xsd_node, xdr_ns->href, xdr_ns->prefix); | |
| else | |
| FIXME("unexpected default xmlns: %s\n", xdr_ns->href); | |
| } | |
| FOREACH_ATTR(xdr, xdr_attr) | |
| { | |
| xmlCopyProp(xsd_node, xdr_attr); | |
| } | |
| FOREACH_CHILD(xdr, xdr_child) | |
| { | |
| if (xmlStrEqual(xdr_child->name, xs_AttributeType)) | |
| XDR_E_AttributeType(xdr_child, xsd_node); | |
| else if (xmlStrEqual(xdr_child->name, xs_description)) | |
| XDR_E_description(xdr_child, xsd_node); | |
| else if (xmlStrEqual(xdr_child->name, xs_ElementType)) | |
| XDR_E_ElementType(xdr_child, xsd_node); | |
| else | |
| FIXME("unexpected child <%s>\n", xdr_child->name); | |
| } | |
| return xsd_node; | |
| } | |
| xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI) | |
| { | |
| xmlDocPtr xsd_doc = xmlNewDoc(NULL); | |
| TRACE("(%p)\n", xdr_doc); | |
| XDR_E_Schema(get_schema((xmlNodePtr)xdr_doc), (xmlNodePtr)xsd_doc, nsURI); | |
| return xsd_doc; | |
| } | |
| #endif /* HAVE_LIBXML2 */ |