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