My preferred approach is, essentially, the reverse of the xml system I used for input of game data, a system which I consider to have been very successful.
Every object to be saved will require a save accessor in the form of
float saveAmount() for example. Under most circumstances
this would just call the equivalent get function, but the save function
allows more flexility. It will also require a matching restore method.
Each saveable object must also implement an
Object difference(Object object) method which returns an object
recording the differences between the saveable objects (the earlier one
being the parameter), and an update method which "adds" the parameter
object to the current object. Successive application of this will produce
the most up to date version of tbe game.
It will also allow any particular turn to be restored. The advantages of this for debugging are obvious. Any such restoration, however, will destroy any saved later turns for the game. Branches of this type can be saved, however, by an explicit save.
Where, within an object, another Saveable object is part of the data (for example units within a task force) a reference method, by name, will be needed for the contained or referenced object.
The file will be a zip file called <game name>, with an inner file for the setup (probably a copy of the scenario file) called setup.xml, and files called turn1.xml, turn2.xml, and so forth. If there are performance problems, every so often (every 10 turns perhaps), current situation file, current10, for example, might be interpolated. This will be only be done if and when it becomes necessary.
Because the file consists of zipped xml I do not expect any space problems to occur. In fact I confidently expect that our save file (and remember it needs only one per game, not one per turn) will be no larger than the equivalent in other games.