Logo Search packages:      
Sourcecode: kdesdk version File versions

xmlschemawriter.cpp

/***************************************************************************
                          xmlschemawriter.cpp  -  description
                             -------------------
    copyright            : (C) 2003 Brian Thomas brian.thomas@gsfc.nasa.gov
***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include "xmlschemawriter.h"

#include <kdebug.h>

#include <klocale.h>
#include <kmessagebox.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qregexp.h>

#include "../umldoc.h"
#include "../class.h"
#include "../interface.h"
#include "../operation.h"
#include "../umlnamespace.h"

// Constructor
00033 XMLSchemaWriter::XMLSchemaWriter( UMLDoc *doc, const char *name ) 
   : SimpleCodeGenerator ( doc, name )
{

      packageNamespaceTag = "tns";
      packageNamespaceURI = "http://foo.example.com/";
      schemaNamespaceTag = "xs";
      schemaNamespaceURI = "http://www.w3.org/2001/XMLSchema";
      indent = m_indentation;
      indentLevel = 0;
      startline = m_newLineEndingChars;
}

// form of..."the Destructor"!!
00047 XMLSchemaWriter::~XMLSchemaWriter() {
}

00050 QString XMLSchemaWriter::getLanguage() {
        return "XMLSchema";
}

bool XMLSchemaWriter::isType (QString & type)
{
   if(type == "XMLSchemaWriter")
        return true;
   return false;
}

// main method for invoking..
00062 void XMLSchemaWriter::writeClass(UMLClassifier *c)
{

      if (!c) {
            kdDebug()<<"Cannot write class of NULL classifier!\n";
            return;
      }

      // find an appropriate name for our file
      QString fileName = findFileName(c,".xsd");

      if (!fileName) {
            emit codeGenerated(c, false);
            return;
      }

      // check that we may open that file for writing
      QFile file;
      if ( !openFile(file, fileName+".xsd") ) {
            emit codeGenerated(c, false);
            return;
      }

      QTextStream XMLschema(&file);

      // set package namespace tag appropriately
        if(!c->getPackage().isEmpty())
             packageNamespaceTag = c->getPackage();

      // START WRITING

      // 0. FIRST THING: open the xml processing instruction. This MUST be
      // the first thing in the file
      XMLschema<<"<?xml version=\"1.0\"?>"<<endl;

      // 1. create the header
      QString headerText = getHeadingFile(".xsd");
      if(!headerText.isEmpty()) {
            headerText.replace(QRegExp("%filename%"),fileName+".xsd");
            headerText.replace(QRegExp("%filepath%"),file.name());
      }
      if(!headerText.isEmpty())
            XMLschema<<headerText<<endl;

      // 2. Open schema element node with appropriate namespace decl
      XMLschema<<"<"<<makeSchemaTag("schema");
      // common namespaces we know will be in the file..
      XMLschema<<" targetNamespace=\""<<packageNamespaceURI+packageNamespaceTag<<"\""<<endl;
      XMLschema<<" xmlns:"<<schemaNamespaceTag<<"=\""<<schemaNamespaceURI<<"\"";
      XMLschema<<" xmlns:"<<packageNamespaceTag<<"=\""<<packageNamespaceURI+packageNamespaceTag<<"\"";

      XMLschema<<">"<<endl; // close opening declaration

      indentLevel++;

        // 3? IMPORT statements -- do we need to do anything here? I suppose if
      // our document has more than one package, which is possible, we are missing
      // the correct import statements. Leave that for later at this time.
        /*
        //only import classes in a different package as this class
        UMLClassifierList imports;
        findObjectsRelated(c,imports);
        for(UMLClassifier *con = imports.first(); con ; con = imports.next())
                if(con->getPackage() != c->getPackage())
                        XMLschema<<"import "<<con->getPackage()<<"."<<cleanName(con->getName())<<";"<<endl;
        */

      // 4. BODY of the schema.
      // start the writing by sending this classifier, the "root" for this particular
      // schema, to writeClassifier method, which will subsequently call itself on all
      // related classifiers and thus populate the schema.
      writeClassifier(c, XMLschema);

      // 5. What remains is to make the root node declaration
      XMLschema<<endl;
      writeElementDecl(getElementName(c), getElementTypeName(c), XMLschema);

      // 6. Finished: now we may close schema decl
      indentLevel--;
      XMLschema<<getIndent()<<"</"<<makeSchemaTag("schema")<<">"<<endl; // finished.. close schema node

      // bookeeping for code generation
      emit codeGenerated(c, true);

      // tidy up. no dangling open files please..
      file.close();

      // need to clear HERE, NOT in the destructor because we want each
      // schema that we write to have all related classes.
      writtenClassifiers.clear();
}

