Difference between revisions of "DOM guide: Using custom COLLADA data"

From COLLADA Public Wiki
Jump to: navigation, search
m (None)
(Undo revision 7086 by LLutz74 (talk))
 
Line 1: Line 1:
The [[COLLADA]] format has many locations where a user can store extra custom data. This data can be any well-formed XML. In the [[COLLADA DOM]], this data is stored in objects of the <code>domAny</code> class.
+
The [[COLLADA]] format has many locations where a user can store extra custom data. This data can be any well-formed XML. In the [[COLLADA DOM]], this data is stored in objects of the <code>domAny</code> class.
  
 
==domAny==
 
==domAny==
If the &lt;code>dom*&lt;/code> classes are considered "strongly-typed" element classes then the &lt;code>domAny&lt;/code> class represents weakly typed elements. A weakly typed element, because it lacks associated type information, contains only string data.
+
If the <code>dom*</code> classes are considered "strongly-typed" element classes then the <code>domAny</code> class represents weakly typed elements. A weakly typed element, because it lacks associated type information, contains only string data.
  
 
===Identifying domAny Elements===
 
===Identifying domAny Elements===
&lt;code>domAny&lt;/code> elements, in COLLADA 1.4.1, occur only as children of &lt;code>domTechnique&lt;/code> elements.
+
<code>domAny</code> elements, in COLLADA 1.4.1, occur only as children of <code>domTechnique</code> elements.
The &lt;code>getElementType&lt;/code> method returns a value of &lt;code>COLLADA_TYPE::ANY&lt;/code>, which has an int value of 1.
+
The <code>getElementType</code> method returns a value of <code>COLLADA_TYPE::ANY</code>, which has an int value of 1.
The method for identifying elements based on their &lt;code>_Meta&lt;/code> type descriptor pointer does not work for &lt;code>domAny&lt;/code> elements. Because of this, &lt;code>daeSafeCast&lt;/code> does not work for casting &lt;code>daeElement&lt;/code> objects to &lt;code>domAny&lt;/code>. Instead, you can call &lt;code>daeElement::getElementType&lt;/code>, which returns &lt;code>COLLADA_TYPE::ANY&lt;/code> for &lt;code>domAny&lt;/code> objects, and then do a normal cast to &lt;code>domAny&lt;/code>. This is illustrated in the following code:
+
The method for identifying elements based on their <code>_Meta</code> type descriptor pointer does not work for <code>domAny</code> elements. Because of this, <code>daeSafeCast</code> does not work for casting <code>daeElement</code> objects to <code>domAny</code>. Instead, you can call <code>daeElement::getElementType</code>, which returns <code>COLLADA_TYPE::ANY</code> for <code>domAny</code> objects, and then do a normal cast to <code>domAny</code>. This is illustrated in the following code:
  
 
  domAny* any = (element->getElementType() == COLLADA_TYPE::ANY) ? (domAny*)element : 0;
 
  domAny* any = (element->getElementType() == COLLADA_TYPE::ANY) ? (domAny*)element : 0;
Line 15: Line 15:
  
 
===Accessing Data===
 
===Accessing Data===
The &lt;code>domAny&lt;/code> class provides the following methods for accessing and manipulating its data:
+
The <code>domAny</code> class provides the following methods for accessing and manipulating its data:
  
* To access  a &lt;code>domAny&lt;/code>'s attribute data:  &lt;code>getAttributeCount&lt;/code>, &lt;code>getAttributeName&lt;/code>, and &lt;code>getAttributeValue&lt;/code>
+
* To access  a <code>domAny</code>'s attribute data:  <code>getAttributeCount</code>, <code>getAttributeName</code>, and <code>getAttributeValue</code>
* To create new attributes and set existing ones: &lt;code>setAttribute&lt;/code>
+
* To create new attributes and set existing ones: <code>setAttribute</code>
 
* To remove an attribute: Currently there is no functionality to do this
 
* To remove an attribute: Currently there is no functionality to do this
* To access and modify a &lt;code>domAny&lt;/code>'s value: &lt;code>getValue&lt;/code> and &lt;code>setValue&lt;/code>  
+
* To access and modify a <code>domAny</code>'s value: <code>getValue</code> and <code>setValue</code>  
  
