DOM guide: Working with elements

From COLLADA Public Wiki
Jump to: navigation, search

Two classes provide methods for working with elements after you have loaded a COLLADA instance document into your application:

  • daeDatabase provides access to elements within a document.
  • daeElement is the base class for all COLLADA Object Model classes. This class uses the Reflective Object System (ROS) to provide considerable functionality without the need to use the generated subclass.

Querying Database Elements

The current version of the COLLADA DOM provides two methods to query the database to get information about specific elements:

  • daeDatabase::getElementCount
  • daeDatabase::getElement
Note: domConstants.h provides constants for the element tag names (COLLADA_ELEMENT_*) and the element types (COLLADA_TYPE_*). When querying the database for elements based on type, always use the COLLADA_TYPE_* constant.

getElementCount

getElementCount returns the number of elements for a particular query. For example, the following code asks how many <image> elements are in the database:

imageCount = collada_dom->getDatabase()->getElementCount(NULL, COLLADA_TYPE_IMAGE, NULL);

The additional parameters to getElementCount make the request more specific. The first parameter represents the ID of the element. The third parameter represents the name of the document, and might be used if you have loaded elements from multiple instance documents.

getElement

getElement requests that the database return a specific element. For example, the following code returns an <image> element with an index that matches the value in el_number.

domImage *thisImage;
daeInt error = collada_dom->getDatabase()->getElement((daeElement**)&thisImage, el_number, NULL, COLLADA_TYPE_IMAGE, NULL);

The element itself is returned in the first parameter. The third parameter restricts the query to a specific element by ID, and the fifth parameter restricts the search to a specific document.

Technique for querying elements

Typically, getElementCount and getElement are used as a pair, first getting the number of elements that match a particular ID, type, or document query, and then iterating through those by using the getElement method. For example, if you want to take an action on all of the images in the database, you could do the following:

imageCount = collada_dom->getDatabase()->getElementCount(NULL, COLLADA_TYPE_IMAGE, NULL);
for (unsigned int i=0; i<imageCount; i++)
{ 
    error = collada_dom->getDatabase()->getElement((daeElement**)&thisImage, i, NULL, COLLADA_TYPE_IMAGE, NULL);
    /* take action on this image */
}

As another example, to take action on all images with the ID “landImage”, you could do the following:

imageCount = collada_dom->getDatabase()->getElementCount("landImage", COLLADA_TYPE_IMAGE, NULL);
for (unsigned int i=0; i<imageCount; i++)
{ 
    error = collada_dom->getDatabase()->getElement((daeElement**)&thisImage, i, "landImage", COLLADA_TYPE_IMAGE, NULL);
    /* take action on this land image */
}

The index passed to getElement is not directly associated with the element within the database. The index relates to the query itself. The queries used for getElementCount and getElement must match in order for the index to be valid when passed to the getElement method.

Determining an Element's Type

There are three approaches to determining the type of a daeElement:

  • Using the daeElement::getElementType method, which returns an enumerated value respresenting the element's type. The values returned by this function are in the dom/domTypes.h header. This is the easiest approach.
  • Using the daeElement::getTypeName method, which returns a daeString containing the type name. To determine the type, compare this string with the matching COLLADA_TYPE_* constant defined in dom/domConstants.h.
  • By comparing the daeElement::_meta variable. The _meta is a pointer to a daeMetaElement, which is the class that contains all the ROS information for an element type. By doing a pointer comparison on daeElement::getMeta and the generated class's static dom*::_Meta, it is possible to find the element type. This is the approach that the daeSafeCast method uses to ensure type safety. (See also: DOM meta system.)

NOTE: The daeSafeCast and daeElement::getElementType approaches are newer additions to the COLLADA DOM. When looking at older source code using the DOM, expect to see the older methods used frequently for type checking.

Determining an Element's Name

Use the daeElement:getElementName method to retrieve the name of an element. The element name is the XML tag that would be present in a COLLADA instance document. For the majority of elements in the COLLADA DOM, getElementName returns NULL, indicating that the element's name is the same as its type name, available from daeElement::getTypeName.

Accessing Element Data

The easiest way to access element data is to cast the daeElement to its strongly typed subclass. However, at times, it might not be possible to do the cast or it might be more convenient not to cast. The daeElement class provides methods to access and manipulate data directly for such situations.