00154 void XMLSchemaWriter::writeElementDecl( QString elementName, QString elementTypeName, QTextStream &XMLschema)
{
        if(forceDoc())
            writeComment(elementName+" is the root element, declared here.", XMLschema);

      XMLschema<<getIndent()<<"<"<<makeSchemaTag("element")
            <<" name=\""<<elementName<<"\""
            <<" type=\""<<makePackageTag(elementTypeName)<<"\""
            <<"/>"<<endl;

}

00166 void XMLSchemaWriter::writeClassifier (UMLClassifier *c, QTextStream &XMLschema)
{

      // NO doing this 2 or more times.
      if(hasBeenWritten(c))
            return;

      XMLschema<<endl;

      // write documentation for class, if any, first
        if(forceDoc() || !c->getDoc().isEmpty())
            writeComment(c->getDoc(),XMLschema);

      if(c->getAbstract() || dynamic_cast<UMLInterface*>(c) )
            writeAbstractClassifier(c,XMLschema); // if its an interface or abstract class
      else
            writeConcreteClassifier(c,XMLschema);

}

00186 UMLAttributeList XMLSchemaWriter::findAttributes (UMLClassifier *c)
{
        // sort attributes by Scope
        UMLAttributeList attribs;
        attribs.setAutoDelete(false);

      UMLClass * myClass = dynamic_cast<UMLClass*>(c);
      if(myClass) {
              UMLAttributeList *atl = myClass->getFilteredAttributeList();
              for(UMLAttribute *at=atl->first(); at ; at=atl->next()) {
                      switch(at->getScope())
                      {
                              case Uml::Public:
                              case Uml::Protected:
                                      attribs.append(at);
                                      break;
                              case Uml::Private:
                                      // DO NOTHING! no way to print in the schema
                                      break;
                      }
              }
      }
      return attribs;
}

// We have to do 2 things with abstract classifiers (e.g. abstract classes and interfaces)
// which is to:
// 1) declare it as a complexType so it may be inherited (I can see an option here: to NOT write
//    this complexType declaration IF the classifier itself isnt inherited by or is inheriting
//    from anything because no other element will use this complexType).
// 2) Create a group so that elements, which obey the abstract class /interface may be placed in
//    aggregation with other elements (again, and option here to NOT write the group if no other
//    element use the interface in element aggregation)
//

void XMLSchemaWriter::writeAbstractClassifier (UMLClassifier *c, QTextStream &XMLschema)
{

      // preparations
      UMLClassifierList subclasses = c->findSubClassConcepts(); // list of what inherits from us
      UMLClassifierList superclasses = c->findSuperClassConcepts(); // list of what we inherit from

      // write the main declaration
      writeConcreteClassifier (c, XMLschema);
      writeGroupClassifierDecl (c, subclasses, XMLschema);

      markAsWritten(c);

      // now go back and make sure all sub-classing nodes are declared
      if(subclasses.count() > 0)
      {

            QString elementName = getElementName(c);
            UMLAttributeList attribs = findAttributes(c);
            QStringList attribGroups = findAttributeGroups(c);

            writeAttributeGroupDecl(elementName, attribs, XMLschema);

            // now write out inheriting classes, as needed
            for(UMLClassifier * classifier = subclasses.first(); classifier; classifier = subclasses.next())
                  writeClassifier(classifier, XMLschema);
      }

      // write out any superclasses as needed
      for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
            writeClassifier(classifier, XMLschema);

}

