private NeutralSchema parseElement(XmlSchemaElement element, XmlSchema schema) {

    QName elementTypeName = element.getSchemaTypeName();

    // Derive Element Schema
    XmlSchemaType elementSchemaType = element.getSchemaType();

    // Element annotations override type annotations.
    if (element.getAnnotation() != null) {
      elementSchemaType.setAnnotation(element.getAnnotation());
    }

    NeutralSchema elementSchema = null;
    if (elementSchemaType != null) {
      if (elementSchemaType.getName() != null) {
        elementSchema = this.parse(elementSchemaType, schema);
      } else {
        elementSchema = this.parse(elementSchemaType, element.getName(), schema);
      }
    } else if (elementTypeName != null) {
      elementSchema = getSchemaFactory().createSchema(elementTypeName);
    }

    if (elementSchema != null) {

      // List Schema
      if (element.getMaxOccurs() > 1) {
        ListSchema listSchema = (ListSchema) getSchemaFactory().createSchema("list");
        listSchema.getList().add(elementSchema);
        listSchema.updateAnnotations();
        elementSchema = listSchema;
      }
    }

    Long min = element.getMinOccurs();
    Long max = element.getMaxOccurs();
    QName type = element.getSchemaTypeName();

    if (min != null) {
      elementSchema.getProperties().put("minCardinality", min);
    }
    if (max != null) {
      elementSchema.getProperties().put("maxCardinality", max);
    }
    if (type != null) {
      elementSchema.getProperties().put("elementType", type.toString());
    }

    return elementSchema;
  }
  private NeutralSchema recursiveParseSimpleType(
      XmlSchemaSimpleType schemaSimpleType, XmlSchema schema) {
    NeutralSchema simpleSchema = null;

    String simpleTypeName = schemaSimpleType.getName();

    if (NeutralSchemaType.isPrimitive(schemaSimpleType.getQName())) {
      simpleSchema = getSchemaFactory().createSchema(schemaSimpleType.getQName());

    } else if (NeutralSchemaType.exists(schemaSimpleType.getBaseSchemaTypeName())) {

      if (NeutralSchemaType.isPrimitive(schemaSimpleType.getBaseSchemaTypeName())) {
        simpleSchema = getSchemaFactory().createSchema(schemaSimpleType.getBaseSchemaTypeName());

      } else {
        XmlSchemaSimpleType simpleBaseType =
            getSimpleBaseType(schemaSimpleType.getBaseSchemaTypeName(), schema);
        if (simpleBaseType != null) {

          if (simpleTypeName == null) {
            simpleTypeName = simpleBaseType.getName();
          }
          simpleSchema = getSchemaFactory().createSchema(simpleTypeName);
        }
      }

    } else if (schemaSimpleType.getContent() != null
        && schemaSimpleType.getContent() instanceof XmlSchemaSimpleTypeList) {

      ListSchema listSchema = (ListSchema) getSchemaFactory().createSchema("list");

      XmlSchemaSimpleTypeList content = (XmlSchemaSimpleTypeList) schemaSimpleType.getContent();
      NeutralSchema listContentSchema = null;

      if (content.getItemType() != null) {
        listContentSchema = parseSimpleType(content.getItemType(), schema, null);

      } else {
        QName itemTypeName = content.getItemTypeName();
        listContentSchema = getSchemaFactory().createSchema(itemTypeName.getLocalPart());
      }
      listSchema.getList().add(listContentSchema);
      listSchema.updateAnnotations();
      return listSchema;

    } else if (getSimpleContentTypeName(schemaSimpleType) != null) {

      if (NeutralSchemaType.isPrimitive(getSimpleContentTypeName(schemaSimpleType))) {
        simpleSchema = getSchemaFactory().createSchema(getSimpleContentTypeName(schemaSimpleType));

      } else {

        XmlSchemaSimpleType simpleBaseType =
            getSimpleBaseType(getSimpleContentTypeName(schemaSimpleType), schema);
        simpleSchema = recursiveParseSimpleType(simpleBaseType, schema);
      }
    }

    if (simpleSchema != null && schemaSimpleType.getContent() != null) {

      if (schemaSimpleType.getContent() instanceof XmlSchemaSimpleTypeRestriction) {

        XmlSchemaSimpleTypeRestriction simpleRestrictedContent =
            (XmlSchemaSimpleTypeRestriction) schemaSimpleType.getContent();
        XmlSchemaObjectCollection facets = simpleRestrictedContent.getFacets();
        List<String> tokens = new ArrayList<String>();
        for (int i = 0; i < facets.getCount(); i++) {
          XmlSchemaObject facetObject = facets.getItem(i);

          if (facetObject instanceof XmlSchemaEnumerationFacet) {
            XmlSchemaEnumerationFacet enumerationFacet = (XmlSchemaEnumerationFacet) facetObject;
            tokens.add(enumerationFacet.getValue().toString());
          } else if (facetObject instanceof XmlSchemaFacet) {
            XmlSchemaFacet facet = (XmlSchemaFacet) facetObject;
            String facetPropertyName = NeutralSchemaType.lookupPropertyName(facet);
            simpleSchema.getProperties().put(facetPropertyName, facet.getValue().toString());
          }
        }

        if (tokens.size() > 0) {
          // Token Schema
          Collections.sort(tokens); // sort so we can binary search
          simpleSchema.getProperties().put(TokenSchema.TOKENS, tokens);
        }
      }
    }

    parseAnnotations(simpleSchema, schemaSimpleType);

    if ((simpleSchema != null) && (simpleTypeName != null)) {
      simpleSchema.setType(simpleTypeName);
    }

    return simpleSchema;
  }