Navigating the Object Model

daeElement provides the following methods for accessing various information about an element:

  • getDocument provides access to the COLLADA document that the element belongs to.
  • getDocumentURI is a helper method if you need only the document's name.
  • getParentElement returns the parent element, which allows you to traverse up the tree to the root. If this method returns NULL, the element is the root of the tree. If the root element belongs to a document (getDocument or getDocumentURI are non-NULL) then it is safe to assume that the element is a domCOLLADA element, which is an element that is the root of a COLLADA document.
  • getChildren populates an array with the children of an element. This allows you to iterate over all the children of an element and traverse down the element hierarchy. This array is ordered the same as it would be if the element were written to a COLLADA instance document. This array is the same as the _contents array, if an element's dom* subclass has a _contents array.

Accessing Attributes

The daeElement class provides many functions for accessing the attributes that an element may have:

  • setAttribute takes both the attribute name and the new value as string arguments. The COLLADA DOM converts the value from a string to the data type of the attribute. This method returns false if the element does not have an attribute with the specified name.
  • hasAttribute queries the existence of an attribute.
  • isAttributeSet returns true if the attribute exists and has been set. The attribute can be set when loading the document or programmatically. Attributes with default values are always considered set.
  • getAttributeValue returns a byte pointer to the memory used to store the specified attribute. The client application is responsible for type casting this pointer to the appropriate type before using it. One common mistake occurs when dealing with string attributes. Remember that this function returns a pointer to the data and that daeString is a pointer itself, therefore this function returns a pointer to a pointer for string attributes.

Accessing the Value

  • The daeElement::hasValue method is used to query if an element has a value.
  • The daeElement::getValuePointer method works the same as daeElement::getAttributeValue except that it returns a pointer to the value field.

Adding and Removing Elements

The daeElement class provides methods for adding elements to, and removing them from, the Object Model. Using these methods ensures that the element bookkeeping information maintained by the COLLADA DOM is appropriately updated. For example, many DOM classes contain a _contents array, which keeps the correct order of all the child elements of that DOM class so they can be written in the valid order. The DOM maintains the _contents array automatically when you use these methods to create and delete child elements.

Note. We strongly advise againt manually updating the _contents array as it is very error-prone.

Adding Elements

The method daeElement::createAndPlace creates a new element as a child of the current element. It places the new element in the appropriate field of its parent element based on the className parameter provided in the method invocation.

The following example demonstrates how to add a new light to an existing library of lights:

// Add a new light to the library
domLight *newLight = daeSafeCast<domLight>(myLib->createAndPlace(COLLADA_ELEMENT_LIGHT));
// Now you can add data to the new light.
Note: The daeElement::create* methods work with element tag names, not element types. When using the string constants provided in domConstants.h, use the COLLADA_ELEMENT_* value and not the COLLADA_TYPE_*. This is in contrast to working with the database, which uses element types.

Removing Elements

To remove a child element from its parent element, you can use either of the following methods; the results are identical, but one might better suit your coding style:

  • daeElement::removeChildElement
  • daeElement::removeFromParent, which is a static method that finds the parent object automatically.

The following example demonstrates one way to remove a light from a library of lights:

daeElement* lightParent = myLight->getParentElement();
// Remove the light
daeBool removed = lightParent->removeChildElement(myLight);

Here is the other method:

// Remove the light from its parent
daeBool removed = daeElement::removeFromParent(myLight);

Moving Elements

To move an element from one parent to another, use daeElement::placeElement. placeElement handles all the "bookkeeping" for you. The element passed to placeElement is removed from its old location and inserted as a child to the element placeElement was called on. If the new parent belongs to a different document, placeElement updates all the document references and the runtime database.

placeElement automatically inserts the new child in a valid location within the parent's content model. There may be many valid locations for the new child, but placeElement inserts the child in the first one available. To insert the new child at a specific location, use the placeElementAt, placeElementBefore, or placeElementAfter methods.

Copying Elements

To copy a DOM element, rather than using the assignment operator, use the daeElement::clone method, which provides a deep copy operation. After the element is cloned, you need to resolve any URIs that have been copied, as clone does not do that automatically.

The DOM type daeString, used in many objects derived from the daeElement class, is a C-style string and not a C++ string class. If you use the assignment operator to copy a daeString, you can end up with a dangling pointer if the original string is deleted.


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