docs: protected static CmsXmlComplexTypeSequence validateComplexTypeSequence(
          Element element,
          Set<CmsXmlContentDefinition> includes)
      throws CmsXmlException {
  
          validateAttributesExists(element, new String[] {XSD_ATTRIBUTE_NAME}, new String[0]);
  
          String name = validateAttribute(element, XSD_ATTRIBUTE_NAME, null);
  
          // now check the type definition list
          List<Element> mainElements = CmsXmlGenericWrapper.elements(element);
          if ((mainElements.size() != 1) && (mainElements.size() != 2)) {
              throw new CmsXmlException(
                  Messages.get().container(
                      Messages.ERR_TS_SUBELEMENT_COUNT_2,
                      element.getUniquePath(),
                      new Integer(mainElements.size())));
          }
  
          boolean hasLanguageAttribute = false;
          if (mainElements.size() == 2) {
              // two elements in the master list: the second must be the "language" attribute definition
  
              Element typeAttribute = mainElements.get(1);
              if (!XSD_NODE_ATTRIBUTE.equals(typeAttribute.getQName())) {
                  throw new CmsXmlException(
                      Messages.get().container(
                          Messages.ERR_CD_ELEMENT_NAME_3,
                          typeAttribute.getUniquePath(),
                          XSD_NODE_ATTRIBUTE.getQualifiedName(),
                          typeAttribute.getQName().getQualifiedName()));
              }
              validateAttribute(typeAttribute, XSD_ATTRIBUTE_NAME, XSD_ATTRIBUTE_VALUE_LANGUAGE);
              validateAttribute(typeAttribute, XSD_ATTRIBUTE_TYPE, CmsXmlLocaleValue.TYPE_NAME);
              try {
                  validateAttribute(typeAttribute, XSD_ATTRIBUTE_USE, XSD_ATTRIBUTE_VALUE_REQUIRED);
              } catch (CmsXmlException e) {
                  validateAttribute(typeAttribute, XSD_ATTRIBUTE_USE, XSD_ATTRIBUTE_VALUE_OPTIONAL);
              }
              // no error: then the language attribute is valid
              hasLanguageAttribute = true;
          }
  
          // the type of the sequence
          SequenceType sequenceType;
          int choiceMaxOccurs = 0;
  
          // check the main element type sequence
          Element typeSequenceElement = mainElements.get(0);
          if (!XSD_NODE_SEQUENCE.equals(typeSequenceElement.getQName())) {
              if (!XSD_NODE_CHOICE.equals(typeSequenceElement.getQName())) {
                  throw new CmsXmlException(
                      Messages.get().container(
                          Messages.ERR_CD_ELEMENT_NAME_4,
                          new Object[] {
                              typeSequenceElement.getUniquePath(),
                              XSD_NODE_SEQUENCE.getQualifiedName(),
                              XSD_NODE_CHOICE.getQualifiedName(),
                              typeSequenceElement.getQName().getQualifiedName()}));
              } else {
                  // this is a xsd:choice, check if this is single or multiple choice
                  String minOccursStr = typeSequenceElement.attributeValue(XSD_ATTRIBUTE_MIN_OCCURS);
                  int minOccurs = 1;
                  if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(minOccursStr)) {
                      try {
                          minOccurs = Integer.parseInt(minOccursStr.trim());
                      } catch (NumberFormatException e) {
                          throw new CmsXmlException(
                              Messages.get().container(
                                  Messages.ERR_EL_BAD_ATTRIBUTE_3,
                                  element.getUniquePath(),
                                  XSD_ATTRIBUTE_MIN_OCCURS,
                                  minOccursStr == null ? "1" : minOccursStr));
                      }
                  }
                  String maxOccursStr = typeSequenceElement.attributeValue(XSD_ATTRIBUTE_MAX_OCCURS);
                  choiceMaxOccurs = 1;
                  if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(maxOccursStr)) {
                      if (CmsXmlContentDefinition.XSD_ATTRIBUTE_VALUE_UNBOUNDED.equals(maxOccursStr.trim())) {
                          choiceMaxOccurs = Integer.MAX_VALUE;
                      } else {
                          try {
                              choiceMaxOccurs = Integer.parseInt(maxOccursStr.trim());
                          } catch (NumberFormatException e) {
                              throw new CmsXmlException(
                                  Messages.get().container(
                                      Messages.ERR_EL_BAD_ATTRIBUTE_3,
                                      element.getUniquePath(),
                                      XSD_ATTRIBUTE_MAX_OCCURS,
                                      maxOccursStr));
                          }
                      }
                  }
                  if ((minOccurs == 0) && (choiceMaxOccurs == 1)) {
                      // minOccurs 0 and maxOccurs 1, this is a single choice sequence
                      sequenceType = SequenceType.SINGLE_CHOICE;
                  } else {
                      // this is a multiple choice sequence
                      if (minOccurs > choiceMaxOccurs) {
                          throw new CmsXmlException(
                              Messages.get().container(
                                  Messages.ERR_EL_BAD_ATTRIBUTE_3,
                                  element.getUniquePath(),
                                  XSD_ATTRIBUTE_MIN_OCCURS,
                                  minOccursStr == null ? "1" : minOccursStr));
                      }
                      sequenceType = SequenceType.MULTIPLE_CHOICE;
                  }
              }
          } else {
              // this is a simple sequence
              sequenceType = SequenceType.SEQUENCE;
          }
  
          // check the type definition sequence
          List<Element> typeSequenceElements = CmsXmlGenericWrapper.elements(typeSequenceElement);
          if (typeSequenceElements.size() < 1) {
              throw new CmsXmlException(
                  Messages.get().container(
                      Messages.ERR_TS_SUBELEMENT_TOOFEW_3,
                      typeSequenceElement.getUniquePath(),
                      new Integer(1),
                      new Integer(typeSequenceElements.size())));
          }
  
          // now add all type definitions from the schema
          List<I_CmsXmlSchemaType> sequence = new ArrayList<I_CmsXmlSchemaType>();
  
          if (hasLanguageAttribute) {
              // only generate types for sequence node with language attribute
  
              CmsXmlContentTypeManager typeManager = OpenCms.getXmlContentTypeManager();
              Iterator<Element> i = typeSequenceElements.iterator();
              while (i.hasNext()) {
                  Element typeElement = i.next();
                  if (sequenceType != SequenceType.SEQUENCE) {
                      // in case of xsd:choice, need to make sure "minOccurs" for all type elements is 0
                      String minOccursStr = typeElement.attributeValue(XSD_ATTRIBUTE_MIN_OCCURS);
                      int minOccurs = 1;
                      if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(minOccursStr)) {
                          try {
                              minOccurs = Integer.parseInt(minOccursStr.trim());
                          } catch (NumberFormatException e) {
                              // ignore
                          }
                      }
                      // minOccurs must be "0"
                      if (minOccurs != 0) {
                          throw new CmsXmlException(
                              Messages.get().container(
                                  Messages.ERR_EL_BAD_ATTRIBUTE_3,
                                  typeElement.getUniquePath(),
                                  XSD_ATTRIBUTE_MIN_OCCURS,
                                  minOccursStr == null ? "1" : minOccursStr));
                      }
                  }
                  // create the type with the type manager
                  I_CmsXmlSchemaType type = typeManager.getContentType(typeElement, includes);
  
                  if (type.getTypeName().equals(CmsXmlDynamicCategoryValue.TYPE_NAME)
                      && ((type.getMaxOccurs() != 1) || (type.getMinOccurs() != 1))) {
                      throw new CmsXmlException(
                          Messages.get().container(
                              Messages.ERR_EL_OF_TYPE_MUST_OCCUR_EXACTLY_ONCE_2,
                              typeElement.getUniquePath(),
                              type.getTypeName()));
                  }
  
                  if (sequenceType == SequenceType.MULTIPLE_CHOICE) {
                      // if this is a multiple choice sequence,
                      // all elements must have "minOccurs" 0 or 1 and "maxOccurs" of 1
                      if ((type.getMinOccurs() < 0) || (type.getMinOccurs() > 1) || (type.getMaxOccurs() != 1)) {
                          throw new CmsXmlException(
                              Messages.get().container(
                                  Messages.ERR_EL_BAD_ATTRIBUTE_3,
                                  typeElement.getUniquePath(),
                                  XSD_ATTRIBUTE_MAX_OCCURS,
                                  typeElement.attributeValue(XSD_ATTRIBUTE_MAX_OCCURS)));
                      }
                  }
                  sequence.add(type);
              }
          } else {
              // generate a nested content definition for the main type sequence
  
              Element e = typeSequenceElements.get(0);
              String typeName = validateAttribute(e, XSD_ATTRIBUTE_NAME, null);
              String minOccurs = validateAttribute(e, XSD_ATTRIBUTE_MIN_OCCURS, XSD_ATTRIBUTE_VALUE_ZERO);
              String maxOccurs = validateAttribute(e, XSD_ATTRIBUTE_MAX_OCCURS, XSD_ATTRIBUTE_VALUE_UNBOUNDED);
              validateAttribute(e, XSD_ATTRIBUTE_TYPE, createTypeName(typeName));
  
              CmsXmlNestedContentDefinition cd = new CmsXmlNestedContentDefinition(null, typeName, minOccurs, maxOccurs);
              sequence.add(cd);
          }
  
          // return a data structure with the collected values
          return new CmsXmlComplexTypeSequence(name, sequence, hasLanguageAttribute, sequenceType, choiceMaxOccurs);
      }