00255 void XMLSchemaWriter::writeGroupClassifierDecl (UMLClassifier *c,
                                    UMLClassifierList subclasses,
                                    QTextStream &XMLschema)
{

      // name of class, subclassing classifiers
      QString elementTypeName = getElementGroupTypeName(c);

      // start Writing node but only if it has subclasses? Nah..right now put in empty group
      XMLschema<<getIndent()<<"<"<<makeSchemaTag("group")<<" name=\""<<elementTypeName<<"\">"<<endl;
      indentLevel++;

      XMLschema<<getIndent()<<"<"<<makeSchemaTag("choice")<<">"<<endl;
      indentLevel++;

      for(UMLClassifier *classifier = subclasses.first(); classifier; classifier = subclasses.next()) {
            writeAssociationRoleDecl(classifier, "1", XMLschema);
      }

      indentLevel--;
      XMLschema<<getIndent()<<"</"<<makeSchemaTag("choice")<<">"<<endl;

      indentLevel--;

      // finish node
      XMLschema<<getIndent()<<"</"<<makeSchemaTag("group")<<">"<<endl;

}

00284 void XMLSchemaWriter::writeComplexTypeClassifierDecl (UMLClassifier *c,
                                          UMLAssociationList associations,
                                          UMLAssociationList aggregations,
                                          UMLAssociationList compositions,
                                          UMLClassifierList superclasses,
                                          QTextStream &XMLschema)
{

      // Preparations
      //

      // sort attributes by Scope
      UMLAttributeList attribs = findAttributes(c);
      QStringList attribGroups = findAttributeGroups(c);

      // test for relevant associations
      bool hasAssociations = determineIfHasChildNodes(c);
      bool hasSuperclass = superclasses.count()> 0;
      bool hasAttributes = attribs.count() > 0 || attribGroups.count() > 0;

      // START WRITING

      // start body of element
      QString elementTypeName = getElementTypeName(c);

      XMLschema<<getIndent()<<"<"<<makeSchemaTag("complexType")<<" name=\""<<elementTypeName<<"\"";

      if(hasAssociations || hasAttributes || hasSuperclass)
      {

            XMLschema<<">"<<endl;

            indentLevel++;

            if(hasSuperclass)
            {
                  QString superClassName = getElementTypeName(superclasses.first());
                  XMLschema<<getIndent()<<"<"<<makeSchemaTag("complexContent")<<">"<<endl;

                  //PROBLEM: we only treat ONE superclass for inheritence.. bah.
                  indentLevel++;
                  XMLschema<<getIndent()<<"<"<<makeSchemaTag("extension")<<" base=\""<<makePackageTag(superClassName)
                        <<"\"";
                  if(hasAssociations || hasAttributes )
                        XMLschema<<">"<<endl;
                  else
                        XMLschema<<"/>"<<endl;

                  indentLevel++;
            }

            if(hasAssociations)
            {
                  // Child Elements (from most associations)
                  //
                  bool didFirstOne = false;
                  didFirstOne = writeAssociationDecls(associations, true, didFirstOne, c->getID(), XMLschema);
                  didFirstOne = writeAssociationDecls(aggregations, false, didFirstOne, c->getID(), XMLschema);
                  didFirstOne = writeAssociationDecls(compositions, false, didFirstOne, c->getID(), XMLschema);

                  if (didFirstOne) {
                        indentLevel--;
                        XMLschema<<getIndent()<<"</"<<makeSchemaTag("sequence")<<">"<<endl;
                  }
            }

            // ATTRIBUTES
            //
            if(hasAttributes)
            {
                  writeAttributeDecls(attribs, XMLschema);
                  for(uint i= 0; i < attribGroups.count(); i++)
                        XMLschema<<getIndent()<<"<"<<makeSchemaTag("attributeGroup")<<" ref=\""
                              <<makePackageTag(attribGroups[i])<<"\"/>"<<endl;
            }

            if(hasSuperclass)
            {
                  indentLevel--;

                  if(hasAssociations || hasAttributes )
                        XMLschema<<getIndent()<<"</"<<makeSchemaTag("extension")<<">"<<endl;

                  indentLevel--;
                  XMLschema<<getIndent()<<"</"<<makeSchemaTag("complexContent")<<">"<<endl;
            }

            // close this element decl
            indentLevel--;
            XMLschema<<getIndent()<<"</"<<makeSchemaTag("complexType")<<">"<<endl;

      } else
            XMLschema<<"/>"<<endl; // empty node. just close this element decl

}

