XML in FlexSim
Introduction
FlexSim saves its models, library and tree files in XML format. There are many advantages to using this capability in your model development, including:
- Since XML is an ascii/text based format, it increases the utility of using content management and versioning software such as Subversion, CVS, Microsoft Visual SourceSafe, git, etc. to manage the development of a model. These systems automatically track a history of changes to a model or project, and for ascii/text based files, they allow you to see line-by-line change logs for the files, as well as revert line-item changes if needed.
- With the added benefit of versioning systems comes the ability to develop a model concurrently by different modelers using a much more stream-lined method. No more saving off individual t files from one modeller's changes to a model and loading them manually into the master model. When saving to XML format, if one modeller is working on one portion of the model, only that portion of the model file changes when saved, so when the modeller checks his changes into the versioning system's repository, another modeller can automatically merge those changes into his copy. If there are conflicts, where two modellers change the same part of the model, then the versioning system has tools that allow modellers to easily see in the XML file where the conflicts occur and quickly perform the manual conflict resolution.
- FlexSim also has the added ability to distribute a single model across multiple XML files. This increases your control over how to manage the model development in your versioning system, and makes conflict resolution even easier.
- The distributed save mechanism also opens the door for much more automated control of FlexSim. By saving small pieces of your model off into separate XML files, you can auto-regenerate one or more of those XML files outside of FlexSim, consequently changing the configuration of the model for the purpose of running different scenarios.
Build a Simple Model
First build a simple example model containing a Source, Queue, Processor and Sink.
Save in XML Format
Save the model, and in the save dialog, choose "FlexSim XML" from the drop-down at the bottom. Save the model as "PostOfficeXML.fsx".
Now you've saved the file in FlexSim's XML format. You can view the file in a regular text editor like Notepad, Visual Studio, Notepad++, EditPlus, etc.
Unless you plan on doing automated changes to the XML file, it's not necessary to know all the details of the file format. In simple terms, the primary tag in FlexSim XML is the <node> tag, representing a node in FlexSim. The node's name is described in the <name> tag, and the node's data, if applicable, is described in the <data> tag. If you do plan on doing automated changes, and need a more detailed definition of the xml format, you can refer to FlexSim's xml schema.
Version Management Utilities
To give you a better idea of the advantages of using an XML format, we'll go through some of the things that you might do with a versioning system. At FlexSim we use Git and various client-side UI tools, such as Fork, Git Extensions, or Sourcetree. Details of installing and configuring a version management system are outside the scope of this tutorial. You can find many install and setup helps online. As part of this tutorial we will simply assume that, once the model has been saved, a repository is set up for the model.
When using a version control system with Windows Explorer integration, such as TortoiseSVN or TortoiseHg, unmodified files will appear with a green icon indicating that your copy is "clean", or you haven't made any changes since your last check-in.
Now let's say we make a small change to the model, such as moving the Queue to a different location and then saving the model again.
Once saved, you'll notice that the file's icon has changed to a red symbol, meaning the file is "dirty", or it has changed since the last check-in. You can also right-click the file, and see exactly what's changed by choosing the "Diff" operation. This will give you a difference comparison of your current copy of the file with the last version that you checked-in.
Various version control software products provide a simple diff utility, but you can also configure them to use a third-party comparison tool such as WinMerge or kdiff3.
Using the diff tool you can see where the model has been changed, namely in spatialx and spatialy attributes. You can revert line-item changes in the diff tool if you don't want those changes applied.
Distributed Save
Next let's distribute the model across multiple files. To do this you create a "FlexSim File Map" file. This is an xml file with the .ffm extension. It must be placed in the same directory as the model's .fsx file, and, except for the extension, must be given the same name as the .fsx file. So, let's create that file. Let's also create a subdirectory to put the distributed files into.
Now edit PostOfficeXML.ffm in a text editor. The first thing we'll do is put the node model/Tools/Workspace into a different file. This is something you'll probably want to do always if you're using version management. The node model/Tools/Workspace stores all of the windows open in the model, so if you're editing a model and change or reposition the windows that are open, that will change the model file. For version management this is often just static that doesn't need to be tracked, so we'll have the node saved off to a different file, and then we can just never (or at least rarely) check that file into the version management system. Specify the following code:
<?xml version="1.0" encoding="UTF-8"?>
<flexsim-file-map version="1">
<map-node path="/Tools/Workspace" file="distributedfiles\windows.fsx" file-map-method="single-node"/>
</flexsim-file-map>
Save the file map, then go back into FlexSim. Save the post office model again under the same name "PostOfficeXML.fsx". Now look in the distributedfiles directory. You'll see that it contains a new xml file named windows.fsx. This xml holds the definition of the node model/Tools/Workspace. All interaction with the model remains the same, i.e. from FlexSim you just load and save the main xml model file, but now the model is distributed across multiple files.
In the file map, the main document element is the <flexsim-file-map> tag. Inside the main document element should be any number of <map-node> elements. Each <map-node> element should have a path attribute, a file attribute, and a file-map-method attribute. The path attribute should specify the path, from the main saved node, to the node that is going to be saved into the distributed file. The file attribute specifies the path, relative to the saved model file, to the distributed file that you want to save. The file-map-method should either have a value of "single-node" or "split-points". In this case "single-node" means you want to save all of the Workspace node into windows.fsx.
Now let's do an example of the "split-points" method. Let's say we want to save the Tools folder in one file, the Source and Queue into another file, and the Processor and Sink in a third file. To do this, add another <map-node> element to the file map:
<?xml version="1.0" encoding="UTF-8"?>
<flexsim-file-map version="1">
<map-node path="/Tools/Workspace" file="distributedfiles\windows.fsx" file-map-method="single-node"/>
<map-node path="" file="distributedfiles\Tools.fsx" file-map-method="split-points">
<split-point name="Source1" file="distributedfiles\Source_Queue.fsx"/>
<split-point name="Processor3" file="distributedfiles\Processor_Sink.fsx"/>
</map-node>
</flexsim-file-map>
Now save the file, save your FlexSim model, and again you'll see new files created in the distributedfiles directory.
If a <map-node> element uses the "split-points" method, then it can have <split-point> sub-elements. Each split-point should have a name, defining the name of a node inside the map-node's defined node, and a file attribute defining the file to save to. The map-node has a path="" attribute. This means that it applies to the root node, or the model itself. The map-node's file attribute defines the first file to use. This configuration tells FlexSim to save all sub-nodes in the model up to but not including the node named "Source1" to the file "distributedfiles\Tools.fsx", save everything from Source1 up to but not including the node named "Processor3" in "distributedfiles\Source_Queue.fsx", and save everything from Processor3 to the end in "distributedfiles\Processor_Sink.fsx".
Why Distribute?
The main reason you would want to distribute your model across multiple files is for version management. It allows you to easily see what you've changed in your model by seeing what files, and consequently which parts of the tree, have changed. If you inadvertently changed one piece of the model, you can easily see that and then revert that change if needed. When multiple modellers are developing the model, one modeller can essentially confine himself to one part of the model tree, and by associating that part of the tree with a specific file, it makes it much easier to merge changes from different developers, it reduces the chance of conflicts in the merge, and makes it easier to do a manual merge if needed.
Saving Connections
One important thing to understand when using XML save is how connections are encoded into the XML file. When encoding connections (i.e. nodes that point to other nodes in the tree), the unique named path to the target node, relative to the root save point, is what is saved in the file.
This can have consequences regarding how you name the objects in your model. If you have multiple objects with the same name, then FlexSim resolves unique paths by using a special '~' (tilda) character. For example, if you have multiple objects named 'Queue' in your model, the first object's unique path, relative to the model, will be /Queue. However, the second object's unique path will be /Queue~2, the third will be /Queue~3, and so forth.
Since connections encode the unique path, then for the second, third, etc., objects with the same name, all connections to that object, such as input, output, and center ports, etc., will be encoded into the XML with /Queue~2 as part of their path. This is fine, but it can have significant implications for source control, specifically regarding model diffs and merging others' changes together. If you were to delete the first object named 'Queue' in your model, or merely change its name to 'MyQueue', then the xml saved paths for all other objects named 'Queue' will change. All connections that previously referenced /Queue~2 will now reference /Queue, all connections that previously referenced /Queue~3 will now reference /Queue~2, and so forth. Thus, just by deleting a single object, you have created xml changes all over your model. This, first of all, creates more diffs that need to be committed than would otherwise be required, and second, creates potential merging issues if other users simultaneously make changes that affect the same parts of the xml file. These merge conflicts are often very difficult to resolve using standard merging tools.
Given these considerations, we strongly advise that you uniquely name objects that are in the same tree layer in the model. By doing this, you can minimize the diffs generated by model changes, and can more easily merge work from multiple modelers.