The &lt;code>domAny&lt;/code> class can have any number of &lt;code>domAny&lt;/code> children.
+
The <code>domAny</code> class can have any number of <code>domAny</code> children.
  
 
==Working With Custom Data==
 
==Working With Custom Data==
 
All locations in the COLLADA standard that allow for custom data can contain arbitrary XML elements, which are weakly typed, or COLLADA elements, which are strongly typed. When validating COLLADA data against the COLLADA schema, the weakly typed elements and their children are not validated. The strongly typed elements are still validated. This forces custom data to use element names that are different from the COLLADA element names.
 
All locations in the COLLADA standard that allow for custom data can contain arbitrary XML elements, which are weakly typed, or COLLADA elements, which are strongly typed. When validating COLLADA data against the COLLADA schema, the weakly typed elements and their children are not validated. The strongly typed elements are still validated. This forces custom data to use element names that are different from the COLLADA element names.
  
  &lt;extra>
+
  <extra>
   &lt;technique profile="custom">
+
   <technique profile="custom">
     &lt;myFoo bar="true">
+
     <myFoo bar="true">
       &lt;myBar>Woot Woot&lt;/myBar>
+
       <myBar>Woot Woot</myBar>
     &lt;/myFoo>
+
     </myFoo>
     &lt;param type="float" name="value">15.0&lt;/param>
+
     <param type="float" name="value">15.0</param>
   &lt;/technique>
+
   </technique>
  &lt;/extra>
+
  </extra>
In this example, the elements &lt;myFoo> and &lt;myBar> are weakly typed and are not validated. The &lt;param> element is validated as a COLLADA param element.
+
In this example, the elements <myFoo> and <myBar> are weakly typed and are not validated. The <param> element is validated as a COLLADA param element.
  
 
The COLLADA DOM deals with custom data in the same manner. The following object hierarchy shows how the previous example would be represented in the DOM:
 
The COLLADA DOM deals with custom data in the same manner. The following object hierarchy shows how the previous example would be represented in the DOM:
Line 44: Line 44:
 
     domParam
 
     domParam
  
The following sample code reads an &lt;extra> element. It looks for the "custom" technique profile. For this example, the "custom" profile can contain any arbitrary XML structures but only COLLADA &lt;param> strongly typed elements. As a COLLADA implementor, you are free to design and use any elements you would like in your own profile.
+
The following sample code reads an <extra> element. It looks for the "custom" technique profile. For this example, the "custom" profile can contain any arbitrary XML structures but only COLLADA <param> strongly typed elements. As a COLLADA implementor, you are free to design and use any elements you would like in your own profile.
 
  //extra is of type domExtra and was obtained from the Object Model in a normal manner.
 
  //extra is of type domExtra and was obtained from the Object Model in a normal manner.
 
  unsigned int numTeqs = extra->getTechnique_array().getCount();
 
  unsigned int numTeqs = extra->getTechnique_array().getCount();
  for ( unsigned int currTeq = 0; currTeq &lt; numTeqs; ++currTeq )
+
  for ( unsigned int currTeq = 0; currTeq < numTeqs; ++currTeq )
 
  {
 
  {
 
   if ( strcmp( extra->getTechnique_array()[currTeq]->getProfile(), "custom" ) == 0 ) )
 
   if ( strcmp( extra->getTechnique_array()[currTeq]->getProfile(), "custom" ) == 0 ) )
Line 53: Line 53:
 
     domTechnique *teq = extra->getTechnique_array()[currTeq];
 
     domTechnique *teq = extra->getTechnique_array()[currTeq];
 
     unsigned int numChildren = teq->getContents().getCount();
 
     unsigned int numChildren = teq->getContents().getCount();
     for( unsigned int currChild = 0; currChild &lt; numChildren; ++currChild )
