Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.impl » inst2xsd » [javadoc | source]

    1   /*   Copyright 2004 The Apache Software Foundation
    2    *
    3    *   Licensed under the Apache License, Version 2.0 (the "License");
    4    *   you may not use this file except in compliance with the License.
    5    *   You may obtain a copy of the License at
    6    *
    7    *       http://www.apache.org/licenses/LICENSE-2.0
    8    *
    9    *   Unless required by applicable law or agreed to in writing, software
   10    *   distributed under the License is distributed on an "AS IS" BASIS,
   11    *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12    *   See the License for the specific language governing permissions and
   13    *  limitations under the License.
   14    */
   15   package org.apache.xmlbeans.impl.inst2xsd;
   16   
   17   import org.apache.xmlbeans;
   18   import org.apache.xmlbeans.impl.common.PrefixResolver;
   19   import org.apache.xmlbeans.impl.common.ValidationContext;
   20   import org.apache.xmlbeans.impl.common.XmlWhitespace;
   21   import org.apache.xmlbeans.impl.inst2xsd.util.Attribute;
   22   import org.apache.xmlbeans.impl.inst2xsd.util.Element;
   23   import org.apache.xmlbeans.impl.inst2xsd.util.TypeSystemHolder;
   24   import org.apache.xmlbeans.impl.inst2xsd.util.Type;
   25   import org.apache.xmlbeans.impl.util.XsTypeConverter;
   26   import org.apache.xmlbeans.impl.values;
   27   
   28   import javax.xml.namespace.QName;
   29   import java.util;
   30   
   31   /**
   32    * @author Cezar Andrei ( cezar.andrei at bea.com )
   33    * Date: Jul 26, 2004
   34    */
   35   public class RussianDollStrategy
   36       implements XsdGenStrategy
   37   {
   38       static final String _xsi         = "http://www.w3.org/2001/XMLSchema-instance";
   39   
   40       static final QName _xsiNil          = new QName( _xsi, "nil", "xsi" );
   41       static final QName _xsiType         = new QName( _xsi, "type", "xsi" );
   42   
   43       public void processDoc(XmlObject[] instances, Inst2XsdOptions options, TypeSystemHolder typeSystemHolder)
   44       {
   45           for (int i = 0; i < instances.length; i++)
   46           {
   47               XmlObject instance = instances[i];
   48               XmlCursor xc = instance.newCursor();
   49               // xc on start doc
   50   
   51               StringBuffer comment = new StringBuffer();
   52   
   53               while( !xc.isStart() )
   54               {
   55                   xc.toNextToken();
   56                   if( xc.isComment() )
   57                       comment.append(xc.getTextValue());
   58                   else if (xc.isEnddoc())
   59                       return;
   60               }
   61               // xc now on the root element
   62   
   63               Element withElem = processElement(xc, comment.toString(), options, typeSystemHolder);
   64               withElem.setGlobal(true);
   65   
   66               addGlobalElement(withElem, typeSystemHolder, options);
   67           }
   68       }
   69   
   70       protected Element addGlobalElement(Element withElem, TypeSystemHolder typeSystemHolder, Inst2XsdOptions options)
   71       {
   72           assert withElem.isGlobal();
   73           Element intoElem = typeSystemHolder.getGlobalElement(withElem.getName());
   74   
   75           if (intoElem==null)
   76           {
   77               typeSystemHolder.addGlobalElement(withElem);
   78               return withElem;
   79           }
   80           else
   81           {
   82               combineTypes(intoElem.getType(), withElem.getType(), options);
   83               combineElementComments(intoElem, withElem);
   84               return intoElem;
   85           }
   86       }
   87   
   88       protected Element processElement(XmlCursor xc, String comment,
   89           Inst2XsdOptions options, TypeSystemHolder typeSystemHolder)
   90       {
   91           assert xc.isStart();
   92           Element element = new Element();
   93           element.setName(xc.getName());
   94           element.setGlobal(false);
   95   
   96           Type elemType = Type.createUnnamedType(Type.SIMPLE_TYPE_SIMPLE_CONTENT); //assume simple, set later
   97           element.setType(elemType);
   98   
   99           StringBuffer textBuff = new StringBuffer();
  100           StringBuffer commentBuff = new StringBuffer();
  101           List children = new ArrayList();
  102           List attributes = new ArrayList();
  103   
  104           loop: do
  105           {
  106               XmlCursor.TokenType tt = xc.toNextToken();
  107               switch (tt.intValue())
  108               {
  109                   case XmlCursor.TokenType.INT_ATTR:
  110                       // todo check for xsi:type
  111                       // ignore xsi:... attributes other than xsi:nil
  112                       QName attName = xc.getName();
  113                       if (!_xsiNil.getNamespaceURI().equals(attName.getNamespaceURI()))
  114                           attributes.add(processAttribute(xc, options, element.getName().getNamespaceURI(), typeSystemHolder));
  115                       else if (_xsiNil.equals(attName))
  116                           element.setNillable(true);
  117   
  118                       break;
  119   
  120                   case XmlCursor.TokenType.INT_START:
  121                       children.add(processElement(xc, commentBuff.toString(), options, typeSystemHolder));
  122                       commentBuff.delete(0, commentBuff.length());
  123                       break;
  124   
  125                   case XmlCursor.TokenType.INT_TEXT:
  126                       textBuff.append(xc.getChars());
  127                       break;
  128   
  129                   case XmlCursor.TokenType.INT_COMMENT:
  130                       commentBuff.append(xc.getTextValue());
  131                       break;
  132   
  133                   case XmlCursor.TokenType.INT_NAMESPACE:
  134                       // ignore,
  135                       // each element and attribute will take care to define itself in the right targetNamespace
  136                       break;
  137   
  138                   case XmlCursor.TokenType.INT_END:
  139                       break loop;
  140   
  141                   case XmlCursor.TokenType.INT_PROCINST:
  142                       // ignore
  143                       break;
  144   
  145                   case XmlCursor.TokenType.INT_ENDDOC:
  146                       break loop;
  147   
  148                   case XmlCursor.TokenType.INT_NONE:
  149                       break loop;
  150   
  151                   case XmlCursor.TokenType.INT_STARTDOC:
  152                       throw new IllegalStateException();
  153   
  154                   default:
  155                       throw new IllegalStateException("Unknown TokenType.");
  156               }
  157           }
  158           while( true );
  159   
  160           String collapsedText =  XmlWhitespace.collapse(textBuff.toString(), XmlWhitespace.WS_COLLAPSE);
  161   
  162           String commnetStr = (comment == null ?
  163               ( commentBuff.length() == 0 ? null : commentBuff.toString() ) :
  164               ( commentBuff.length() == 0 ? comment : commentBuff.insert(0, comment).toString()) );
  165           element.setComment(commnetStr);
  166   
  167           if (children.size()>0)
  168           {
  169               // complex content
  170               if (collapsedText.length()>0)
  171               {
  172                   elemType.setContentType(Type.COMPLEX_TYPE_MIXED_CONTENT);
  173               }
  174               else
  175               {
  176                   elemType.setContentType(Type.COMPLEX_TYPE_COMPLEX_CONTENT);
  177               }
  178               processElementsInComplexType(elemType, children, element.getName().getNamespaceURI(), typeSystemHolder, options);
  179               processAttributesInComplexType(elemType, attributes);
  180           }
  181           else
  182           {
  183               // simple content
  184               // hack workaround for being able to call xc.getNamespaceForPrefix()
  185               XmlCursor xcForNamespaces = xc.newCursor();
  186               xcForNamespaces.toParent();
  187   
  188               if (attributes.size()>0)
  189               {
  190                   elemType.setContentType(Type.COMPLEX_TYPE_SIMPLE_CONTENT);
  191   
  192                   Type extendedType = Type.createNamedType(
  193                       processSimpleContentType(textBuff.toString(), options, xcForNamespaces), Type.SIMPLE_TYPE_SIMPLE_CONTENT);
  194                   elemType.setExtensionType(extendedType);
  195   
  196                   processAttributesInComplexType(elemType, attributes);
  197               }
  198               else
  199               {
  200                   elemType.setContentType(Type.SIMPLE_TYPE_SIMPLE_CONTENT);
  201                   elemType.setName(processSimpleContentType(textBuff.toString(), options, xcForNamespaces));
  202   
  203                   // add enumeration value
  204                   String enumValue = XmlString.type.getName().equals(elemType.getName()) ? textBuff.toString() : collapsedText;
  205                   elemType.addEnumerationValue(enumValue, xcForNamespaces);
  206               }
  207   
  208               xcForNamespaces.dispose(); // end hack
  209           }
  210   
  211           checkIfReferenceToGlobalTypeIsNeeded( element, typeSystemHolder, options);
  212   
  213           return element;
  214       }
  215   
  216       protected void processElementsInComplexType(Type elemType, List children, String parentNamespace,
  217           TypeSystemHolder typeSystemHolder, Inst2XsdOptions options)
  218       {
  219           Map elemNamesToElements = new HashMap();
  220           Element currentElem = null;
  221   
  222           for (Iterator iterator = children.iterator(); iterator.hasNext();)
  223           {
  224               Element child = (Element) iterator.next();
  225   
  226               if (currentElem==null)
  227               {   // first element in this type
  228                   checkIfElementReferenceIsNeeded(child, parentNamespace, typeSystemHolder, options);
  229                   elemType.addElement(child);
  230                   elemNamesToElements.put(child.getName(), child);
  231                   currentElem = child;
  232                   continue;
  233               }
  234   
  235               if (currentElem.getName()==child.getName())
  236               {   // same contiguos element
  237                   combineTypes(currentElem.getType(), child.getType(), options); // unify types
  238                   combineElementComments(currentElem, child);
  239                   // minOcc=0 maxOcc=unbounded
  240                   currentElem.setMinOccurs(0);
  241                   currentElem.setMaxOccurs(Element.UNBOUNDED);
  242               }
  243               else
  244               {
  245                   Element sameElem = (Element)elemNamesToElements.get(child.getName());
  246                   if (sameElem==null)
  247                   {   // new element name
  248                       checkIfElementReferenceIsNeeded(child, parentNamespace, typeSystemHolder, options);
  249                       elemType.addElement(child);
  250                       elemNamesToElements.put(child.getName(), child);
  251                   }
  252                   else
  253                   {   //same non contiguos
  254                       combineTypes(currentElem.getType(), child.getType(), options);
  255                       combineElementComments(currentElem, child);
  256                       elemType.setTopParticleForComplexOrMixedContent(Type.PARTICLE_CHOICE_UNBOUNDED);
  257                   }
  258                   currentElem = child;
  259               }
  260           }
  261       }
  262   
  263       protected void checkIfElementReferenceIsNeeded(Element child, String parentNamespace,
  264           TypeSystemHolder typeSystemHolder, Inst2XsdOptions options)
  265       {
  266           if (!child.getName().getNamespaceURI().equals(parentNamespace))
  267           {
  268               Element referencedElem = new Element();
  269               referencedElem.setGlobal(true);
  270               referencedElem.setName(child.getName());
  271               referencedElem.setType(child.getType());
  272   
  273               if (child.isNillable())
  274               {
  275                   referencedElem.setNillable(true);
  276                   child.setNillable(false);
  277               }
  278   
  279               referencedElem = addGlobalElement(referencedElem, typeSystemHolder, options);
  280   
  281               child.setRef(referencedElem); // clears child's type
  282           }
  283       }
  284   
  285       protected void checkIfReferenceToGlobalTypeIsNeeded(Element elem, TypeSystemHolder typeSystemHolder,
  286           Inst2XsdOptions options)
  287       {
  288           // RussianDollDesign doesn't define global types
  289       }
  290   
  291       protected void processAttributesInComplexType(Type elemType, List attributes)
  292       {
  293           assert elemType.isComplexType();
  294           for (Iterator iterator = attributes.iterator(); iterator.hasNext();)
  295           {
  296               Attribute att = (Attribute) iterator.next();
  297               elemType.addAttribute(att);
  298           }
  299       }
  300   
  301       protected Attribute processAttribute(XmlCursor xc, Inst2XsdOptions options, String parentNamespace,
  302                                                 TypeSystemHolder typeSystemHolder)
  303       {
  304           assert xc.isAttr() : "xc not on attribute";
  305           Attribute attribute = new Attribute();
  306           QName attName = xc.getName();
  307   
  308           attribute.setName(attName);
  309   
  310           XmlCursor parent = xc.newCursor();
  311           parent.toParent();
  312   
  313           Type simpleContentType = Type.createNamedType(
  314               processSimpleContentType(xc.getTextValue(), options, parent), Type.SIMPLE_TYPE_SIMPLE_CONTENT);
  315   
  316           parent.dispose();
  317   
  318           attribute.setType(simpleContentType);
  319   
  320           checkIfAttributeReferenceIsNeeded(attribute, parentNamespace, typeSystemHolder);
  321   
  322           return attribute;
  323       }
  324   
  325       protected void checkIfAttributeReferenceIsNeeded(Attribute attribute, String parentNamespace, TypeSystemHolder typeSystemHolder)
  326       {
  327           if (!attribute.getName().getNamespaceURI().equals("") &&
  328               !attribute.getName().getNamespaceURI().equals(parentNamespace))
  329           {
  330               // make attribute be a reference to a top level attribute in a different targetNamespace
  331               Attribute referencedAtt = new Attribute();
  332               referencedAtt.setGlobal(true);
  333               referencedAtt.setName(attribute.getName());
  334               referencedAtt.setType(attribute.getType());
  335   
  336               typeSystemHolder.addGlobalAttribute(referencedAtt);
  337   
  338               attribute.setRef(referencedAtt);
  339           }
  340       }
  341   
  342       protected class SCTValidationContext
  343           implements ValidationContext
  344       {
  345           protected boolean valid = true;
  346   
  347           public boolean isValid()
  348           {
  349               return valid;
  350           }
  351   
  352           public void resetToValid()
  353           {
  354               valid = true;
  355           }
  356   
  357           public void invalid(String message)
  358           {
  359               valid = false;
  360           }
  361   
  362           public void invalid(String code, Object[] args)
  363           {
  364               valid = false;
  365           }
  366       }
  367   
  368       private SCTValidationContext _validationContext = new SCTValidationContext();
  369   
  370   
  371       // List of precedence for smart simple primitive type determination
  372       // byte, short, int, long, integer, float, double, decimal,
  373       // boolean
  374       // date, dateTime, time, gDuration,
  375       // QName ?,
  376       // anyUri ? - triggered only for http:// or www. constructs,
  377       // list types ?
  378       // string
  379       protected QName processSimpleContentType(String lexicalValue, Inst2XsdOptions options, final XmlCursor xc)
  380       {
  381           // check options and return xsd:string or if smart is enabled, look for a better type
  382           if (options.getSimpleContentTypes()==Inst2XsdOptions.SIMPLE_CONTENT_TYPES_STRING)
  383               return XmlString.type.getName();
  384   
  385           if (options.getSimpleContentTypes()!=Inst2XsdOptions.SIMPLE_CONTENT_TYPES_SMART)
  386               throw new IllegalArgumentException("Unknown value for Inst2XsdOptions.getSimpleContentTypes() :" + options.getSimpleContentTypes());
  387   
  388           // Inst2XsdOptions.SIMPLE_CONTENT_TYPES_SMART case
  389   
  390   
  391           try
  392           {
  393               XsTypeConverter.lexByte(lexicalValue);
  394               return XmlByte.type.getName();
  395           }
  396           catch (Exception e) {}
  397   
  398           try
  399           {
  400               XsTypeConverter.lexShort(lexicalValue);
  401               return XmlShort.type.getName();
  402           }
  403           catch (Exception e) {}
  404   
  405           try
  406           {
  407               XsTypeConverter.lexInt(lexicalValue);
  408               return XmlInt.type.getName();
  409           }
  410           catch (Exception e) {}
  411   
  412           try
  413           {
  414               XsTypeConverter.lexLong(lexicalValue);
  415               return XmlLong.type.getName();
  416           }
  417           catch (Exception e) {}
  418   
  419           try
  420           {
  421               XsTypeConverter.lexInteger(lexicalValue);
  422               return XmlInteger.type.getName();
  423           }
  424           catch (Exception e) {}
  425   
  426           try
  427           {
  428               XsTypeConverter.lexFloat(lexicalValue);
  429               return XmlFloat.type.getName();
  430           }
  431           catch (Exception e) {}
  432   
  433   //        // this not needed because it's lexical space is covered by float
  434   //        try
  435   //        {
  436   //            XsTypeConverter.lexDouble(lexicalValue);
  437   //            return XmlDouble.type.getName();
  438   //        }
  439   //        catch (Exception e) {}
  440   //
  441   //        try
  442   //        {
  443   //            XsTypeConverter.lexDecimal(lexicalValue);
  444   //            return XmlDecimal.type.getName();
  445   //        }
  446   //        catch (Exception e) {}
  447   
  448           XmlDateImpl.validateLexical(lexicalValue, XmlDate.type, _validationContext);
  449           if (_validationContext.isValid())
  450               return XmlDate.type.getName();
  451           _validationContext.resetToValid();
  452   
  453           XmlDateTimeImpl.validateLexical(lexicalValue, XmlDateTime.type, _validationContext);
  454           if (_validationContext.isValid())
  455               return XmlDateTime.type.getName();
  456           _validationContext.resetToValid();
  457   
  458           XmlTimeImpl.validateLexical(lexicalValue, XmlTime.type, _validationContext);
  459           if (_validationContext.isValid())
  460               return XmlTime.type.getName();
  461           _validationContext.resetToValid();
  462   
  463           XmlDurationImpl.validateLexical(lexicalValue, XmlDuration.type, _validationContext);
  464           if (_validationContext.isValid())
  465               return XmlDuration.type.getName();
  466           _validationContext.resetToValid();
  467   
  468           // check for uri
  469           if (lexicalValue.startsWith("http://") || lexicalValue.startsWith("www."))
  470           {
  471               XmlAnyUriImpl.validateLexical(lexicalValue, _validationContext);
  472               if (_validationContext.isValid())
  473                   return XmlAnyURI.type.getName();
  474               _validationContext.resetToValid();
  475           }
  476   
  477           // check for QName
  478           int idx = lexicalValue.indexOf(':');
  479           if (idx>=0 && idx==lexicalValue.lastIndexOf(':') && idx+1<lexicalValue.length())
  480           {
  481               PrefixResolver prefixResolver = new PrefixResolver()
  482               {
  483                   public String getNamespaceForPrefix(String prefix)
  484                   {  return xc.namespaceForPrefix(prefix); }
  485               };
  486   
  487               QName qname = XmlQNameImpl.validateLexical(lexicalValue, _validationContext, prefixResolver);
  488               if (_validationContext.isValid())
  489                   return XmlQName.type.getName();
  490               _validationContext.resetToValid();
  491           }
  492   
  493           //the check for lists is probably too expensive
  494   
  495           return XmlString.type.getName();
  496       }
  497   
  498   
  499       protected void combineTypes(Type into, Type with, Inst2XsdOptions options)
  500       {
  501           if (into==with)
  502               return;
  503   
  504           if (into.isGlobal() && with.isGlobal() && into.getName().equals(with.getName()))
  505               return;
  506   
  507   
  508           if (into.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT &&
  509               with.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT)
  510           {
  511               combineSimpleTypes(into, with, options);
  512               return;
  513           }
  514   
  515           if ((into.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT ||
  516               into.getContentType()==Type.COMPLEX_TYPE_SIMPLE_CONTENT) &&
  517               (with.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT ||
  518               with.getContentType()==Type.COMPLEX_TYPE_SIMPLE_CONTENT) )
  519           {
  520               // take the extension name if it's a complex type
  521               QName intoTypeName = into.isComplexType() ? into.getExtensionType().getName() : into.getName();
  522               QName withTypeName = with.isComplexType() ? with.getExtensionType().getName() : with.getName();
  523   
  524               //complex type simple content
  525               into.setContentType(Type.COMPLEX_TYPE_SIMPLE_CONTENT);
  526   
  527               QName moreGeneralTypeName = combineToMoreGeneralSimpleType(intoTypeName, withTypeName);
  528               if (into.isComplexType())
  529               {
  530                   Type extendedType = Type.createNamedType(moreGeneralTypeName, Type.SIMPLE_TYPE_SIMPLE_CONTENT);
  531                   into.setExtensionType(extendedType);
  532               }
  533               else
  534                   into.setName(moreGeneralTypeName);
  535   
  536               combineAttributesOfTypes(into, with);
  537               return;
  538           }
  539   
  540           if (into.getContentType()==Type.COMPLEX_TYPE_COMPLEX_CONTENT &&
  541               with.getContentType()==Type.COMPLEX_TYPE_COMPLEX_CONTENT)
  542           {
  543               combineAttributesOfTypes(into, with);
  544               combineElementsOfTypes(into, with, false, options);
  545               return;
  546           }
  547   
  548           if (into.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT ||
  549               into.getContentType()==Type.COMPLEX_TYPE_SIMPLE_CONTENT ||
  550               with.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT ||
  551               with.getContentType()==Type.COMPLEX_TYPE_SIMPLE_CONTENT)
  552           {
  553               into.setContentType(Type.COMPLEX_TYPE_MIXED_CONTENT);
  554               combineAttributesOfTypes(into, with);
  555               combineElementsOfTypes(into, with, true, options);
  556               return;
  557           }
  558   
  559           if ((into.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT ||
  560               into.getContentType()==Type.COMPLEX_TYPE_SIMPLE_CONTENT ||
  561               into.getContentType()==Type.COMPLEX_TYPE_COMPLEX_CONTENT ||
  562               into.getContentType()==Type.COMPLEX_TYPE_MIXED_CONTENT) &&
  563               (with.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT ||
  564               with.getContentType()==Type.COMPLEX_TYPE_SIMPLE_CONTENT ||
  565               with.getContentType()==Type.COMPLEX_TYPE_COMPLEX_CONTENT ||
  566               with.getContentType()==Type.COMPLEX_TYPE_MIXED_CONTENT) )
  567           {
  568               into.setContentType(Type.COMPLEX_TYPE_MIXED_CONTENT);
  569               combineAttributesOfTypes(into, with);
  570               combineElementsOfTypes(into, with, false, options);
  571               return;
  572           }
  573   
  574           throw new IllegalArgumentException("Unknown content type.");
  575       }
  576   
  577       protected void combineSimpleTypes(Type into, Type with, Inst2XsdOptions options)
  578       {
  579           assert (into.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT &&
  580               with.getContentType()==Type.SIMPLE_TYPE_SIMPLE_CONTENT) : "Invalid arguments";
  581   
  582           //simple type simple content
  583           into.setName(combineToMoreGeneralSimpleType(into.getName(), with.getName()));
  584   
  585           // take care of enumeration values
  586           if (options.isUseEnumerations())
  587           {
  588               into.addAllEnumerationsFrom(with);
  589   
  590               if (into.getEnumerationValues().size()>options.getUseEnumerations())
  591               {
  592                   into.closeEnumeration();
  593               }
  594           }
  595       }
  596   
  597       protected QName combineToMoreGeneralSimpleType(QName t1, QName t2)
  598       {
  599           if (t1.equals(t2))
  600               return t1;
  601   
  602           if (t2.equals(XmlShort.type.getName()) && t1.equals(XmlByte.type.getName()))
  603               return t2;
  604           if (t1.equals(XmlShort.type.getName()) && t2.equals(XmlByte.type.getName()))
  605               return t1;
  606   
  607           if (t2.equals(XmlInt.type.getName()) &&
  608               (t1.equals(XmlShort.type.getName()) || t1.equals(XmlByte.type.getName())) )
  609               return t2;
  610           if (t1.equals(XmlInt.type.getName()) &&
  611               (t2.equals(XmlShort.type.getName()) || t2.equals(XmlByte.type.getName())) )
  612               return t1;
  613   
  614           if (t2.equals(XmlLong.type.getName()) &&
  615               (t1.equals(XmlInt.type.getName()) || t1.equals(XmlShort.type.getName()) || t1.equals(XmlByte.type.getName())) )
  616               return t2;
  617           if (t1.equals(XmlLong.type.getName()) &&
  618               (t2.equals(XmlInt.type.getName()) || t2.equals(XmlShort.type.getName()) || t2.equals(XmlByte.type.getName())) )
  619               return t1;
  620   
  621           if (t2.equals(XmlInteger.type.getName()) &&
  622               (t1.equals(XmlLong.type.getName()) || t1.equals(XmlInt.type.getName()) ||
  623               t1.equals(XmlShort.type.getName()) || t1.equals(XmlByte.type.getName())) )
  624               return t2;
  625           if (t1.equals(XmlInteger.type.getName()) &&
  626               (t2.equals(XmlLong.type.getName()) || t2.equals(XmlInt.type.getName()) ||
  627               t2.equals(XmlShort.type.getName()) || t2.equals(XmlByte.type.getName())) )
  628               return t1;
  629   
  630           if (t2.equals(XmlFloat.type.getName()) &&
  631               (t1.equals(XmlInteger.type.getName()) ||
  632               t1.equals(XmlLong.type.getName()) || t1.equals(XmlInt.type.getName()) ||
  633               t1.equals(XmlShort.type.getName()) || t1.equals(XmlByte.type.getName())) )
  634               return t2;
  635           if (t1.equals(XmlFloat.type.getName()) &&
  636               (t2.equals(XmlInteger.type.getName()) ||
  637               t2.equals(XmlLong.type.getName()) || t2.equals(XmlInt.type.getName()) ||
  638               t2.equals(XmlShort.type.getName()) || t2.equals(XmlByte.type.getName())) )
  639               return t1;
  640   
  641           //double, decimal will never get here since they don't get generated
  642   
  643           //the rest of the combinations are not compatible, so they will combine in xsd:string
  644           return XmlString.type.getName();
  645       }
  646   
  647       protected void combineAttributesOfTypes(Type into, Type from)
  648       {
  649           // loop through attributes: add fromAtt if they don't exist, combine them if they exist
  650           outterLoop:
  651           for (int i = 0; i < from.getAttributes().size(); i++)
  652           {
  653               Attribute fromAtt = (Attribute)from.getAttributes().get(i);
  654               for (int j = 0; j < into.getAttributes().size(); j++)
  655               {
  656                   Attribute intoAtt = (Attribute)into.getAttributes().get(j);
  657                   if (intoAtt.getName().equals(fromAtt.getName()))
  658                   {
  659                       intoAtt.getType().setName(
  660                           combineToMoreGeneralSimpleType(intoAtt.getType().getName(), fromAtt.getType().getName()));
  661                       continue outterLoop;
  662                   }
  663               }
  664               // fromAtt doesn't exist in into type, will add it right now
  665               into.addAttribute(fromAtt);
  666           }
  667   
  668           //optional attributes: if there are atts in into that are not in from, make them optional
  669           outterLoop:
  670           for (int i = 0; i < into.getAttributes().size(); i++)
  671           {
  672               Attribute intoAtt = (Attribute)into.getAttributes().get(i);
  673               for (int j = 0; j < from.getAttributes().size(); j++)
  674               {
  675                   Attribute fromAtt = (Attribute)from.getAttributes().get(j);
  676                   if (fromAtt.getName().equals(intoAtt.getName()))
  677                   {
  678                       continue;
  679                   }
  680               }
  681               // intoAtt doesn't exist in into type, will add it right now
  682               intoAtt.setOptional(true);
  683           }
  684       }
  685   
  686       protected void combineElementsOfTypes(Type into, Type from, boolean makeElementsOptional, Inst2XsdOptions options)
  687       {
  688           boolean needsUnboundedChoice = false;
  689   
  690           if (into.getTopParticleForComplexOrMixedContent()!=Type.PARTICLE_SEQUENCE ||
  691               from.getTopParticleForComplexOrMixedContent()!=Type.PARTICLE_SEQUENCE)
  692               needsUnboundedChoice = true;
  693   
  694           List res = new ArrayList();
  695   
  696           int fromStartingIndex = 0;
  697           int fromMatchedIndex = -1;
  698           int intoMatchedIndex = -1;
  699   
  700           // for each element in into
  701           for (int i = 0; !needsUnboundedChoice && i < into.getElements().size(); i++)
  702           {
  703               // try to find one with same name in from
  704               Element intoElement = (Element) into.getElements().get(i);
  705               for (int j = fromStartingIndex; j < from.getElements().size(); j++)
  706               {
  707                   Element fromElement = (Element) from.getElements().get(j);
  708                   if (intoElement.getName().equals(fromElement.getName()))
  709                   {
  710                       fromMatchedIndex = j;
  711                       break;
  712                   }
  713               }
  714   
  715               // if not found, it's safe to add this one to result 'res' (as optional) and continue
  716               if ( fromMatchedIndex < fromStartingIndex )
  717               {
  718                   res.add(intoElement);
  719                   intoElement.setMinOccurs(0);
  720                   continue;
  721               }
  722   
  723               // else try out all from elemens between fromStartingIndex to fromMatchedIndex
  724               // to see if they match one of the into elements
  725               intoMatchingLoop:
  726               for (int j2 = fromStartingIndex; j2 < fromMatchedIndex; j2++)
  727               {
  728                   Element fromCandidate = (Element) from.getElements().get(j2);
  729   
  730                   for (int i2 = i+1; i2 < into.getElements().size(); i2++)
  731                   {
  732                       Element intoCandidate = (Element) into.getElements().get(i2);
  733                       if (fromCandidate.getName().equals(intoCandidate.getName()))
  734                       {
  735                           intoMatchedIndex = i2;
  736                           break intoMatchingLoop;
  737                       }
  738                   }
  739               }
  740   
  741               if (intoMatchedIndex<i)
  742               {
  743                   // if none matched they are safe to be added to res as optional
  744                   for (int j3 = fromStartingIndex; j3 < fromMatchedIndex; j3++)
  745                   {
  746                       Element fromCandidate = (Element) from.getElements().get(j3);
  747                       res.add(fromCandidate);
  748                       fromCandidate.setMinOccurs(0);
  749                   }
  750                   // also since into[i] == from[fromMatchedIndex] add it only once
  751                   res.add(intoElement);
  752                   Element fromMatchedElement = (Element)from.getElements().get(fromMatchedIndex);
  753   
  754                   if (fromMatchedElement.getMinOccurs()<=0)
  755                       intoElement.setMinOccurs(0);
  756                   if (fromMatchedElement.getMaxOccurs()==Element.UNBOUNDED)
  757                       intoElement.setMaxOccurs(Element.UNBOUNDED);
  758   
  759                   combineTypes(intoElement.getType(), fromMatchedElement.getType(), options);
  760                   combineElementComments(intoElement, fromMatchedElement);
  761   
  762                   fromStartingIndex = fromMatchedIndex + 1;
  763                   continue;
  764               }
  765               else
  766               {
  767                   // if matched it means into type will transform into a choice unbounded type
  768                   needsUnboundedChoice = true;
  769               }
  770           }
  771   
  772           for (int j = fromStartingIndex; j < from.getElements().size(); j++)
  773           {
  774               Element remainingFromElement = (Element) from.getElements().get(j);
  775               res.add(remainingFromElement);
  776               remainingFromElement.setMinOccurs(0);
  777           }
  778   
  779           // if choice was detected
  780           if (needsUnboundedChoice)
  781           {
  782               into.setTopParticleForComplexOrMixedContent(Type.PARTICLE_CHOICE_UNBOUNDED);
  783   
  784               outterLoop:
  785               for (int j = 0; j < from.getElements().size(); j++)
  786               {
  787                   Element fromElem = (Element) from.getElements().get(j);
  788                   for (int i = 0; i < into.getElements().size(); i++)
  789                   {
  790                       Element intoElem = (Element)into.getElements().get(i);
  791                       intoElem.setMinOccurs(1);
  792                       intoElem.setMaxOccurs(1);
  793   
  794                       if (intoElem==fromElem)
  795                           continue outterLoop;
  796   
  797                       if (intoElem.getName().equals(fromElem.getName()))
  798                       {
  799                           combineTypes(intoElem.getType(), fromElem.getType(), options);
  800                           combineElementComments(intoElem, fromElem);
  801   
  802                           continue outterLoop;
  803                       }
  804                   }
  805   
  806                   // fromElem doesn't exist in into type, will add it right now
  807                   into.addElement(fromElem);
  808                   fromElem.setMinOccurs(1);
  809                   fromElem.setMaxOccurs(1);
  810               }
  811               return;
  812           }
  813           else
  814           {
  815               // into remains sequence but will contain the new list of elements res
  816               into.setElements(res);
  817               return;
  818           }
  819       }
  820   
  821       protected void combineElementComments(Element into, Element with)
  822       {
  823           if (with.getComment()!=null && with.getComment().length()>0)
  824           {
  825               if (into.getComment()==null)
  826                   into.setComment(with.getComment());
  827               else
  828                   into.setComment(into.getComment() + with.getComment());
  829           }
  830       }
  831   }

Home » xmlbeans-2.5.0-src » org.apache.xmlbeans.impl » inst2xsd » [javadoc | source]