msxml3: Implement _newEnum() for schema cache.
[wine] / dlls / msxml3 / xdr.c
1 /*
2  * XDR (XML-Data Reduced) -> XSD (XML Schema Document) conversion
3  *
4  * Copyright 2010 Adam Martinson for CodeWeavers
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21
22 #include "config.h"
23
24 #include <assert.h>
25 #ifdef HAVE_LIBXML2
26 # include <libxml/tree.h>
27 #endif
28
29 #include "wine/debug.h"
30
31 WINE_DEFAULT_DEBUG_CHANNEL(msxml);
32
33 /* Both XDR and XSD are valid XML
34  * We just convert the doc tree, no need for a parser.
35  */
36
37 #ifdef HAVE_LIBXML2
38
39 static const xmlChar DT_prefix[] = "dt";
40 static const xmlChar DT_href[] = "urn:schemas-microsoft-com:datatypes";
41 static const xmlChar XDR_prefix[] = "xdr";
42 static const xmlChar XDR_href[] = "urn:schemas-microsoft-com:xml-data";
43 static const xmlChar XSD_prefix[] = "xsd";
44 static const xmlChar XSD_href[] = "http://www.w3.org/2001/XMLSchema";
45
46 static const xmlChar xs_all[] = "all";
47 static const xmlChar xs_annotation[] = "annotation";
48 static const xmlChar xs_any[] = "any";
49 static const xmlChar xs_anyAttribute[] = "anyAttribute";
50 static const xmlChar xs_attribute[] = "attribute";
51 static const xmlChar xs_AttributeType[] = "AttributeType";
52 static const xmlChar xs_base[] = "base";
53 static const xmlChar xs_choice[] = "choice";
54 static const xmlChar xs_complexContent[] = "complexContent";
55 static const xmlChar xs_complexType[] = "complexType";
56 static const xmlChar xs_content[] = "content";
57 static const xmlChar xs_datatype[] = "datatype";
58 static const xmlChar xs_default[] = "default";
59 static const xmlChar xs_description[] = "description";
60 static const xmlChar xs_documentation[] = "documentation";
61 static const xmlChar xs_element[] = "element";
62 static const xmlChar xs_ElementType[] = "ElementType";
63 static const xmlChar xs_eltOnly[] = "eltOnly";
64 static const xmlChar xs_empty[] = "empty";
65 static const xmlChar xs_enumeration[] = "enumeration";
66 static const xmlChar xs_extension[] = "extension";
67 static const xmlChar xs_group[] = "group";
68 static const xmlChar xs_lax[] = "lax";
69 static const xmlChar xs_length[] = "length";
70 static const xmlChar xs_many[] = "many";
71 static const xmlChar xs_maxOccurs[] = "maxOccurs";
72 static const xmlChar xs_minOccurs[] = "minOccurs";
73 static const xmlChar xs_mixed[] = "mixed";
74 static const xmlChar xs_model[] = "model";
75 static const xmlChar xs_name[] = "name";
76 static const xmlChar xs_namespace[] = "namespace";
77 static const xmlChar xs_no[] = "no";
78 static const xmlChar xs_one[] = "one";
79 static const xmlChar xs_open[] = "open";
80 static const xmlChar xs_optional[] = "optional";
81 static const xmlChar xs_order[] = "order";
82 static const xmlChar xs_processContents[] = "processContents";
83 static const xmlChar xs_ref[] = "ref";
84 static const xmlChar xs_required[] = "required";
85 static const xmlChar xs_restriction[] = "restriction";
86 static const xmlChar xs_schema[] = "schema";
87 static const xmlChar xs_Schema[] = "Schema";
88 static const xmlChar xs_seq[] = "seq";
89 static const xmlChar xs_sequence[] = "sequence";
90 static const xmlChar xs_simpleContent[] = "simpleContent";
91 static const xmlChar xs_simpleType[] = "simpleType";
92 static const xmlChar xs_strict[] = "strict";
93 static const xmlChar xs_targetNamespace[] = "targetNamespace";
94 static const xmlChar xs_textOnly[] = "textOnly";
95 static const xmlChar xs_true[] = "true";
96 static const xmlChar xs_type[] = "type";
97 static const xmlChar xs_unbounded[] = "unbounded";
98 static const xmlChar xs_use[] = "use";
99 static const xmlChar xs_value[] = "value";
100 static const xmlChar xs_values[] = "values";
101 static const xmlChar xs_xsd_string[] = "xsd:string";
102 static const xmlChar xs_yes[] = "yes";
103
104 typedef enum _CONTENT_TYPE
105 {
106     CONTENT_EMPTY,
107     CONTENT_TEXTONLY,
108     CONTENT_ELTONLY,
109     CONTENT_MIXED
110 } CONTENT_TYPE;
111
112 typedef enum _ORDER_TYPE
113 {
114     ORDER_SEQ,
115     ORDER_MANY,
116     ORDER_ONE
117 } ORDER_TYPE;
118
119 #define FOREACH_CHILD(node, child) \
120     for (child = node->children; child != NULL; child = child->next) \
121         if (child->type == XML_ELEMENT_NODE)
122
123 #define FOREACH_ATTR(node, attr) \
124     for (attr = node->properties; attr != NULL; attr = attr->next)
125
126 #define FOREACH_NS(node, ns) \
127     for (ns = node->nsDef; ns != NULL; ns = ns->next)
128
129 static inline xmlNodePtr get_schema(xmlNodePtr node)
130 {
131     return xmlDocGetRootElement(node->doc);
132 }
133
134 static inline xmlNodePtr get_child(xmlNodePtr node, xmlChar const* name)
135 {
136     xmlNodePtr child = NULL;
137     if (node)
138     {
139         FOREACH_CHILD(node, child)
140         {
141             if (xmlStrEqual(child->name, name))
142                 break;
143         }
144     }
145
146     return child;
147 }
148
149 static inline xmlNodePtr get_child_with_attr(xmlNodePtr node, xmlChar const* name,
150                                              xmlChar const* attr_ns, xmlChar const* attr_name,
151                                              xmlChar const* attr_val)
152 {
153     xmlChar* str;
154     if (node)
155     {
156         FOREACH_CHILD(node, node)
157         {
158             if (xmlStrEqual(node->name, name))
159             {
160                 str = (attr_ns != NULL)? xmlGetNsProp(node, attr_name, attr_ns) :
161                                                   xmlGetProp(node, attr_name);
162                 if (str)
163                 {
164                     if (xmlStrEqual(str, attr_val))
165                     {
166                         xmlFree(str);
167                         return node;
168                     }
169                     xmlFree(str);
170                 }
171             }
172         }
173     }
174
175     return NULL;
176 }
177
178 static inline xmlNsPtr get_dt_ns(xmlNodePtr node)
179 {
180     xmlNsPtr ns;
181
182     node = get_schema(node);
183     assert(node != NULL);
184
185     FOREACH_NS(node, ns)
186     {
187         if (xmlStrEqual(ns->href, DT_href))
188             break;
189     }
190
191     return ns;
192 }
193
194 static inline xmlChar* get_dt_type(xmlNodePtr xdr)
195 {
196     xmlChar* str = xmlGetNsProp(xdr, xs_type, DT_href);
197     if (!str)
198     {
199         xmlNodePtr datatype = get_child(xdr, xs_datatype);
200         if (datatype)
201             str = xmlGetNsProp(datatype, xs_type, DT_href);
202     }
203     return str;
204 }
205
206 static inline xmlChar* get_attr_val(xmlAttrPtr attr)
207 {
208     return xmlNodeGetContent((xmlNodePtr)attr);
209 }
210
211 static inline xmlNodePtr add_any_child(xmlNodePtr parent, BOOL set_occurs)
212 {
213     xmlNodePtr child = xmlNewChild(parent, NULL, xs_any, NULL);
214     if (set_occurs)
215     {
216         xmlSetProp(child, xs_minOccurs, BAD_CAST "0");
217         xmlSetProp(child, xs_maxOccurs, xs_unbounded);
218     }
219     xmlSetProp(child, xs_processContents, xs_strict);
220     return child;
221 }
222
223 static inline xmlNodePtr add_anyAttribute_child(xmlNodePtr parent)
224 {
225     xmlNodePtr child = xmlNewChild(parent, NULL, xs_anyAttribute, NULL);
226     xmlSetProp(child, xs_processContents, xs_lax);
227     return child;
228 }
229
230 static inline xmlAttrPtr copy_prop_ignore_ns(xmlAttrPtr xdr_attr, xmlNodePtr node)
231 {
232     xmlChar* str = get_attr_val(xdr_attr);
233     xmlAttrPtr attr = xmlSetProp(node, xdr_attr->name, str);
234     xmlFree(str);
235     return attr;
236 }
237 static inline xmlAttrPtr XDR_A_default(xmlAttrPtr xdr_attr, xmlNodePtr node)
238 {
239     TRACE("(%p, %p)\n", xdr_attr, node);
240
241     return copy_prop_ignore_ns(xdr_attr, node);
242 }
243
244 static inline xmlAttrPtr XDR_A_dt_type(xmlAttrPtr xdr_attr, xmlNodePtr node)
245 {
246     xmlChar* str = get_attr_val(xdr_attr);
247     xmlAttrPtr attr;
248
249     TRACE("(%p, %p)\n", xdr_attr, node);
250
251     if (xmlStrEqual(str, xs_enumeration))
252         attr = NULL;
253     else
254         attr = xmlSetNsProp(node, get_dt_ns(node), DT_prefix, str);
255     xmlFree(str);
256     return attr;
257 }
258
259 static xmlAttrPtr XDR_A_maxOccurs(xmlAttrPtr xdr_attr, xmlNodePtr node)
260 {
261     xmlChar* str = get_attr_val(xdr_attr);
262     xmlAttrPtr attr;
263
264     TRACE("(%p, %p)\n", xdr_attr, node);
265
266     if (xmlStrEqual(str, BAD_CAST "*"))
267         attr = xmlSetProp(node, xs_maxOccurs, xs_unbounded);
268     else
269         attr = copy_prop_ignore_ns(xdr_attr, node);
270
271     xmlFree(str);
272     return attr;
273 }
274
275 static inline xmlAttrPtr XDR_A_minOccurs(xmlAttrPtr xdr_attr, xmlNodePtr node)
276 {
277     TRACE("(%p, %p)\n", xdr_attr, node);
278
279     return copy_prop_ignore_ns(xdr_attr, node);
280 }
281
282 static inline xmlAttrPtr XDR_A_name(xmlAttrPtr xdr_attr, xmlNodePtr node)
283 {
284     TRACE("(%p, %p)\n", xdr_attr, node);
285
286     return copy_prop_ignore_ns(xdr_attr, node);
287 }
288
289 static xmlAttrPtr XDR_A_type(xmlAttrPtr xdr_attr, xmlNodePtr node)
290 {
291     xmlChar* str = get_attr_val(xdr_attr);
292     xmlAttrPtr attr = xmlSetProp(node, xs_ref, str);
293
294     TRACE("(%p, %p)\n", xdr_attr, node);
295
296     xmlFree(str);
297     return attr;
298 }
299
300 static xmlAttrPtr XDR_A_required(xmlAttrPtr xdr_attr, xmlNodePtr node)
301 {
302     xmlChar* str = get_attr_val(xdr_attr);
303     xmlAttrPtr attr;
304
305     TRACE("(%p, %p)\n", xdr_attr, node);
306
307     if (xmlStrEqual(str, xs_no))
308         attr = xmlSetProp(node, xs_use, xs_optional);
309     else /* yes */
310         attr = xmlSetProp(node, xs_use, xs_required);
311     xmlFree(str);
312     return attr;
313 }
314
315 static xmlNodePtr XDR_E_description(xmlNodePtr xdr, xmlNodePtr parent)
316 {
317     xmlNodePtr xsd_node = xmlNewChild(parent, NULL, xs_annotation, NULL);
318     xmlAttrPtr xdr_attr;
319
320     TRACE("(%p, %p)\n", xdr, parent);
321
322     xmlNewChild(xsd_node, NULL, xs_documentation, xdr->content);
323
324     FOREACH_ATTR(xdr, xdr_attr)
325     {
326         xmlCopyProp(xsd_node, xdr_attr);
327     }
328     return xsd_node;
329 }
330
331 static xmlNodePtr XDR_E_AttributeType(xmlNodePtr xdr, xmlNodePtr parent)
332 {
333     xmlChar *str, *type = get_dt_type(xdr);
334     xmlNodePtr xsd_node, xsd_child, xdr_child;
335     xmlAttrPtr xdr_attr;
336
337     TRACE("(%p, %p)\n", xdr, parent);
338
339     xsd_node = xmlNewChild(parent, NULL, xs_attribute, NULL);
340
341     if (type && xmlStrEqual(type, xs_enumeration))
342     {
343         xmlChar *tmp, *tokBegin, *tokEnd = NULL;
344         xmlNodePtr xsd_enum;
345         xsd_child = xmlNewChild(xsd_node, NULL, xs_simpleType, NULL);
346         xsd_child = xmlNewChild(xsd_child, NULL, xs_restriction, NULL);
347         xmlSetProp(xsd_child, xs_base, xs_xsd_string);
348
349         tokBegin = str = xmlGetNsProp(xdr, xs_values, DT_href);
350         while (tokBegin && *tokBegin)
351         {
352             while (*tokBegin && isspace(*tokBegin))
353                 ++tokBegin;
354             tokEnd = tokBegin;
355             while (*tokEnd && !isspace(*tokEnd))
356                 ++tokEnd;
357             if (tokEnd == tokBegin)
358                 break;
359             xsd_enum = xmlNewChild(xsd_child, NULL, xs_enumeration, NULL);
360             tmp = xmlStrndup(tokBegin, tokEnd-tokBegin);
361             xmlSetProp(xsd_enum, xs_value, tmp);
362             xmlFree(tmp);
363             tokBegin = tokEnd;
364         }
365         xmlFree(str);
366
367     }
368     else if (type)
369     {
370         str = xmlStrdup(DT_prefix);
371         str = xmlStrcat(str, BAD_CAST ":");
372         str = xmlStrcat(str, type);
373         xmlSetProp(xsd_node, xs_type, str);
374         xmlFree(str);
375     }
376     xmlFree(type);
377
378     FOREACH_ATTR(xdr, xdr_attr)
379     {
380         if (xmlStrEqual(xdr_attr->name, xs_default))
381             XDR_A_default(xdr_attr, xsd_node);
382         else if (xmlStrEqual(xdr_attr->name, xs_name))
383             XDR_A_name(xdr_attr, xsd_node);
384         else if (xmlStrEqual(xdr_attr->name, xs_type) && xdr_attr->ns == get_dt_ns(xdr))
385             XDR_A_dt_type(xdr_attr, xsd_node);
386         else if (xmlStrEqual(xdr_attr->name, xs_values) && xdr_attr->ns == get_dt_ns(xdr))
387             ; /* already handled */
388         else if (xmlStrEqual(xdr_attr->name, xs_required))
389             XDR_A_required(xdr_attr, xsd_node);
390         else
391             xmlCopyProp(xsd_node, xdr_attr);
392     }
393
394     FOREACH_CHILD(xdr, xdr_child)
395     {
396         if (xmlStrEqual(xdr_child->name, xs_datatype))
397             ; /* already handled */
398         else if (xmlStrEqual(xdr_child->name, xs_description))
399             XDR_E_description(xdr_child, xsd_node);
400         else
401             FIXME("unexpected child <%s>\n", xdr_child->name);
402     }
403
404     return xsd_node;
405 }
406
407 static xmlNodePtr XDR_E_attribute(xmlNodePtr xdr, xmlNodePtr parent)
408 {
409     xmlChar* str = xmlGetProp(xdr, xs_type);
410     xmlNodePtr xsd_node, xdr_child, xdr_attrType;
411     xmlAttrPtr xdr_attr;
412
413     TRACE("(%p, %p)\n", xdr, parent);
414
415     xdr_attrType = get_child_with_attr(xdr->parent, xs_AttributeType, NULL, xs_name, str);
416     xmlFree(str);
417
418     if (xdr_attrType)
419         xsd_node = XDR_E_AttributeType(xdr_attrType, parent);
420     else
421         xsd_node = xmlNewChild(parent, NULL, xs_attribute, NULL);
422
423     FOREACH_ATTR(xdr, xdr_attr)
424     {
425         if (xmlStrEqual(xdr_attr->name, xs_default))
426             XDR_A_default(xdr_attr, xsd_node);
427         else if (xmlStrEqual(xdr_attr->name, xs_type) && !xdr_attrType)
428             XDR_A_type(xdr_attr, xsd_node);
429         else if (xmlStrEqual(xdr_attr->name, xs_required))
430             XDR_A_required(xdr_attr, xsd_node);
431         else
432             xmlCopyProp(xsd_node, xdr_attr);
433     }
434
435     FOREACH_CHILD(xdr, xdr_child)
436     {
437         FIXME("unexpected child <%s>\n", xdr_child->name);
438     }
439
440     return xsd_node;
441 }
442
443 static xmlNodePtr XDR_E_element(xmlNodePtr xdr, xmlNodePtr parent)
444 {
445     xmlNodePtr xdr_child, xsd_node = xmlNewChild(parent, NULL, xs_element, NULL);
446     xmlAttrPtr xdr_attr;
447
448     FOREACH_ATTR(xdr, xdr_attr)
449     {
450         if (xmlStrEqual(xdr_attr->name, xs_type))
451             XDR_A_type(xdr_attr, xsd_node);
452         else if (xmlStrEqual(xdr_attr->name, xs_maxOccurs))
453             XDR_A_maxOccurs(xdr_attr, xsd_node);
454         else if (xmlStrEqual(xdr_attr->name, xs_minOccurs))
455             XDR_A_minOccurs(xdr_attr, xsd_node);
456         else
457             xmlCopyProp(xsd_node, xdr_attr);
458     }
459
460     FOREACH_CHILD(xdr, xdr_child)
461     {
462         FIXME("unexpected child <%s>\n", xdr_child->name);
463     }
464
465     return xsd_node;
466 }
467
468 static xmlNodePtr XDR_E_group(xmlNodePtr xdr, xmlNodePtr parent)
469 {
470     xmlNodePtr xdr_child, xsd_node;
471     xmlChar* str = xmlGetProp(xdr, xs_order);
472     xmlAttrPtr xdr_attr;
473
474     TRACE("(%p, %p)\n", xdr, parent);
475
476     if (!str || xmlStrEqual(str, xs_seq))
477         xsd_node = xmlNewChild(parent, NULL, xs_sequence, NULL);
478     else if (xmlStrEqual(str, xs_many))
479         xsd_node = xmlNewChild(parent, NULL, xs_choice, NULL);
480     else /* one */
481         xsd_node = xmlNewChild(parent, NULL, xs_all, NULL);
482     xmlFree(str);
483
484     FOREACH_ATTR(xdr, xdr_attr)
485     {
486         if (xmlStrEqual(xdr_attr->name, xs_order))
487             ; /* already handled */
488         else if (xmlStrEqual(xdr_attr->name, xs_model))
489             ; /* ignored */
490         else if (xmlStrEqual(xdr_attr->name, xs_maxOccurs))
491             XDR_A_maxOccurs(xdr_attr, xsd_node);
492         else if (xmlStrEqual(xdr_attr->name, xs_minOccurs))
493             XDR_A_minOccurs(xdr_attr, xsd_node);
494         else
495             xmlCopyProp(xsd_node, xdr_attr);
496     }
497
498     FOREACH_CHILD(xdr, xdr_child)
499     {
500         if (xmlStrEqual(xdr_child->name, xs_description))
501             XDR_E_description(xdr_child, xsd_node);
502         else if (xmlStrEqual(xdr_child->name, xs_element))
503             XDR_E_element(xdr_child, xsd_node);
504     }
505
506     return xsd_node;
507 }
508
509 static xmlNodePtr XDR_E_ElementType(xmlNodePtr xdr, xmlNodePtr parent)
510 {
511     xmlChar *str, *type = get_dt_type(xdr);
512     BOOL is_open = TRUE;
513     int n_attributes = 0, n_elements = 0, n_groups = 0;
514     CONTENT_TYPE content;
515     ORDER_TYPE order;
516     xmlNodePtr xsd_node, xsd_type, xsd_child, xdr_child;
517     xmlAttrPtr xdr_attr;
518     xmlNsPtr dt_ns = get_dt_ns(parent);
519
520     TRACE("(%p, %p)\n", xdr, parent);
521
522     str = xmlGetProp(xdr, xs_model);
523     if (str && !xmlStrEqual(str, xs_open))
524         is_open = FALSE;
525     xmlFree(str);
526
527     if (type)
528     {
529         content = CONTENT_TEXTONLY;
530     }
531     else
532     {
533         str = xmlGetProp(xdr, xs_content);
534         if (!str || xmlStrEqual(str, xs_mixed))
535             content = CONTENT_MIXED;
536         else if (xmlStrEqual(str, xs_eltOnly))
537             content = CONTENT_ELTONLY;
538         else if (xmlStrEqual(str, xs_textOnly))
539             content = CONTENT_TEXTONLY;
540         else /* empty */
541             content = CONTENT_EMPTY;
542         xmlFree(str);
543     }
544
545     str = xmlGetProp(xdr, xs_order);
546     if (!str || xmlStrEqual(str, xs_seq))
547     {
548         order = ORDER_SEQ;
549     }
550     else if (xmlStrEqual(str, xs_many))
551     {
552         order = ORDER_MANY;
553     }
554     else /* one */
555     {
556         order = ORDER_ONE;
557         is_open = FALSE;
558     }
559     xmlFree(str);
560
561     FOREACH_CHILD(xdr, xdr_child)
562     {
563         if (xmlStrEqual(xdr_child->name, xs_element))
564             ++n_elements;
565         else if (xmlStrEqual(xdr_child->name, xs_group))
566             ++n_groups;
567         else if (xmlStrEqual(xdr_child->name, xs_attribute))
568             ++n_attributes;
569     }
570
571     xsd_node = xmlNewChild(parent, NULL, xs_element, NULL);
572     assert(xsd_node != NULL);
573     switch (content)
574     {
575         case CONTENT_MIXED:
576         case CONTENT_ELTONLY:
577             {
578                 xmlNodePtr xsd_base;
579                 xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
580
581                 if (content == CONTENT_MIXED)
582                     xmlSetProp(xsd_type, xs_mixed, xs_true);
583
584                 if (is_open)
585                     xsd_base = xmlNewChild(xsd_type, NULL, xs_sequence, NULL);
586                 else
587                     xsd_base = xsd_type;
588
589                 if (is_open && n_elements < 2 && !n_groups)
590                 {/* no specific sequence of elements we need,
591                     just has to start with the right one, if any */
592                     if ((xdr_child = get_child(xdr, xs_element)))
593                     {
594                         xsd_child = XDR_E_element(xdr_child, xsd_base);
595                         xmlUnsetProp(xsd_child, xs_maxOccurs);
596                     }
597                 }
598                 else
599                 {
600                     switch (order)
601                     {
602                         case ORDER_SEQ:
603                             xsd_child = xmlNewChild(xsd_base, NULL, xs_sequence, NULL);
604                             break;
605                         case ORDER_MANY:
606                             xsd_child = xmlNewChild(xsd_base, NULL, xs_choice, NULL);
607                             xmlSetProp(xsd_child, xs_maxOccurs, xs_unbounded);
608                             break;
609                         case ORDER_ONE:
610                             xsd_child = xmlNewChild(xsd_base, NULL, xs_all, NULL);
611                             break;
612                     }
613
614                     FOREACH_CHILD(xdr, xdr_child)
615                     {
616                         if (xmlStrEqual(xdr_child->name, xs_element))
617                             XDR_E_element(xdr_child, xsd_child);
618                         else if (xmlStrEqual(xdr_child->name, xs_group))
619                             XDR_E_group(xdr_child, xsd_child);
620                     }
621                 }
622
623                 if (n_attributes)
624                 {
625                     FOREACH_CHILD(xdr, xdr_child)
626                     {
627                         if (xmlStrEqual(xdr_child->name, xs_attribute))
628                             XDR_E_attribute(xdr_child, xsd_type);
629                     }
630                 }
631
632                 if (is_open)
633                 {
634                     add_any_child(xsd_base, TRUE);
635                     add_anyAttribute_child(xsd_type);
636                 }
637             }
638             break;
639         case CONTENT_TEXTONLY:
640             {
641                 if (is_open)
642                 {
643                     xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
644                     if (type)
645                     {
646                         xsd_child = xmlNewChild(xsd_type, NULL, xs_simpleContent, NULL);
647                         xsd_child = xmlNewChild(xsd_child, NULL, xs_extension, NULL);
648                         str = xmlStrdup(DT_prefix);
649                         str = xmlStrcat(str, BAD_CAST ":");
650                         str = xmlStrcat(str, type);
651                         xmlSetProp(xsd_child, xs_base, str);
652                         xmlFree(str);
653                         assert(dt_ns != NULL);
654                         xmlSetNsProp(xsd_node, dt_ns, DT_prefix, type);
655                     }
656                     else
657                     {
658                         xmlSetProp(xsd_type, xs_mixed, xs_true);
659                         xsd_child = xmlNewChild(xsd_type, NULL, xs_choice, NULL);
660                         xmlSetProp(xsd_child, xs_minOccurs, BAD_CAST "0");
661                         xmlSetProp(xsd_child, xs_maxOccurs, xs_unbounded);
662                         xsd_child = add_any_child(xsd_child, FALSE);
663                         xmlSetProp(xsd_child, xs_namespace, BAD_CAST "##other");
664                         xsd_child = xsd_type;
665                     }
666
667                     if (n_attributes)
668                         FOREACH_CHILD(xdr, xdr_child)
669                         {
670                             if (xmlStrEqual(xdr_child->name, xs_attribute))
671                                 XDR_E_attribute(xdr_child, xsd_child);
672                         }
673
674                     xmlNewChild(xsd_child, NULL, xs_anyAttribute, NULL);
675                 }
676                 else if (!n_attributes)
677                 {
678                     if (type)
679                     {
680                         str = xmlStrdup(DT_prefix);
681                         str = xmlStrcat(str, BAD_CAST ":");
682                         str = xmlStrcat(str, type);
683                         xmlSetProp(xsd_node, xs_type, str);
684                         xmlFree(str);
685                         str = NULL;
686                         xmlSetNsProp(xsd_node, dt_ns, DT_prefix, type);
687                     }
688                     else
689                     {
690                         xmlSetProp(xsd_node, xs_type, xs_xsd_string);
691                     }
692                 }
693                 else
694                 {
695                     xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
696                     xsd_child = xmlNewChild(xsd_type, NULL, xs_simpleContent, NULL);
697                     xsd_child = xmlNewChild(xsd_child, NULL, xs_extension, NULL);
698                     xmlSetProp(xsd_child, xs_base, xs_xsd_string);
699
700                     FOREACH_CHILD(xdr, xdr_child)
701                     {
702                         if (xmlStrEqual(xdr_child->name, xs_attribute))
703                             XDR_E_attribute(xdr_child, xsd_child);
704                     }
705                 }
706             }
707             break;
708         case CONTENT_EMPTY: /* not allowed with model="open" */
709             {
710                 if (n_attributes)
711                 {
712                     xsd_type = xmlNewChild(xsd_node, NULL, xs_complexType, NULL);
713
714                     FOREACH_CHILD(xdr, xdr_child)
715                     {
716                         if (xmlStrEqual(xdr_child->name, xs_attribute))
717                             XDR_E_attribute(xdr_child, xsd_type);
718                     }
719                 }
720                 else
721                 {
722                     xsd_type = xmlNewChild(xsd_node, NULL, xs_simpleType, NULL);
723                     xsd_child = xmlNewChild(xsd_type, NULL, xs_restriction, NULL);
724                     xmlSetProp(xsd_child, xs_base, xs_xsd_string);
725                     xsd_child = xmlNewChild(xsd_child, NULL, xs_length, NULL);
726                     xmlSetProp(xsd_child, xs_value, BAD_CAST "0");
727                 }
728             }
729             break;
730     }
731     xmlFree(type);
732
733     FOREACH_ATTR(xdr, xdr_attr)
734     {
735         if (xmlStrEqual(xdr_attr->name, xs_content))
736             ; /* already handled */
737         else if (xmlStrEqual(xdr_attr->name, xs_name))
738             XDR_A_name(xdr_attr, xsd_node);
739         else if (xmlStrEqual(xdr_attr->name, xs_type) && xdr_attr->ns == get_dt_ns(xdr))
740             XDR_A_dt_type(xdr_attr, xsd_node);
741         else if (xmlStrEqual(xdr_attr->name, xs_model))
742             ; /* already handled */
743         else if (xmlStrEqual(xdr_attr->name, xs_order))
744             ; /* already handled */
745         else
746             xmlCopyProp(xsd_node, xdr_attr);
747
748     }
749
750     FOREACH_CHILD(xdr, xdr_child)
751     {
752         if (xmlStrEqual(xdr_child->name, xs_attribute))
753             ; /* already handled */
754         else if (xmlStrEqual(xdr_child->name, xs_AttributeType))
755             ; /* handled through XDR_E_attribute when parent is not <Schema> */
756         else if (xmlStrEqual(xdr_child->name, xs_datatype))
757             ; /* already handled */
758         else if (xmlStrEqual(xdr_child->name, xs_description))
759             XDR_E_description(xdr_child, xsd_node);
760         else if (xmlStrEqual(xdr_child->name, xs_element))
761             ; /* already handled */
762         else if (xmlStrEqual(xdr_child->name, xs_group))
763             ; /* already handled */
764         else
765             FIXME("unexpected child <%s>\n", xdr_child->name);
766     }
767
768     return xsd_node;
769 }
770
771 static xmlNodePtr XDR_E_Schema(xmlNodePtr xdr, xmlNodePtr parent, xmlChar const* nsURI)
772 {
773     xmlNodePtr xsd_node, xdr_child;
774     xmlNsPtr ns, xdr_ns;
775     xmlAttrPtr xdr_attr;
776
777     TRACE("(%p, %p)\n", xdr, parent);
778
779     xsd_node = xmlNewDocNode((xmlDocPtr)parent, NULL, xs_schema, NULL);
780     xmlDocSetRootElement((xmlDocPtr)parent, xsd_node);
781     assert(xsd_node != NULL);
782
783     if (nsURI && *nsURI) xmlNewNs(xsd_node, nsURI, NULL);
784     ns = xmlNewNs(xsd_node, XSD_href, XSD_prefix);
785     assert(ns != NULL);
786
787     xmlSetNs(xsd_node, ns);
788
789     if (nsURI && *nsURI) xmlSetProp(xsd_node, xs_targetNamespace, nsURI);
790
791     FOREACH_NS(xdr, xdr_ns)
792     {
793         /* TODO: special handling for dt namespace? */
794         assert(xdr_ns->href != NULL);
795         if (xmlStrEqual(xdr_ns->href, XDR_href))
796             ; /* ignored */
797         else if (xdr_ns->prefix != NULL)
798             xmlNewNs(xsd_node, xdr_ns->href, xdr_ns->prefix);
799         else
800             FIXME("unexpected default xmlns: %s\n", xdr_ns->href);
801     }
802
803     FOREACH_ATTR(xdr, xdr_attr)
804     {
805         xmlCopyProp(xsd_node, xdr_attr);
806     }
807
808     FOREACH_CHILD(xdr, xdr_child)
809     {
810         if (xmlStrEqual(xdr_child->name, xs_AttributeType))
811             XDR_E_AttributeType(xdr_child, xsd_node);
812         else if (xmlStrEqual(xdr_child->name, xs_description))
813             XDR_E_description(xdr_child, xsd_node);
814         else if (xmlStrEqual(xdr_child->name, xs_ElementType))
815             XDR_E_ElementType(xdr_child, xsd_node);
816         else
817             FIXME("unexpected child <%s>\n", xdr_child->name);
818     }
819
820     return xsd_node;
821 }
822
823 xmlDocPtr XDR_to_XSD_doc(xmlDocPtr xdr_doc, xmlChar const* nsURI)
824 {
825     xmlDocPtr xsd_doc = xmlNewDoc(NULL);
826
827     TRACE("(%p)\n", xdr_doc);
828
829     XDR_E_Schema(get_schema((xmlNodePtr)xdr_doc), (xmlNodePtr)xsd_doc, nsURI);
830
831     return xsd_doc;
832 }
833
834 #endif /* HAVE_LIBXML2 */