+
     for( unsigned int currChild = 0; currChild < numChildren; ++currChild )
 
     {
 
     {
 
       if ( teq->getContents()[currChild]->getElementType() == COLLADA_TYPE::ANY )
 
       if ( teq->getContents()[currChild]->getElementType() == COLLADA_TYPE::ANY )
Line 62: Line 62:
 
       else if ( teq->getContents()[currChild]->getElementType() == COLLADA_TYPE::PARAM )
 
       else if ( teq->getContents()[currChild]->getElementType() == COLLADA_TYPE::PARAM )
 
       {
 
       {
         domParam *param = daeSafeCast&lt;domParam>( teq->getContents()[currChild] );
+
         domParam *param = daeSafeCast<domParam>( teq->getContents()[currChild] );
 
         //use param element
 
         //use param element
 
       }
 
       }
Line 77: Line 77:
 
   char *indentStr = new char[ indent + 1 ];
 
   char *indentStr = new char[ indent + 1 ];
 
   indentStr[ 0 ] = '\0';
 
   indentStr[ 0 ] = '\0';
   for( unsigned int i = 0; i &lt; indent; ++i )
+
   for( unsigned int i = 0; i < indent; ++i )
 
   {
 
   {
 
     strcat( indentStr, "\t" );
 
     strcat( indentStr, "\t" );
Line 83: Line 83:
 
   printf( "%sElement: %s\n", indentStr, anyElement->getElementName() );
 
   printf( "%sElement: %s\n", indentStr, anyElement->getElementName() );
 
   unsigned int numAttrs = anyElement->getAttributeCount();
 
   unsigned int numAttrs = anyElement->getAttributeCount();
   for ( unsigned int currAttr = 0; currAttr &lt; numAttrs; ++currAttr )
+
   for ( unsigned int currAttr = 0; currAttr < numAttrs; ++currAttr )
 
   {
 
   {
 
     printf( "%s\tAttribute: %s has value: %s\n", indentStr, anyElement->getAttributeName( currAttr ),
 
     printf( "%s\tAttribute: %s has value: %s\n", indentStr, anyElement->getAttributeName( currAttr ),
Line 89: Line 89:
 
   }
 
   }
 
   unsigned int numChildren = anyElement->getContents().getCount();
 
   unsigned int numChildren = anyElement->getContents().getCount();
   for ( unsigned int currChild = 0; currChild &lt; numChildren; ++currChild )
+
   for ( unsigned int currChild = 0; currChild < numChildren; ++currChild )
 
   {
 
   {
 
     printDomAny( anyElement->getContents()[currChild], indent + 1 );
 
     printDomAny( anyElement->getContents()[currChild], indent + 1 );
Line 104: Line 104:
  
 
  //currElement is any daeElement or subclass that allows for domExtra as a child.
 
  //currElement is any daeElement or subclass that allows for domExtra as a child.
  domExtra *extra = daeSafeCast&lt;domExtra>( currElement->createAndPlace( COLLADA_ELEMENT_EXTRA ) );
+
  domExtra *extra = daeSafeCast<domExtra>( currElement->createAndPlace( COLLADA_ELEMENT_EXTRA ) );
  domTechnique *teq = daeSafeCast&lt;domTechnique>( extra->createAndPlace( COLLADA_ELEMENT_TECHNIQUE ) );
+
  domTechnique *teq = daeSafeCast<domTechnique>( extra->createAndPlace( COLLADA_ELEMENT_TECHNIQUE ) );
 
  teq->setProfile( "custom" );
 
  teq->setProfile( "custom" );
 
  domAny *myFoo = (domAny*)teq->createAndPlace( "myFoo" );
 
  domAny *myFoo = (domAny*)teq->createAndPlace( "myFoo" );
Line 111: Line 111:
 
  domAny *myBar = (domAny*)myFoo->createAndPlace( "myBar" );
 
  domAny *myBar = (domAny*)myFoo->createAndPlace( "myBar" );
 
  myBar->setValue( "Woot Woot" );
 
  myBar->setValue( "Woot Woot" );
  domParam *param = daeSafeCast&lt;domParam>( teq->createAndPlace( COLLADA_ELEMENT_PARAM ) );
+
  domParam *param = daeSafeCast<domParam>( teq->createAndPlace( COLLADA_ELEMENT_PARAM ) );
 
  param->setType( "float" );
 
  param->setType( "float" );
 
  param->setName( "value" );
 
  param->setName( "value" );
 
  param->setValue( "15.0" );
 
  param->setValue( "15.0" );
  
The &lt;code>domTechnique&lt;/code> class is currently the only class in the COLLADA DOM that allows for &lt;code>domAny&lt;/code> children (because <span class="plainlinks">[http://www.thepiggybackrider.com/ <span style="color:black;font-weight:normal; text-decoration:none!important; background:none!important; text-decoration:none;/*CITATION*/">kid carrier</span>]</span> the &lt;technique> element in the COLLADA schema is the only element that allows for arbitrary XML). As you can see in the example, to create a &lt;code>domAny&lt;/code> element, all you need to do is call &lt;code>createAndPlace&lt;/code>, passing in the element name just like you would when dealing with normal COLLADA elements. The only difference is that, since the name is custom, the name passed as an argument does not have a COLLADA_ELEMENT_* constant defined. You are free to define your own constant strings for the names of your custom elements. For example:
+
The <code>domTechnique</code> class is currently the only class in the COLLADA DOM that allows for <code>domAny</code> children (because the <technique> element in the COLLADA schema is the only element that allows for arbitrary XML). As you can see in the example, to create a <code>domAny</code> element, all you need to do is call <code>createAndPlace</code>, passing in the element name just like you would when dealing with normal COLLADA elements. The only difference is that, since the name is custom, the name passed as an argument does not have a COLLADA_ELEMENT_* constant defined. You are free to define your own constant strings for the names of your custom elements. For example:
  
 
  const char* PROFILE_CUSTOM_MYFOO = "myFoo";
 
  const char* PROFILE_CUSTOM_MYFOO = "myFoo";

Latest revision as of 18:00, 26 September 2011

The COLLADA format has many locations where a user can store extra custom data. This data can be any well-formed XML. In the COLLADA DOM, this data is stored in objects of the domAny class.

domAny

If the dom* classes are considered "strongly-typed" element classes then the domAny class represents weakly typed elements. A weakly typed element, because it lacks associated type information, contains only string data.

Identifying domAny Elements

domAny elements, in COLLADA 1.4.1, occur only as children of domTechnique elements. The getElementType method returns a value of COLLADA_TYPE::ANY, which has an int value of 1. The method for identifying elements based on their _Meta type descriptor pointer does not work for domAny elements. Because of this, daeSafeCast does not work for casting daeElement objects to domAny. Instead, you can call daeElement::getElementType, which returns COLLADA_TYPE::ANY for domAny objects, and then do a normal cast to domAny. This is illustrated in the following code:

domAny* any = (element->getElementType() == COLLADA_TYPE::ANY) ? (domAny*)element : 0;
if (any) {
  // Do stuff with the domAny object
}

Accessing Data

The domAny class provides the following methods for accessing and manipulating its data:

  • To access a domAny's attribute data: getAttributeCount, getAttributeName, and getAttributeValue
  • To create new attributes and set existing ones: setAttribute
  • To remove an attribute: Currently there is no functionality to do this
  • To access and modify a domAny's value: getValue and setValue

The domAny class can have any number of domAny children.

Working With Custom Data

All locations in the COLLADA standard that allow for custom data can contain arbitrary XML elements, which are weakly typed, or COLLADA elements, which are strongly typed. When validating COLLADA data against the COLLADA schema, the weakly typed elements and their children are not validated. The strongly typed elements are still validated. This forces custom data to use element names that are different from the COLLADA element names.

<extra>
  <technique profile="custom">
    <myFoo bar="true">
      <myBar>Woot Woot</myBar>
    </myFoo>
    <param type="float" name="value">15.0</param>
  </technique>
</extra>

In this example, the elements <myFoo> and <myBar> are weakly typed and are not validated. The <param> element is validated as a COLLADA param element.

The COLLADA DOM deals with custom data in the same manner. The following object hierarchy shows how the previous example would be represented in the DOM:

domExtra
  domTechnique
    domAny
      domAny
    domParam

The following sample code reads an <extra> element. It looks for the "custom" technique profile. For this example, the "custom" profile can contain any arbitrary XML structures but only COLLADA <param> strongly typed elements. As a COLLADA implementor, you are free to design and use any elements you would like in your own profile.

//extra is of type domExtra and was obtained from the Object Model in a normal manner.
unsigned int numTeqs = extra->getTechnique_array().getCount();
for ( unsigned int currTeq = 0; currTeq < numTeqs; ++currTeq )
{
  if ( strcmp( extra->getTechnique_array()[currTeq]->getProfile(), "custom" ) == 0 ) )
  {
    domTechnique *teq = extra->getTechnique_array()[currTeq];
    unsigned int numChildren = teq->getContents().getCount();
    for( unsigned int currChild = 0; currChild < numChildren; ++currChild )
    {
      if ( teq->getContents()[currChild]->getElementType() == COLLADA_TYPE::ANY )
      {
        domAny *child = (domAny*)(daeElement*)teq->getContents()[currChild];
        printDomAny( child );
      }
      else if ( teq->getContents()[currChild]->getElementType() == COLLADA_TYPE::PARAM )
      {
        domParam *param = daeSafeCast<domParam>( teq->getContents()[currChild] );
        //use param element
      }
      else
      {
        printf( "Error: Invalid element for profile custom" );
      }
    }
  }
}
void printDomAny( domAny *anyElement, unsigned int indent = 0 )
{
  char *indentStr = new char[ indent + 1 ];
  indentStr[ 0 ] = '\0';
  for( unsigned int i = 0; i < indent; ++i )
  {
    strcat( indentStr, "\t" );
  }
  printf( "%sElement: %s\n", indentStr, anyElement->getElementName() );
  unsigned int numAttrs = anyElement->getAttributeCount();
  for ( unsigned int currAttr = 0; currAttr < numAttrs; ++currAttr )
  {
    printf( "%s\tAttribute: %s has value: %s\n", indentStr, anyElement->getAttributeName( currAttr ),
            anyElement->getAttributeValue( currAttr ) );
  }
  unsigned int numChildren = anyElement->getContents().getCount();
  for ( unsigned int currChild = 0; currChild < numChildren; ++currChild )
  {
    printDomAny( anyElement->getContents()[currChild], indent + 1 );
  }
  if ( anyAttr->getValue() != NULL )
  {
    printf( "%sValue: %s\n", indentStr, anyElement->getValue() );
  }
  delete []indentStr;
}

Here is sample code to programatically create the custom COLLADA shown earlier.


//currElement is any daeElement or subclass that allows for domExtra as a child.
domExtra *extra = daeSafeCast<domExtra>( currElement->createAndPlace( COLLADA_ELEMENT_EXTRA ) );
domTechnique *teq = daeSafeCast<domTechnique>( extra->createAndPlace( COLLADA_ELEMENT_TECHNIQUE ) );
teq->setProfile( "custom" );
domAny *myFoo = (domAny*)teq->createAndPlace( "myFoo" );
myFoo->setAttribute( "blah", "true" );
domAny *myBar = (domAny*)myFoo->createAndPlace( "myBar" );
myBar->setValue( "Woot Woot" );
domParam *param = daeSafeCast<domParam>( teq->createAndPlace( COLLADA_ELEMENT_PARAM ) );
param->setType( "float" );
param->setName( "value" );
param->setValue( "15.0" );

The domTechnique class is currently the only class in the COLLADA DOM that allows for domAny children (because the <technique> element in the COLLADA schema is the only element that allows for arbitrary XML). As you can see in the example, to create a domAny element, all you need to do is call createAndPlace, passing in the element name just like you would when dealing with normal COLLADA elements. The only difference is that, since the name is custom, the name passed as an argument does not have a COLLADA_ELEMENT_* constant defined. You are free to define your own constant strings for the names of your custom elements. For example:

const char* PROFILE_CUSTOM_MYFOO = "myFoo";
domAny *myFoo = (domAny*)teq->createAndPlace( PROFILE_CUSTOM_MYFOO );


COLLADA DOM - Version 2.4 Historical Reference
List of main articles under the DOM portal.
User Guide chapters:  • Intro  • Architecture  • Setting up  • Working with documents  • Creating docs  • Importing docs  • Representing elements  • Working with elements  • Resolving URIs  • Resolving SIDs  • Using custom COLLADA data  • Integration templates  • Error handling

Systems:  • URI resolver  • Meta  • Load/save flow  • Runtime database  • Memory • StringRef  • Code generator
Additional information:  • What's new  • Backward compatibility  • Future work
Terminology categories:  • COLLADA  • DOM  • XML