00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "xmlschemawriter.h"
00016
00017 #include <kdebug.h>
00018
00019 #include <klocale.h>
00020 #include <kmessagebox.h>
00021 #include <qfile.h>
00022 #include <qtextstream.h>
00023 #include <qregexp.h>
00024
00025 #include "../umldoc.h"
00026 #include "../classifier.h"
00027 #include "../operation.h"
00028 #include "../umlnamespace.h"
00029
00030
00031 XMLSchemaWriter::XMLSchemaWriter()
00032 {
00033
00034 packageNamespaceTag = "tns";
00035 packageNamespaceURI = "http://foo.example.com/";
00036 schemaNamespaceTag = "xs";
00037 schemaNamespaceURI = "http://www.w3.org/2001/XMLSchema";
00038 }
00039
00040
00041 XMLSchemaWriter::~XMLSchemaWriter() {
00042 }
00043
00047 Uml::Programming_Language XMLSchemaWriter::getLanguage() {
00048 return Uml::pl_XMLSchema;
00049 }
00050
00051
00052 void XMLSchemaWriter::writeClass(UMLClassifier *c)
00053 {
00054
00055 if (!c) {
00056 kDebug()<<"Cannot write class of NULL classifier!\n";
00057 return;
00058 }
00059
00060
00061 QString fileName = findFileName(c,".xsd");
00062
00063 if (fileName.isEmpty()) {
00064 emit codeGenerated(c, false);
00065 return;
00066 }
00067
00068
00069 QFile file;
00070 if ( !openFile(file, fileName) ) {
00071 emit codeGenerated(c, false);
00072 return;
00073 }
00074
00075 QTextStream XMLschema(&file);
00076
00077
00078 if(!c->getPackage().isEmpty())
00079 packageNamespaceTag = c->getPackage();
00080
00081
00082
00083
00084
00085 XMLschema<<"<?xml version=\"1.0\"?>"<<m_endl;
00086
00087
00088 QString headerText = getHeadingFile(".xsd");
00089 if(!headerText.isEmpty()) {
00090 headerText.replace(QRegExp("%filename%"),fileName);
00091 headerText.replace(QRegExp("%filepath%"),file.name());
00092 }
00093 if(!headerText.isEmpty())
00094 XMLschema<<headerText<<m_endl;
00095
00096
00097 XMLschema<<"<"<<makeSchemaTag("schema");
00098
00099 XMLschema<<" targetNamespace=\""<<packageNamespaceURI+packageNamespaceTag<<"\""<<m_endl;
00100 XMLschema<<" xmlns:"<<schemaNamespaceTag<<"=\""<<schemaNamespaceURI<<"\"";
00101 XMLschema<<" xmlns:"<<packageNamespaceTag<<"=\""<<packageNamespaceURI+packageNamespaceTag<<"\"";
00102
00103 XMLschema<<">"<<m_endl;
00104
00105 m_indentLevel++;
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 writeClassifier(c, XMLschema);
00124
00125
00126 XMLschema<<m_endl;
00127 writeElementDecl(getElementName(c), getElementTypeName(c), XMLschema);
00128
00129
00130 m_indentLevel--;
00131 XMLschema<<getIndent()<<"</"<<makeSchemaTag("schema")<<">"<<m_endl;
00132
00133
00134 emit codeGenerated(c, true);
00135
00136
00137 file.close();
00138
00139
00140
00141 writtenClassifiers.clear();
00142 }
00143
00144 void XMLSchemaWriter::writeElementDecl( const QString &elementName, const QString &elementTypeName, QTextStream &XMLschema)
00145 {
00146 if(forceDoc())
00147 writeComment(elementName+" is the root element, declared here.", XMLschema);
00148
00149 XMLschema<<getIndent()<<"<"<<makeSchemaTag("element")
00150 <<" name=\""<<elementName<<"\""
00151 <<" type=\""<<makePackageTag(elementTypeName)<<"\""
00152 <<"/>"<<m_endl;
00153
00154 }
00155
00156 void XMLSchemaWriter::writeClassifier (UMLClassifier *c, QTextStream &XMLschema)
00157 {
00158
00159
00160 if(hasBeenWritten(c))
00161 return;
00162
00163 XMLschema<<m_endl;
00164
00165
00166 if(forceDoc() || !c->getDoc().isEmpty())
00167 writeComment(c->getDoc(),XMLschema);
00168
00169 if(c->getAbstract() || c->isInterface() )
00170 writeAbstractClassifier(c,XMLschema);
00171 else
00172 writeConcreteClassifier(c,XMLschema);
00173
00174 }
00175
00176 UMLAttributeList XMLSchemaWriter::findAttributes (UMLClassifier *c)
00177 {
00178
00179 UMLAttributeList attribs;
00180 attribs.setAutoDelete(false);
00181
00182 if (!c->isInterface()) {
00183 UMLAttributeList atl = c->getAttributeList();
00184 for(UMLAttribute *at=atl.first(); at ; at=atl.next()) {
00185 switch(at->getVisibility())
00186 {
00187 case Uml::Visibility::Public:
00188 case Uml::Visibility::Protected:
00189 attribs.append(at);
00190 break;
00191 case Uml::Visibility::Private:
00192
00193 break;
00194 default:
00195 break;
00196 }
00197 }
00198 }
00199 return attribs;
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212 void XMLSchemaWriter::writeAbstractClassifier (UMLClassifier *c, QTextStream &XMLschema)
00213 {
00214
00215
00216 UMLClassifierList subclasses = c->findSubClassConcepts();
00217 UMLClassifierList superclasses = c->findSuperClassConcepts();
00218
00219
00220 writeConcreteClassifier (c, XMLschema);
00221 writeGroupClassifierDecl (c, subclasses, XMLschema);
00222
00223 markAsWritten(c);
00224
00225
00226 if(subclasses.count() > 0)
00227 {
00228
00229 QString elementName = getElementName(c);
00230 UMLAttributeList attribs = findAttributes(c);
00231 QStringList attribGroups = findAttributeGroups(c);
00232
00233 writeAttributeGroupDecl(elementName, attribs, XMLschema);
00234
00235
00236 for(UMLClassifier * classifier = subclasses.first(); classifier; classifier = subclasses.next())
00237 writeClassifier(classifier, XMLschema);
00238 }
00239
00240
00241 for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
00242 writeClassifier(classifier, XMLschema);
00243
00244 }
00245
00246 void XMLSchemaWriter::writeGroupClassifierDecl (UMLClassifier *c,
00247 UMLClassifierList subclasses,
00248 QTextStream &XMLschema)
00249 {
00250
00251
00252 QString elementTypeName = getElementGroupTypeName(c);
00253
00254
00255 XMLschema<<getIndent()<<"<"<<makeSchemaTag("group")<<" name=\""<<elementTypeName<<"\">"<<m_endl;
00256 m_indentLevel++;
00257
00258 XMLschema<<getIndent()<<"<"<<makeSchemaTag("choice")<<">"<<m_endl;
00259 m_indentLevel++;
00260
00261 for(UMLClassifier *classifier = subclasses.first(); classifier; classifier = subclasses.next()) {
00262 writeAssociationRoleDecl(classifier, "1", XMLschema);
00263 }
00264
00265 m_indentLevel--;
00266 XMLschema<<getIndent()<<"</"<<makeSchemaTag("choice")<<">"<<m_endl;
00267
00268 m_indentLevel--;
00269
00270
00271 XMLschema<<getIndent()<<"</"<<makeSchemaTag("group")<<">"<<m_endl;
00272
00273 }
00274
00275 void XMLSchemaWriter::writeComplexTypeClassifierDecl (UMLClassifier *c,
00276 UMLAssociationList associations,
00277 UMLAssociationList aggregations,
00278 UMLAssociationList compositions,
00279 UMLClassifierList superclasses,
00280 QTextStream &XMLschema)
00281 {
00282
00283
00284
00285
00286
00287 UMLAttributeList attribs = findAttributes(c);
00288 QStringList attribGroups = findAttributeGroups(c);
00289
00290
00291 bool hasAssociations = determineIfHasChildNodes(c);
00292 bool hasSuperclass = superclasses.count()> 0;
00293 bool hasAttributes = attribs.count() > 0 || attribGroups.count() > 0;
00294
00295
00296
00297
00298 QString elementTypeName = getElementTypeName(c);
00299
00300 XMLschema<<getIndent()<<"<"<<makeSchemaTag("complexType")<<" name=\""<<elementTypeName<<"\"";
00301
00302 if(hasAssociations || hasAttributes || hasSuperclass)
00303 {
00304
00305 XMLschema<<">"<<m_endl;
00306
00307 m_indentLevel++;
00308
00309 if(hasSuperclass)
00310 {
00311 QString superClassName = getElementTypeName(superclasses.first());
00312 XMLschema<<getIndent()<<"<"<<makeSchemaTag("complexContent")<<">"<<m_endl;
00313
00314
00315 m_indentLevel++;
00316 XMLschema<<getIndent()<<"<"<<makeSchemaTag("extension")<<" base=\""<<makePackageTag(superClassName)
00317 <<"\"";
00318 if(hasAssociations || hasAttributes )
00319 XMLschema<<">"<<m_endl;
00320 else
00321 XMLschema<<"/>"<<m_endl;
00322
00323 m_indentLevel++;
00324 }
00325
00326 if(hasAssociations)
00327 {
00328
00329
00330 bool didFirstOne = false;
00331 didFirstOne = writeAssociationDecls(associations, true, didFirstOne, c->getID(), XMLschema);
00332 didFirstOne = writeAssociationDecls(aggregations, false, didFirstOne, c->getID(), XMLschema);
00333 didFirstOne = writeAssociationDecls(compositions, false, didFirstOne, c->getID(), XMLschema);
00334
00335 if (didFirstOne) {
00336 m_indentLevel--;
00337 XMLschema<<getIndent()<<"</"<<makeSchemaTag("sequence")<<">"<<m_endl;
00338 }
00339 }
00340
00341
00342
00343 if(hasAttributes)
00344 {
00345 writeAttributeDecls(attribs, XMLschema);
00346 for(uint i= 0; i < attribGroups.count(); i++)
00347 XMLschema<<getIndent()<<"<"<<makeSchemaTag("attributeGroup")<<" ref=\""
00348 <<makePackageTag(attribGroups[i])<<"\"/>"<<m_endl;
00349 }
00350
00351 if(hasSuperclass)
00352 {
00353 m_indentLevel--;
00354
00355 if(hasAssociations || hasAttributes )
00356 XMLschema<<getIndent()<<"</"<<makeSchemaTag("extension")<<">"<<m_endl;
00357
00358 m_indentLevel--;
00359 XMLschema<<getIndent()<<"</"<<makeSchemaTag("complexContent")<<">"<<m_endl;
00360 }
00361
00362
00363 m_indentLevel--;
00364 XMLschema<<getIndent()<<"</"<<makeSchemaTag("complexType")<<">"<<m_endl;
00365
00366 } else
00367 XMLschema<<"/>"<<m_endl;
00368
00369 }
00370
00371 void XMLSchemaWriter::writeConcreteClassifier (UMLClassifier *c, QTextStream &XMLschema)
00372 {
00373
00374
00375
00376 UMLClassifierList superclasses = c->findSuperClassConcepts();
00377 UMLClassifierList subclasses = c->findSubClassConcepts();
00378 UMLAssociationList aggregations = c->getAggregations();
00379 UMLAssociationList compositions = c->getCompositions();
00380
00381 UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association);
00382
00383
00384 writeComplexTypeClassifierDecl(c, associations, aggregations, compositions, superclasses, XMLschema);
00385
00386 markAsWritten(c);
00387
00388
00389 writeChildObjsInAssociation(c, associations, XMLschema);
00390 writeChildObjsInAssociation(c, aggregations, XMLschema);
00391 writeChildObjsInAssociation(c, compositions, XMLschema);
00392
00393
00394 for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
00395 writeClassifier(classifier, XMLschema);
00396
00397
00398 for(UMLClassifier *classifier = subclasses.first(); classifier; classifier = subclasses.next())
00399 writeClassifier(classifier, XMLschema);
00400 }
00401
00402
00403 QStringList XMLSchemaWriter::findAttributeGroups (UMLClassifier *c)
00404 {
00405
00406
00407 QStringList list;
00408 UMLClassifierList superclasses = c->findSuperClassConcepts();
00409 for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
00410 {
00411 if(classifier->getAbstract())
00412 {
00413
00414 if (!classifier->isInterface()) {
00415 UMLAttributeList attribs = c->getAttributeList();
00416 if (attribs.count() > 0)
00417 list.append(getElementName(classifier)+"AttribGroupType");
00418 }
00419 }
00420 }
00421 return list;
00422 }
00423
00424 bool XMLSchemaWriter::determineIfHasChildNodes( UMLClassifier *c)
00425 {
00426 UMLObjectList aggList = findChildObjsInAssociations (c, c->getAggregations());
00427 UMLObjectList compList = findChildObjsInAssociations (c, c->getCompositions());
00428 UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association);
00429 UMLObjectList assocList = findChildObjsInAssociations (c, associations);
00430 return aggList.count() > 0 || compList.count() > 0 || assocList.count() > 0;
00431 }
00432
00433 void XMLSchemaWriter::writeChildObjsInAssociation (UMLClassifier *c,
00434 UMLAssociationList assoc,
00435 QTextStream &XMLschema)
00436 {
00437
00438 UMLObjectList list = findChildObjsInAssociations (c, assoc);
00439 for(UMLObject * obj = list.first(); obj; obj = list.next())
00440 {
00441 UMLClassifier * thisClassifier = dynamic_cast<UMLClassifier*>(obj);
00442 if(thisClassifier)
00443 writeClassifier(thisClassifier, XMLschema);
00444 }
00445 }
00446
00447 bool XMLSchemaWriter::hasBeenWritten(UMLClassifier *c) {
00448 if (writtenClassifiers.contains(c))
00449 return true;
00450 else
00451 return false;
00452 }
00453
00454 void XMLSchemaWriter::markAsWritten(UMLClassifier *c) {
00455 writtenClassifiers.append(c);
00456 }
00457
00458 void XMLSchemaWriter::writeAttributeDecls(UMLAttributeList &attribs, QTextStream &XMLschema )
00459 {
00460
00461 UMLAttribute *at;
00462 for(at=attribs.first(); at; at=attribs.next())
00463 {
00464 writeAttributeDecl(at,XMLschema);
00465 }
00466
00467 }
00468
00469 void XMLSchemaWriter::writeAttributeDecl(UMLAttribute *attrib, QTextStream &XMLschema )
00470 {
00471
00472 QString documentation = attrib->getDoc();
00473 QString typeName = fixTypeName(attrib->getTypeName());
00474 bool isStatic = attrib->getStatic();
00475 QString initialValue = fixInitialStringDeclValue(attrib->getInitialValue(), typeName);
00476
00477 if(!documentation.isEmpty())
00478 writeComment(documentation, XMLschema);
00479
00480 XMLschema<<getIndent()<<"<"<<makeSchemaTag("attribute")
00481 <<" name=\""<<cleanName(attrib->getName())<<"\""
00482 <<" type=\""<<typeName<<"\"";
00483
00484
00485 if(!initialValue.isEmpty())
00486 {
00487
00488
00489 if(isStatic)
00490 XMLschema<<" use=\"required\" fixed=\""<<initialValue<<"\"";
00491 else
00492 XMLschema<<" use=\"optional\" default=\""<<initialValue<<"\"";
00493 }
00494
00495
00496 XMLschema<<"/>"<<m_endl;
00497
00498 }
00499
00500 void XMLSchemaWriter::writeAttributeGroupDecl (const QString &elementName, UMLAttributeList &attribs, QTextStream &XMLschema )
00501 {
00502
00503 if (attribs.count()> 0) {
00504
00505
00506 writeComment("attributes for element "+elementName,XMLschema);
00507
00508
00509 XMLschema<<getIndent()<<"<"<<makeSchemaTag("attributeGroup")<<" name=\""<<elementName+"AttribGroupType"<<"\">"<<m_endl;
00510
00511 m_indentLevel++;
00512
00513 for( UMLAttribute *at=attribs.first(); at; at=attribs.next())
00514 {
00515 writeAttributeDecl(at,XMLschema);
00516 }
00517
00518 m_indentLevel--;
00519
00520
00521 XMLschema<<getIndent()<<"</"<<makeSchemaTag("attributeGroup")<<">"<<m_endl;
00522 }
00523 }
00524
00525 void XMLSchemaWriter::writeComment( const QString &comment, QTextStream &XMLschema )
00526 {
00527
00528
00529
00530 QString indent = getIndent();
00531 XMLschema<<indent<<"<!-- ";
00532 if (comment.contains(QRegExp("\n"))) {
00533 XMLschema<<m_endl;
00534 QStringList lines = QStringList::split( "\n", comment);
00535 for(uint i= 0; i < lines.count(); i++)
00536 XMLschema<<indent<<" "<<lines[i]<<m_endl;
00537
00538 XMLschema<<indent<<"-->"<<m_endl;
00539 } else {
00540
00541
00542 XMLschema<<comment<<" -->"<<m_endl;
00543 }
00544 }
00545
00546
00547
00548
00549
00550
00551
00552 bool XMLSchemaWriter::writeAssociationDecls(UMLAssociationList associations,
00553 bool noRoleNameOK, bool didFirstOne, Uml::IDType id, QTextStream &XMLschema)
00554 {
00555
00556 if( !associations.isEmpty() )
00557 {
00558 bool printRoleA = false, printRoleB = false;
00559
00560 for(UMLAssociation *a = associations.first(); a; a = associations.next())
00561 {
00562
00563
00564
00565 if (a->getObjectId(Uml::A) == id && a->getVisibility(Uml::B) != Uml::Visibility::Private)
00566 printRoleB = true;
00567
00568 if (a->getObjectId(Uml::B) == id && a->getVisibility(Uml::A) != Uml::Visibility::Private)
00569 printRoleA = true;
00570
00571
00572
00573 if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
00574 writeComment(a->getDoc(), XMLschema);
00575
00576
00577 if(!didFirstOne && (printRoleA || printRoleB))
00578 {
00579 didFirstOne = true;
00580 XMLschema<<getIndent()<<"<"<<makeSchemaTag("sequence")<<">"<<m_endl;
00581 m_indentLevel++;
00582 }
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 if (printRoleA)
00603 {
00604 UMLClassifier *classifierA = dynamic_cast<UMLClassifier*>(a->getObject(Uml::A));
00605 if (classifierA) {
00606
00607
00608 if (!a->getRoleName(Uml::A).isEmpty() || noRoleNameOK )
00609 writeAssociationRoleDecl(classifierA, a->getMulti(Uml::A), XMLschema);
00610 }
00611 }
00612 }
00613
00614 }
00615
00616 return didFirstOne;
00617 }
00618
00619 UMLObjectList XMLSchemaWriter::findChildObjsInAssociations (UMLClassifier *c, UMLAssociationList associations)
00620 {
00621 Uml::IDType id = c->getID();
00622 UMLObjectList list;
00623 for(UMLAssociation *a = associations.first(); a; a = associations.next())
00624 {
00625 if (a->getObjectId(Uml::A) == id
00626 && a->getVisibility(Uml::B) != Uml::Visibility::Private
00627 && !a->getRoleName(Uml::B).isEmpty()
00628 )
00629 list.append(a->getObject(Uml::B));
00630
00631 if (a->getObjectId(Uml::B) == id
00632 && a->getVisibility(Uml::A) != Uml::Visibility::Private
00633 && !a->getRoleName(Uml::A).isEmpty()
00634 )
00635 list.append(a->getObject(Uml::A));
00636 }
00637 return list;
00638 }
00639
00640 void XMLSchemaWriter::writeAssociationRoleDecl( UMLClassifier *c, const QString &multi, QTextStream &XMLschema)
00641 {
00642
00643 bool isAbstract = c->getAbstract();
00644 bool isInterface = c->isInterface();
00645
00646 QString elementName = getElementName(c);
00647 QString doc = c->getDoc();
00648
00649 if (!doc.isEmpty())
00650 writeComment(doc, XMLschema);
00651
00652
00653
00654
00655
00656 QString minOccurs = "0";
00657 QString maxOccurs = "unbounded";
00658 if (multi.isEmpty())
00659 {
00660
00661
00662 minOccurs = "1";
00663 maxOccurs = "1";
00664 }
00665 else
00666 {
00667 QStringList values = QStringList::split( QRegExp("[^\\d{1,}|\\*]"), multi);
00668
00669
00670
00671
00672 if (values.count() > 0)
00673 {
00674
00675
00676 if(values[0].contains(QRegExp("\\d{1,}")))
00677 minOccurs = values[0];
00678
00679 if(values[values.count()-1].contains(QRegExp("\\d{1,}")))
00680 maxOccurs = values[values.count()-1];
00681 }
00682 }
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714 if ((isAbstract || isInterface ) && c->findSubClassConcepts().count() > 0)
00715 XMLschema<<getIndent()<<"<"<<makeSchemaTag("group")
00716 <<" ref=\""<<makePackageTag(getElementGroupTypeName(c))<<"\"";
00717 else
00718 XMLschema<<getIndent()<<"<"<<makeSchemaTag("element")
00719 <<" name=\""<<getElementName(c)<<"\""
00720 <<" type=\""<<makePackageTag(getElementTypeName(c))<<"\"";
00721
00722
00723 if (minOccurs != "1")
00724 XMLschema<<" minOccurs=\""<<minOccurs<<"\"";
00725
00726 if (maxOccurs != "1")
00727 XMLschema<<" maxOccurs=\""<<maxOccurs<<"\"";
00728
00729
00730 XMLschema<<"/>"<<m_endl;
00731
00732 }
00733
00734
00735
00736
00737 QString XMLSchemaWriter::fixTypeName(const QString& string)
00738 {
00739
00740
00741 return schemaNamespaceTag + ':' + string;
00742 }
00743
00744 QString XMLSchemaWriter::fixInitialStringDeclValue(QString value, const QString &type)
00745 {
00746
00747 if (!value.isEmpty() && type == "xs:string") {
00748 if (!value.startsWith("\""))
00749 value.remove(0,1);
00750 if (!value.endsWith("\""))
00751 value.remove(value.length(),1);
00752 }
00753 return value;
00754 }
00755
00756 QString XMLSchemaWriter::getElementName(UMLClassifier *c)
00757 {
00758 return cleanName(c->getName());
00759 }
00760
00761 QString XMLSchemaWriter::getElementTypeName(UMLClassifier *c)
00762 {
00763 QString elementName = getElementName(c);
00764 return elementName + "ComplexType";
00765 }
00766
00767 QString XMLSchemaWriter::getElementGroupTypeName(UMLClassifier *c)
00768 {
00769 QString elementName = getElementName(c);
00770 return elementName + "GroupType";
00771 }
00772
00773 QString XMLSchemaWriter::makePackageTag (QString tagName) {
00774 tagName.prepend( packageNamespaceTag + ':');
00775 return tagName;
00776 }
00777
00778 QString XMLSchemaWriter::makeSchemaTag (QString tagName) {
00779 tagName.prepend( schemaNamespaceTag + ':');
00780 return tagName;
00781 }
00782
00783 const QStringList XMLSchemaWriter::reservedKeywords() const {
00784
00785 static QStringList keywords;
00786
00787 if (keywords.isEmpty()) {
00788 keywords << "ATTLIST"
00789 << "CDATA"
00790 << "DOCTYPE"
00791 << "ELEMENT"
00792 << "ENTITIES"
00793 << "ENTITY"
00794 << "ID"
00795 << "IDREF"
00796 << "IDREFS"
00797 << "NMTOKEN"
00798 << "NMTOKENS"
00799 << "NOTATION"
00800 << "PUBLIC"
00801 << "SHORTREF"
00802 << "SYSTEM"
00803 << "USEMAP";
00804 }
00805
00806 return keywords;
00807 }
00808
00809 #include "xmlschemawriter.moc"