void XMLSchemaWriter::writeConcreteClassifier (UMLClassifier *c, QTextStream &XMLschema)
{

      // preparations.. gather information about this classifier
      //
      UMLClassifierList superclasses = c->findSuperClassConcepts(); // list of what inherits from us
      UMLClassifierList subclasses = c->findSubClassConcepts(); // list of what we inherit from
      UMLAssociationList aggregations = c->getAggregations();
      UMLAssociationList compositions = c->getCompositions();
      // BAD! only way to get "general" associations.
      UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association);

      // write the main declaration
      writeComplexTypeClassifierDecl(c, associations, aggregations, compositions, superclasses, XMLschema);

      markAsWritten(c);

      // Now write out any child def's
      writeChildObjsInAssociation(c, associations, XMLschema);
      writeChildObjsInAssociation(c, aggregations, XMLschema);
      writeChildObjsInAssociation(c, compositions, XMLschema);

      // write out any superclasses as needed
      for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
            writeClassifier(classifier, XMLschema);

      // write out any subclasses as needed
      for(UMLClassifier *classifier = subclasses.first(); classifier; classifier = subclasses.next())
            writeClassifier(classifier, XMLschema);
}

// these exist for abstract classes only (which become xs:group nodes)
00412 QStringList XMLSchemaWriter::findAttributeGroups (UMLClassifier *c)
{
      // we need to look for any class we inherit from. IF these
      // have attributes, then we need to notice
      QStringList list;
      UMLClassifierList superclasses = c->findSuperClassConcepts(); // list of what inherits from us
      for(UMLClassifier *classifier = superclasses.first(); classifier; classifier = superclasses.next())
      {
            if(classifier->getAbstract())
            {
                  // only classes have attributes..
                  UMLClass * myClass = dynamic_cast<UMLClass*>(classifier);
                  if(myClass) {
                        UMLAttributeList* attribs = myClass->getFilteredAttributeList();
                        if (attribs->count() > 0)
                              list.append(getElementName(classifier)+"AttribGroupType");
                  }
            }
      }
      return list;
}

00434 bool XMLSchemaWriter::determineIfHasChildNodes( UMLClassifier *c)
{
      UMLObjectList aggList = findChildObjsInAssociations (c, c->getAggregations());
      UMLObjectList compList = findChildObjsInAssociations (c, c->getCompositions());
      UMLAssociationList associations = c->getSpecificAssocs(Uml::at_Association); // BAD! only way to get "general" associations.
      UMLObjectList assocList = findChildObjsInAssociations (c, associations);
      return aggList.count() > 0 || compList.count() > 0 || assocList.count() > 0;
}

00443 void XMLSchemaWriter::writeChildObjsInAssociation (UMLClassifier *c,
            UMLAssociationList assoc,
            QTextStream &XMLschema)
{

      UMLObjectList list = findChildObjsInAssociations (c, assoc);
      for(UMLObject * obj = list.first(); obj; obj = list.next())
      {
            UMLClassifier * thisClassifier = dynamic_cast<UMLClassifier*>(obj);
            if(thisClassifier)
                  writeClassifier(thisClassifier, XMLschema);
      }
}

00457 bool XMLSchemaWriter::hasBeenWritten(UMLClassifier *c) {
      if (writtenClassifiers.contains(c))
             return true;
      else
            return false;
}

00464 void XMLSchemaWriter::markAsWritten(UMLClassifier *c) {
      writtenClassifiers.append(c);
}

00468 void XMLSchemaWriter::writeAttributeDecls(UMLAttributeList &attribs, QTextStream &XMLschema )
{

      UMLAttribute *at;
      for(at=attribs.first(); at; at=attribs.next())
      {
            writeAttributeDecl(at,XMLschema);
      }

}

