DOM guide: Importing documents
Be sure to read the section on creating documents first. It covers some important topics relevant to this section.
A simple example
Let's begin with a simple example of reading some information from a Collada document. We'll open the document and print the ID of the first <node> we find.
DAE dae; daeElement* root = dae.open("simpleImport.dae"); if (!root) { cout << "Document import failed.\n"; return 0; }
We create the DAE object then call DAE::open to open a file called "simpleImport.dae". If there is no file of that name in the current directory, or the file failed to open for some other reason, then the DAE::open method will return null. We check for that and print an error message if opening the document failed.
daeElement* node = root->getDescendant("node"); if (!node) cout << "No nodes found\n"; else cout << "node id: " << node->getAttribute("id") << endl;
Here we use the daeElement::getDescendant method to do a breadth-first search through the xml element tree for an element with the given name. This method will return null if it couldn't find an element with a matching name, which we check for. If it did find a matching element we use the daeElement::getAttribute method to print the value of the 'id' attribute.
The complete code.
#include <iostream> #include <dae.h> #include <dom/domCOLLADA.h> using namespace std; int main() { DAE dae; daeElement* root = dae.open("simpleImport.dae"); if (!root) { cout << "Document import failed.\n"; return 0; } daeElement* node = root->getDescendant("node"); if (!node) cout << "No nodes found\n"; else cout << "node id: " << node->getAttribute("id") << endl; return 0; }
The simpleImport.dae document.
<?xml version="1.0" encoding="UTF-8"?> <COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1"> <asset> <contributor/> <created>2008-04-08T13:07:52-08:00</created> <modified>2008-04-08T13:07:52-08:00</modified> </asset> <library_nodes> <node id="hello"/> </library_nodes> </COLLADA>
And the results of running the program.
node id: hello
Reading data from elements
Any individual xml element has four types of data you might need: the element name, the element's attributes, the element's character data, and the element's child elements. The DOM provides easy access to all of this data via the daeElement interface.
Element name
Use the daeElement::getElementName method to get an element's name.
daeString getElementName() const; // Function signature
cout << elt->getElementName() << endl; // Example: print an element's name
Element attributes
To get the value of an attribute given the attribute's name, use the daeElement::getAttribute method.
std::string getAttribute(daeString name);
We've already seen an example of daeElement::getAttribute usage in the simple import example.
cout << "node id: " << node->getAttribute("id") << endl;
If you don't know what attributes an element has, you can iterate over its attribute list using the following methods of daeElement.
size_t getAttributeCount(); std::string getAttributeName(size_t i); std::string getAttribute(size_t i);
This code snippet prints all the attribute names and values of the root element.
for (size_t i = 0; i < root->getAttributeCount(); i++) { cout << "attr " << i << " name: " << root->getAttributeName(i) << endl; cout << "attr " << i << " value: " << root->getAttribute(i) << endl; }
Character data
You can retrieve an element's character data with the daeElement::getCharData method.
std::string getCharData();
For example, let's say you have an <asset> element and you want to tell if the <up_axis> setting is Z_UP. You could do that as follows.
daeElement* upAxis = asset->getDescendant("up_axis"); if (upAxis && upAxis->getCharData() == "Z_UP") // We have a match!
Child elements
If you know the name of the child element you want, you can access it with daeElement::getChild.
daeElement* getChild(daeString eltName);
This will return null if the element with the given name doesn't exist. You might use this function to test for the existence of a particular child element.
if (root->getChild("asset") == NULL) cout << "Missing <asset> element!\n"
If you don't have a specific element in mind you can get a list of all the child elements instead with the daeElement::getChildren method.
daeTArray< daeSmartRef<daeElement> > getChildren();
It returns an array of smart pointers to daeElement objects, which you can simply treat like ordinary daeElement pointers. You can use daeElement::getChildren to print a list of all the child elements of root like this.
daeTArray<daeElementRef> children = root->getChildren(); for (size_t i = 0; i < children.getCount(); i++) cout << "child " << i << " name: " << children[i]->getElementName() << endl;
daeElementRef is just a typedef for daeSmartRef<daeElement> that's made available to DOM clients to keep code simpler.
The dom* classes
As was mentioned in the creating documents section, the dom* classes provide an alternative interface to working with elements in the DOM. All of the operations discussed so far can be done with the dom* classes instead of the daeElement interface. For example, the code to print the id attribute of the first <node> in the document could've been written like this instead:
domNode* node = (domNode*)root->getDescendant("node"); if (!node) cout << "No nodes found\n"; else cout << "node id: " << node->getId() << endl;
The dom* classes provide a more strongly typed interface to the Collada elements, and sometimes this can be convenient. Use your judgment to decide between the daeElement interface and a dom* class for a given task.