OpenSim uses XML files (.osim or .xml) to store models and analysis objects. Backward compatibility is maintained through a versioning system and the updateFromXMLNode hook.
Key Concepts
- Version Number: Every file includes a version number in the header (e.g.,
<OpenSimDocument Version="NNNNN">). This number must be monotonically increasing and must match the content of the file. The version is managed in XMLDocument.cpp. - Serialization/Deserialization: Properties use macros like
OpenSim_DECLARE_UNNAMED_PROPERTY to handle XML layout. If you change a property name or layout, you must increment the version number and update the deserialization code. - The
updateFromXMLNode Hook: This is the primary mechanism for handling format changes. When an object is instantiated from XML, updateFromXMLNode(SimTK::Xml::Element& node, int versionNumber) is called. Developers can use this method to manipulate the node (the XML element) to match the current code's expected schema before calling the base class implementation.
Implementation Pattern
If an object requires format updates, implement updateFromXMLNode as follows:
void XXX::updateFromXMLNode(SimTK::Xml::Element& node, int versionNumber)
{
// Guard against re-converting already updated files
if ( versionNumber < XMLDocument::getLatestVersion()) {
if (versionNumber <= 20301) {
// convert node from version 20301 or prior to the next version
……
}
if (versionNumber < 30500) {
// Convert versions before 30500
}
}
// At this point, node is on the latest XML format.
// Call base class to populate Property values.
Super::updateFromXMLNode(node, versionNumber);
}
void XXX::updateFromXMLNode(SimTK::Xml::Element& node, int versionNumber)
{
if ( versionNumber < XMLDocument::getLatestVersion()) {
if (versionNumber <= 20301) {
// convert node from version 20301 or prior to the next version
……
}
if (versionNumber < 30500) {
// Convert versions before 30500
}
}
Super::updateFromXMLNode(node, versionNumber);
}