00479 void XMLSchemaWriter::writeAttributeDecl(UMLAttribute *attrib, QTextStream &XMLschema )
{

      QString documentation = attrib->getDoc();
      QString typeName = fixTypeName(attrib->getTypeName());
      bool isStatic = attrib->getStatic();
      QString initialValue = fixInitialStringDeclValue(attrib->getInitialValue(), typeName);

      if(!documentation.isEmpty())
            writeComment(documentation, XMLschema);

      XMLschema<<getIndent()<<"<"<<makeSchemaTag("attribute")
                  <<" name=\""<<cleanName(attrib->getName())<<"\""
                  <<" type=\""<<typeName<<"\"";

      // default value?
      if(!initialValue.isEmpty())
      {
            // IF its static, then we use "fixed", otherwise, we use "default" decl.
            // For the default decl, we _must_ use "optional" decl
            if(isStatic)
                  XMLschema<<" use=\"required\" fixed=\""<<initialValue<<"\"";
            else
                  XMLschema<<" use=\"optional\" default=\""<<initialValue<<"\"";
      }

      // finish decl
      XMLschema<<"/>"<<endl;

}

00510 void XMLSchemaWriter::writeAttributeGroupDecl (QString elementName, UMLAttributeList &attribs, QTextStream &XMLschema )
{

      if (attribs.count()> 0) {

            // write a little documentation
            writeComment("attributes for element "+elementName,XMLschema);

            // open attribute group
            XMLschema<<getIndent()<<"<"<<makeSchemaTag("attributeGroup")<<" name=\""<<elementName+"AttribGroupType"<<"\">"<<endl;

            indentLevel++;

            for( UMLAttribute *at=attribs.first(); at; at=attribs.next())
            {
                  writeAttributeDecl(at,XMLschema);
            }

            indentLevel--;

            // close attrib group node
            XMLschema<<getIndent()<<"</"<<makeSchemaTag("attributeGroup")<<">"<<endl;
      }
}

00535 void XMLSchemaWriter::writeComment(QString comment, QTextStream &XMLschema)
{
      // in the case we have several line comment..
      // NOTE: this part of the method has the problem of adopting UNIX newline,
      // need to resolve for using with MAC/WinDoze eventually I assume
      QString indent = getIndent();
      XMLschema<<indent<<"<!-- ";
      if (comment.contains(QRegExp("\n"))) {
            XMLschema<<endl;
            QStringList lines = QStringList::split( "\n", comment);
            for(uint i= 0; i < lines.count(); i++)
                  XMLschema<<indent<<"     "<<lines[i]<<endl;

            XMLschema<<indent<<"-->"<<endl;
      } else {
            // this should be more fancy in the future, breaking it up into 80 char
            // lines so that it doesnt look too bad
            XMLschema<<comment<<" -->"<<endl;
      }
}

// all that matters here is roleA, the role served by the children of this class
// in any composition or aggregation association. In full associations, I have only
// considered the case of "self" association, so it shouldnt matter if we use role A or
// B to find the child class as long as we dont use BOTH roles. I bet this will fail
// badly for someone using a plain association between 2 different classes. THAT should
// be done, but isnt yet (this is why I have left role b code in for now). -b.t.
00562 bool XMLSchemaWriter::writeAssociationDecls(UMLAssociationList associations,
            bool noRoleNameOK, bool didFirstOne, int id, QTextStream &XMLschema)
{

      if( !associations.isEmpty() )
      {
            bool printRoleA = false, printRoleB = false;

            for(UMLAssociation *a = associations.first(); a; a = associations.next())
            {
                  // it may seem counter intuitive, but you want to insert the role of the
                  // *other* class into *this* class.

                  if (a->getRoleId(A) == id && a->getVisibility(B) != Uml::Private)
                        printRoleB = true;

                  if (a->getRoleId(B) == id && a->getVisibility(A) != Uml::Private)
                        printRoleA = true;

                  // First: we insert documentaion for association IF it has either role
                  // AND some documentation (!)
                  if ((printRoleA || printRoleB) && !(a->getDoc().isEmpty()))
                        writeComment(a->getDoc(), XMLschema);

                  // opening for sequence
                  if(!didFirstOne && (printRoleA || printRoleB))
                  {
                        didFirstOne = true;
                        XMLschema<<getIndent()<<"<"<<makeSchemaTag("sequence")<<">"<<endl;
                        indentLevel++;
                  }

                  // print RoleB decl
                  /*
// As mentioned in the header comment for this method: this block of code is
// commented out for now as it will only be needed if/when plain associations
// between different classes are to be treated
                  if (printRoleB)
                  {
                        UMLClassifier *classifierB = dynamic_cast<UMLClassifier*>(a->getObjectB());
                        if (classifierB) {
                              // ONLY write out IF there is a rolename given
                              // otherwise its not meant to be declared
                              if (!a->getRoleNameB().isEmpty() || noRoleNameOK)
                                    writeAssociationRoleDecl(classifierB, a->getMultiB(), XMLschema);
                        }
                  }
                  */

                  // print RoleA decl
                  if (printRoleA)
                  {
                        UMLClassifier *classifierA = dynamic_cast<UMLClassifier*>(a->getObject(A));
                        if (classifierA) {
                              // ONLY write out IF there is a rolename given
                              // otherwise its not meant to be declared
                              if (!a->getRoleName(A).isEmpty() || noRoleNameOK )
                                    writeAssociationRoleDecl(classifierA, a->getMulti(A), XMLschema);
                        }
                  }
            }

      }

      return didFirstOne;
}

