I’m assuming the rotations need to be done in order, but why are there two different rotations about each of the x, y and z axes, and what space are these axes defined in?

Do I need to do the translation before the rotations?

Actually I find this a very confusing statement in the spec.

Basically the order matters, and you should use the ‘getContents’ to iterate over the proper order of transforms (<lookat>,<matrix>,<rotate>,<scale>,<scew>,<translate>) and build the resulting matrix, using post-multiplication (as if each individual transform element first was converted to a matrix).

According to the Collada 1.4.1 spec:

Rotations change the orientation of objects in a coordinated system without any translation.
Translations change the position of objects in a coordinate system without any rotation

I wonder what this ‘without translation’ part in the <rotate> and ‘without rotation’ in the <translate> part is refering too?
Those transforms act in a local coordinate system, and they concatenate in order, so they include all translate’s, rotate’s and others (scale etc) previous applied in all the transforms in this node’s transform stack. In a node-hierarchy, they also include all transforms (rotates,translates etc) from its parent… That’s why ‘without translation’ and ‘without rotation’ is confusing: the local coordinate system does include translation/rotation.