Browse Source

Merge pull request #767 from lukaspj/fix/taml-schema-for-array-groups

Fix TAML schema for array groups
Brian Roberts 3 years ago
parent
commit
4b391d8a27
1 changed files with 192 additions and 100 deletions
  1. 192 100
      Engine/source/persistence/taml/taml.cpp

+ 192 - 100
Engine/source/persistence/taml/taml.cpp

@@ -1055,6 +1055,115 @@ ImplementEnumType(_TamlFormatMode,
 
    //-----------------------------------------------------------------------------
 
+   tinyxml2::XMLElement* g__write_schema_attribute_element(const AbstractClassRep::Field& field, AbstractClassRep* pType,
+                                                          tinyxml2::XMLDocument& schemaDocument)
+   {
+      // Skip if not a data field.
+      if (field.type == AbstractClassRep::DeprecatedFieldType ||
+         field.type == AbstractClassRep::StartGroupFieldType ||
+         field.type == AbstractClassRep::EndGroupFieldType)
+         return NULL;
+
+      // Skip if the field root is not this type.
+      if (pType->findFieldRoot(field.pFieldname) != pType)
+         return NULL;
+
+      // Add attribute element.
+      tinyxml2::XMLElement* pAttributeElement = schemaDocument.NewElement("xs:attribute");
+      pAttributeElement->SetAttribute("name", field.pFieldname);
+
+      // Handle the console type appropriately.
+      const S32 fieldType = (S32)field.type;
+
+      /*
+      // Is the field an enumeration?
+      if ( fieldType == TypeEnum )
+      {
+      // Yes, so add attribute type.
+      tinyxml2::XMLElement* pAttributeSimpleTypeElement = schemaDocument.NewElement( "xs:simpleType" );
+      pAttributeElement->LinkEndChild( pAttributeSimpleTypeElement );
+
+      // Add restriction element.
+      tinyxml2::XMLElement* pAttributeRestrictionElement = schemaDocument.NewElement( "xs:restriction" );
+      pAttributeRestrictionElement->SetAttribute( "base", "xs:string" );
+      pAttributeSimpleTypeElement->LinkEndChild( pAttributeRestrictionElement );
+
+      // Yes, so fetch enumeration count.
+      const S32 enumCount = field.table->size;
+
+      // Iterate enumeration.
+      for( S32 index = 0; index < enumCount; ++index )
+      {
+      // Add enumeration element.
+      tinyxml2::XMLElement* pAttributeEnumerationElement = schemaDocument.NewElement( "xs:enumeration" );
+      pAttributeEnumerationElement->SetAttribute( "value", field.table->table[index].label );
+      pAttributeRestrictionElement->LinkEndChild( pAttributeEnumerationElement );
+      }
+      }
+      else
+      {*/
+      // No, so assume it's a string type initially.
+      const char* pFieldTypeDescription = "xs:string";
+
+      // Handle known types.
+      if (fieldType == TypeF32)
+      {
+         pFieldTypeDescription = "xs:float";
+      }
+      else if (fieldType == TypeS8 || fieldType == TypeS32)
+      {
+         pFieldTypeDescription = "xs:int";
+      }
+      else if (fieldType == TypeBool || fieldType == TypeFlag)
+      {
+         pFieldTypeDescription = "xs:boolean";
+      }
+      else if (fieldType == TypePoint2F)
+      {
+         pFieldTypeDescription = "Point2F_ConsoleType";
+      }
+      else if (fieldType == TypePoint2I)
+      {
+         pFieldTypeDescription = "Point2I_ConsoleType";
+      }
+      else if (fieldType == TypeRectI)
+      {
+         pFieldTypeDescription = "RectI_ConsoleType";
+      }
+      else if (fieldType == TypeRectF)
+      {
+         pFieldTypeDescription = "RectF_ConsoleType";
+      }
+      else if (fieldType == TypeColorF)
+      {
+         pFieldTypeDescription = "ColorF_ConsoleType";
+      }
+      else if (fieldType == TypeColorI)
+      {
+         pFieldTypeDescription = "ColorI_ConsoleType";
+      }
+      else if (fieldType == TypeAssetId/* ||
+                                       fieldType == TypeImageAssetPtr ||
+                                       fieldType == TypeAnimationAssetPtr ||
+                                       fieldType == TypeAudioAssetPtr*/)
+      {
+         pFieldTypeDescription = "AssetId_ConsoleType";
+      }
+
+      // Set attribute type.
+      pAttributeElement->SetAttribute("type", pFieldTypeDescription);
+      //}
+
+      pAttributeElement->SetAttribute("use", "optional");
+      return pAttributeElement;
+   }
+
+   String g_sanitize_schema_element_name(String buffer)
+   {
+      return buffer.replace("(", "")
+         .replace(")", "");
+   }
+
    bool Taml::generateTamlSchema()
    {
       // Fetch any TAML Schema file reference.
@@ -1298,8 +1407,8 @@ ImplementEnumType(_TamlFormatMode,
          pSchemaElement->LinkEndChild(pComplexTypeElement);
 
          // Add sequence.
-         tinyxml2::XMLElement* pSequenceElement = schemaDocument.NewElement("xs:sequence");
-         pComplexTypeElement->LinkEndChild(pSequenceElement);
+         tinyxml2::XMLElement* pAllElement = schemaDocument.NewElement("xs:all");
+         pComplexTypeElement->LinkEndChild(pAllElement);
 
          // Fetch container child class.
          AbstractClassRep* pContainerChildClass = pType->getContainerChildClass(true);
@@ -1311,7 +1420,7 @@ ImplementEnumType(_TamlFormatMode,
             tinyxml2::XMLElement* pChoiceElement = schemaDocument.NewElement("xs:choice");
             pChoiceElement->SetAttribute("minOccurs", 0);
             pChoiceElement->SetAttribute("maxOccurs", "unbounded");
-            pSequenceElement->LinkEndChild(pChoiceElement);
+            pAllElement->LinkEndChild(pChoiceElement);
 
             // Find child group.
             HashTable<AbstractClassRep*, StringTableEntry>::Iterator childGroupItr = childGroups.find(pContainerChildClass);
@@ -1369,124 +1478,107 @@ ImplementEnumType(_TamlFormatMode,
                continue;
 
             // Call schema generation function.
-            customSchemaFn(pType, pSequenceElement);
+            customSchemaFn(pType, pAllElement);
          }
 
-         // Generate field attribute group.
-         tinyxml2::XMLElement* pFieldAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup");
-         dSprintf(buffer, sizeof(buffer), "%s_Fields", pType->getClassName());
-         pFieldAttributeGroupElement->SetAttribute("name", buffer);
-         pSchemaElement->LinkEndChild(pFieldAttributeGroupElement);
-
          // Fetch field list.
          const AbstractClassRep::FieldList& fields = pType->mFieldList;
 
-         // Fetcj field count.
+         // Fetch field count.
          const S32 fieldCount = fields.size();
 
-         // Iterate static fields (in reverse as most types are organized from the root-fields up).
-         for (S32 index = fieldCount - 1; index > 0; --index)
+         // Generate array attribute groups
+         for (S32 index = 0; index < fieldCount; ++index)
          {
             // Fetch field.
             const AbstractClassRep::Field& field = fields[index];
 
-            // Skip if not a data field.
-            if (field.type == AbstractClassRep::DeprecatedFieldType ||
-               field.type == AbstractClassRep::StartGroupFieldType ||
-               field.type == AbstractClassRep::EndGroupFieldType)
-               continue;
-
-            // Skip if the field root is not this type.
-            if (pType->findFieldRoot(field.pFieldname) != pType)
-               continue;
-
-            // Add attribute element.
-            tinyxml2::XMLElement* pAttributeElement = schemaDocument.NewElement("xs:attribute");
-            pAttributeElement->SetAttribute("name", field.pFieldname);
-
-            // Handle the console type appropriately.
-            const S32 fieldType = (S32)field.type;
-
-            /*
-            // Is the field an enumeration?
-            if ( fieldType == TypeEnum )
+            if (field.type == AbstractClassRep::StartArrayFieldType)
             {
-            // Yes, so add attribute type.
-            tinyxml2::XMLElement* pAttributeSimpleTypeElement = schemaDocument.NewElement( "xs:simpleType" );
-            pAttributeElement->LinkEndChild( pAttributeSimpleTypeElement );
+               // Add the top-level array identifier
+               tinyxml2::XMLElement* pArrayElement = schemaDocument.NewElement("xs:element");
+               dSprintf(buffer, sizeof(buffer), "%s.%s", pType->getClassName(), g_sanitize_schema_element_name(field.pGroupname).c_str());
+               pArrayElement->SetAttribute("name", buffer);
+               pArrayElement->SetAttribute("minOccurs", 0);
+               pAllElement->LinkEndChild(pArrayElement);
+
+               // Inline type specification
+               tinyxml2::XMLElement* pArrayComplexTypeElement = schemaDocument.NewElement("xs:complexType");
+               pArrayElement->LinkEndChild(pArrayComplexTypeElement);
+
+               // Add the actual (repeating) array elements
+               tinyxml2::XMLElement* pInnerArrayElement = schemaDocument.NewElement("xs:element");
+               pInnerArrayElement->SetAttribute("name", g_sanitize_schema_element_name(field.pFieldname).c_str());
+               pInnerArrayElement->SetAttribute("minOccurs", 0);
+               pInnerArrayElement->SetAttribute("maxOccurs", field.elementCount);
+               pArrayComplexTypeElement->LinkEndChild(pInnerArrayElement);
+
+               // Inline type specification
+               tinyxml2::XMLElement* pInnerComplexTypeElement = schemaDocument.NewElement("xs:complexType");
+               pInnerArrayElement->LinkEndChild(pInnerComplexTypeElement);
+
+               // Add a reference to the attribute group for the array
+               tinyxml2::XMLElement* pInnerAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup");
+               dSprintf(buffer, sizeof(buffer), "%s_%s_Array_Fields", pType->getClassName(), g_sanitize_schema_element_name(field.pFieldname).c_str());
+               pInnerAttributeGroupElement->SetAttribute("ref", buffer);
+               pInnerComplexTypeElement->LinkEndChild(pInnerAttributeGroupElement);
+
+               // Add the attribute group itself
+               tinyxml2::XMLElement* pFieldAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup");
+               pFieldAttributeGroupElement->SetAttribute("name", buffer);
+               pSchemaElement->LinkEndChild(pFieldAttributeGroupElement);
+
+               // Keep adding fields to attribute group until we hit the end of the array
+               for (; index < fieldCount; ++index)
+               {
+                  const AbstractClassRep::Field& array_field = fields[index];
+                  if (array_field.type == AbstractClassRep::EndArrayFieldType)
+                  {
+                     break;
+                  }
+                  
+                  tinyxml2::XMLElement* pAttributeElement = g__write_schema_attribute_element(array_field, pType, schemaDocument);
+                  if (pAttributeElement == NULL)
+                  {
+                     continue;
+                  }
 
-            // Add restriction element.
-            tinyxml2::XMLElement* pAttributeRestrictionElement = schemaDocument.NewElement( "xs:restriction" );
-            pAttributeRestrictionElement->SetAttribute( "base", "xs:string" );
-            pAttributeSimpleTypeElement->LinkEndChild( pAttributeRestrictionElement );
+                  pFieldAttributeGroupElement->LinkEndChild(pAttributeElement);
+               }
+            }
+         }
 
-            // Yes, so fetch enumeration count.
-            const S32 enumCount = field.table->size;
+         // Generate field attribute group.
+         tinyxml2::XMLElement* pFieldAttributeGroupElement = schemaDocument.NewElement("xs:attributeGroup");
+         dSprintf(buffer, sizeof(buffer), "%s_Fields", pType->getClassName());
+         pFieldAttributeGroupElement->SetAttribute("name", buffer);
+         pSchemaElement->LinkEndChild(pFieldAttributeGroupElement);
 
-            // Iterate enumeration.
-            for( S32 index = 0; index < enumCount; ++index )
-            {
-            // Add enumeration element.
-            tinyxml2::XMLElement* pAttributeEnumerationElement = schemaDocument.NewElement( "xs:enumeration" );
-            pAttributeEnumerationElement->SetAttribute( "value", field.table->table[index].label );
-            pAttributeRestrictionElement->LinkEndChild( pAttributeEnumerationElement );
-            }
-            }
-            else
-            {*/
-            // No, so assume it's a string type initially.
-            const char* pFieldTypeDescription = "xs:string";
+         // Iterate static fields (in reverse as most types are organized from the root-fields up).
+         for (S32 index = fieldCount - 1; index > 0; --index)
+         {
+            // Fetch field.
+            const AbstractClassRep::Field& field = fields[index];
 
-            // Handle known types.
-            if (fieldType == TypeF32)
-            {
-               pFieldTypeDescription = "xs:float";
-            }
-            else if (fieldType == TypeS8 || fieldType == TypeS32)
-            {
-               pFieldTypeDescription = "xs:int";
-            }
-            else if (fieldType == TypeBool || fieldType == TypeFlag)
-            {
-               pFieldTypeDescription = "xs:boolean";
-            }
-            else if (fieldType == TypePoint2F)
-            {
-               pFieldTypeDescription = "Point2F_ConsoleType";
-            }
-            else if (fieldType == TypePoint2I)
-            {
-               pFieldTypeDescription = "Point2I_ConsoleType";
-            }
-            else if (fieldType == TypeRectI)
+            // Skip fields inside arrays
+            if (field.type == AbstractClassRep::EndArrayFieldType)
             {
-               pFieldTypeDescription = "RectI_ConsoleType";
-            }
-            else if (fieldType == TypeRectF)
-            {
-               pFieldTypeDescription = "RectF_ConsoleType";
-            }
-            else if (fieldType == TypeColorF)
-            {
-               pFieldTypeDescription = "ColorF_ConsoleType";
-            }
-            else if (fieldType == TypeColorI)
-            {
-               pFieldTypeDescription = "ColorI_ConsoleType";
+               for (; index > 0; --index)
+               {
+                  if (field.type == AbstractClassRep::StartArrayFieldType)
+                  {
+                     break;
+                  }
+               }
+               continue;
             }
-            else if (fieldType == TypeAssetId/* ||
-                                             fieldType == TypeImageAssetPtr ||
-                                             fieldType == TypeAnimationAssetPtr ||
-                                             fieldType == TypeAudioAssetPtr*/)
+
+            tinyxml2::XMLElement* pAttributeElement = g__write_schema_attribute_element(field, pType, schemaDocument);
+            if (pAttributeElement == NULL)
             {
-               pFieldTypeDescription = "AssetId_ConsoleType";
+               continue;
             }
 
-            // Set attribute type.
-            pAttributeElement->SetAttribute("type", pFieldTypeDescription);
-            //}
-
-            pAttributeElement->SetAttribute("use", "optional");
             pFieldAttributeGroupElement->LinkEndChild(pAttributeElement);
          }