00629 UMLObjectList XMLSchemaWriter::findChildObjsInAssociations (UMLClassifier *c, UMLAssociationList associations)
{
      int id = c->getID();
      UMLObjectList list;
      for(UMLAssociation *a = associations.first(); a; a = associations.next())
      {
            if (a->getRoleId(A) == id
                        && a->getVisibility(B) != Uml::Private
                        && !a->getRoleName(B).isEmpty()
               )
                  list.append(a->getObject(B));

            if (a->getRoleId(B) == id
                        && a->getVisibility(A) != Uml::Private
                        && !a->getRoleName(A).isEmpty()
               )
                  list.append(a->getObject(A));
      }
      return list;
}

00650 void XMLSchemaWriter::writeAssociationRoleDecl( UMLClassifier *c, QString multi, QTextStream &XMLschema)
{

      bool isAbstract = c->getAbstract();
      bool isInterface = dynamic_cast<UMLInterface*>(c) ? true : false;

      QString elementName = getElementName(c);
      QString doc = c->getDoc();

      if (!doc.isEmpty())
            writeComment(doc, XMLschema);


      // Min/Max Occurs is based on whether it is this a single element
      // or a List (maxoccurs>1). One day this will be done correctly with special
      // multiplicity object that we dont have to figure out what it means via regex.
      QString minOccurs = "0";
      QString maxOccurs = "unbounded";
      if (multi.isEmpty())
      {
            // in this case, association will only specify ONE element can exist
            // as a child
            minOccurs = "1";
            maxOccurs = "1";
      }
      else
      {
            QStringList values = QStringList::split( QRegExp("[^\\d{1,}|\\*]"), multi);

            // could use some improvement here.. for sequences like "0..1,3..5,10" we
            // dont capture the whole "richness" of the multi. Instead we translate it
            // now to minOccurs="0" maxOccurs="10"
            if (values.count() > 0)
            {
                  // populate both with the actual value as long as our value isnt an asterix
                  // In that case, use special value (from above)
                  if(values[0].contains(QRegExp("\\d{1,}")))
                        minOccurs = values[0]; // use first number in sequence

                  if(values[values.count()-1].contains(QRegExp("\\d{1,}")))
                        maxOccurs = values[values.count()-1]; // use only last number in sequence
            }
      }

      // Now declare the class in the association as an element or group.
      //
      // In a semi-arbitrary way, we have decided to make abstract classes into
      // "groups" and concrete classes into "complexTypes".
      //
      // This is because about the only thing you can do with an abstract
      // class (err. node) is inherit from it with a "concrete" element. Therefore,
      // in this manner, we need a group node for abstract classes to lay out the child
      // element choices so that the child, concrete class may be plugged into whatever spot
      // it parent could go. The tradeoff is that "group" nodes may not be extended, so the
      // choices that you lay out here are it (e.g. no more nodes may inherit" from this group)
      //
      // The flipside for concrete classes is that we want to use them as elements in our document.
      // Unfortunately, about all you can do with complexTypes in terms of inheritance, is to
      // use these as the basis for a new node type. This is NOT full inheritence because the new
      // class (err. element node) wont be able to go into the document where it parent went without
      // you heavily editing the schema.
      //
      // Therefore, IF a group is abstract, but has no inheriting sub-classes, there are no choices, and its nigh
      // on pointless to declare it as a group, in this special case, abstract classes get declared
      // as complexTypes.
      //
      // Of course, in OO methodology, you should be able to inherit from
      // any class, but schema just dont allow use to have full inheritence using either groups
      // or complexTypes. Thus we have taken a middle rode. If someone wants to key me into a
      // better way to represent this, I'd be happy to listen. =b.t.
      //
      // UPDATE: partial solution to the above: as of 13-Mar-2003 we now write BOTH a complexType
      //         AND a group declaration for interfaces AND classes which are inherited from.
      //
      if ((isAbstract || isInterface ) && c->findSubClassConcepts().count() > 0)
            XMLschema<<getIndent()<<"<"<<makeSchemaTag("group")
                  <<" ref=\""<<makePackageTag(getElementGroupTypeName(c))<<"\"";
      else
            XMLschema<<getIndent()<<"<"<<makeSchemaTag("element")
                  <<" name=\""<<getElementName(c)<<"\""
                  <<" type=\""<<makePackageTag(getElementTypeName(c))<<"\"";

      // min/max occurs
      if (minOccurs != "1")
            XMLschema<<" minOccurs=\""<<minOccurs<<"\"";

      if (maxOccurs != "1")
            XMLschema<<" maxOccurs=\""<<maxOccurs<<"\"";

      // tidy up the node
      XMLschema<<"/>"<<endl;

}

// IF the type is "string" we need to declare it as
// the XMLSchema Object "String" (there is no string primative in XMLSchema).
// Same thing again for "bool" to "boolean"
00747 QString XMLSchemaWriter::fixTypeName(QString string)
{
//    string.replace(QRegExp("^string$"),schemaNamespaceTag+":string");
//    string.replace(QRegExp("^bool$"),schemaNamespaceTag+":boolean");
      string.prepend(schemaNamespaceTag+":");
      return string;
}

00755 QString XMLSchemaWriter::fixInitialStringDeclValue(QString value, QString type)
{
      // check for strings only
      if (!value.isEmpty() && type == "xs:string") {
            if (!value.startsWith("\""))
                  value.remove(0,1);
            if (!value.endsWith("\""))
                  value.remove(value.length(),1);
      }
      return value;
}

00767 QString XMLSchemaWriter::lowerFirstLetterCase(QString string)
{
      QChar firstChar = string.at(0);
      string.replace( 0, 1, firstChar.lower());
      return string;
}

00774 QString XMLSchemaWriter::getIndent ()
{
      QString myIndent = "";
      for (int i = 0 ; i < indentLevel ; i++)
            myIndent.append(indent);
      return myIndent;
}

00782 QString XMLSchemaWriter::getElementName(UMLClassifier *c)
{
      // return cleanName(lowerFirstLetterCase(c->getName()));
      return cleanName(c->getName());
}

00788 QString XMLSchemaWriter::getElementTypeName(UMLClassifier *c)
{
      QString elementName = getElementName(c);
      return elementName + "ComplexType";
}

00794 QString XMLSchemaWriter::getElementGroupTypeName(UMLClassifier *c)
{
      QString elementName = getElementName(c);
      return elementName + "GroupType";
}

00800 QString XMLSchemaWriter::makePackageTag (QString tagName) {
      tagName.prepend( packageNamespaceTag + ":");
      return tagName;
}

00805 QString XMLSchemaWriter::makeSchemaTag (QString tagName) {
      tagName.prepend( schemaNamespaceTag + ":");
      return tagName;
}

#include "xmlschemawriter.moc"

Generated by  Doxygen 1.6.0   Back to index