Do you version your .xml files?

Updated by Brady Stroud [SSW] 1 year ago. See history

123

It is good to store program settings in an .xml file. But developers rarely worry about future schema changes and how they will inform the user it is an old schema.

What is wrong with this?

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<xs:schema id="NewDataSet" xmlns=""
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name=NewDataSet" msdata:IsDataSet="true" msdata:Locale="en-AU">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Table1">
<xs:complexType>
<xs:sequence>
<xs:element name="DateUpdated" type="xs:dateTime" minOccurs="0" />
<xs:element name="NewDatabase" type="xs:boolean" minOccurs="0" />
<xs:element name="ConnectionString" type="xs:string" minOccurs="0" />
<xs:element name="SQLFilePath" type="xs:string" minOccurs="0" />
<xs:element name="TimeOut" type="xs:int" minOccurs="0" />
<xs:element name="TurnOnMSDE" type="xs:boolean" minOccurs="0" />
<xs:element name="KeepXMLRecords" type="xs:boolean" minOccurs="0" />
<xs:element name="UserMode" type="xs:boolean" minOccurs="0" />
<xs:element name="ReconcileScriptsMode" type="xs:boolean" minOccurs="0" />
<xs:element name="FolderPath" type="xs:string" minOccurs="0" /> />
<xs:element name="SelectedFile" type="xs:string" minOccurs="0" />
<xs:element name="UpdateVersionTable" type="xs:boolean" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
 </xs:element>
  </xs:schema>
  <Table1>
  <DateUpdated>2004-05-17T10:04:06.9438192+10:00</DateUpdated>
  <NewDatabase>true</NewDatabase>
  <ConnectionString>Provider=SQLOLEDB.1;Integrated Security=SSPI;
Persist Security Info=False;
Data Source=(local);Initial Catalog=master</ConnectionString>
  <SQLFilePath>ver0001.sql</SQLFilePath>
  <TimeOut>5</TimeOut>
  <TurnOnMSDE>false</TurnOnMSDE>
  <KeepXMLRecords>false</KeepXMLRecords>
  <UserMode>true</UserMode>
  <ReconcileScriptsMode>true</ReconcileScriptsMode>
  <FolderPath>C:\Program Files\SSW SQL Deploy\Samples\DatabaseSQLScripts\
</FolderPath>
  <SelectedFile />
  <UpdateVersionTable>true</UpdateVersionTable>
  </Table1>
</NewDataSet>

❌ Figure: Bad example - XML file without version control

<?xml version="1.0" standalone="yes"?>
<NewDataSet>
<xs:schema id="NewDataSet" xmlns=""
  xmlns:xs="http://www.w3.org/2001/XMLSchema"
  xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name=NewDataSet" msdata:IsDataSet="true" msdata:Locale="en-AU">
<xs:complexType>
<xs:choice maxOccurs="unbounded">
<xs:element name="Table1">
<xs:complexType>
<xs:sequence>
<xs:element name="Version" type="xs:string" minOccurs="0" />
<xs:element name="DateUpdated" type="xs:dateTime" minOccurs="0" />
<xs:element name="NewDatabase" type="xs:boolean" minOccurs="0" />
<xs:element name="ConnectionString" type="xs:string" minOccurs="0" />
<xs:element name="SQLFilePath" type="xs:string" minOccurs="0" />
<xs:element name="TimeOut" type="xs:int" minOccurs="0" />
<xs:element name="TurnOnMSDE" type="xs:boolean" minOccurs="0" />
<xs:element name="KeepXMLRecords" type="xs:boolean" minOccurs="0" />
<xs:element name="UserMode" type="xs:boolean" minOccurs="0" />
<xs:element name="ReconcileScriptsMode" type="xs:boolean" minOccurs="0" />
<xs:element name="FolderPath" type="xs:string" minOccurs="0" /> />
<xs:element name="SelectedFile" type="xs:string" minOccurs="0" />
<xs:element name="UpdateVersionTable" type="xs:boolean" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
 </xs:element>
  </xs:schema>
  <Table1>
<Version>1.2</Version>
   <DateUpdated>2004-05-17T10:04:06.9438192+10:00</DateUpdated>
  <NewDatabase>true</NewDatabase>
  <ConnectionString>Provider=SQLOLEDB.1;Integrated Security=SSPI;
Persist Security Info=False;
Data Source=(local);Initial Catalog=master</ConnectionString>
  <SQLFilePath>ver0001.sql</SQLFilePath>
  <TimeOut>5</TimeOut>
  <TurnOnMSDE>false</TurnOnMSDE>
  <KeepXMLRecords>false</KeepXMLRecords>
  <UserMode>true</UserMode>
  <ReconcileScriptsMode>true</ReconcileScriptsMode>
  <FolderPath>C:\Program Files\SSW SQL Deploy\Samples\DatabaseSQLScripts\
</FolderPath>
  <SelectedFile />
  <UpdateVersionTable>true</UpdateVersionTable>
  </Table1>
</NewDataSet>

✅ Figure: Good example - XML file with version control

The version tags identifies what version the file is. This version should be hard coded into the application. Every time you change the format of the file, you would increment this number.

The code below shows how this would be implemented in your project.

Public Function IsXMLFileValid() As Boolean
Dim fileVersion As String = "not specified"
Dim dsSettings As New DataSet
Dim IsMalformed As Boolean = False
' Is the file malformed all together with possibly version
Try
dsSettings.ReadXml(mXMLFileInfo.FullName, XmlReadMode.ReadSchema)
Catch ex As Exception
IsMalformed = True
End Try
If (Not IsMalformed) Then
Dim strm As Stream = Asm.GetManifestResourceStream(Asm.GetName().Name _
+ "." + "XMLFileSchema.xsd")
 Dim sReader As New StreamReader(strm)
 Dim dsXMLSchema As New DataSet
 dsXMLSchema.ReadXmlSchema(sReader)
 If dsSettings.Tables(0).Columns.Contains("Version") Then _
  fileVersion = dsSettings.Tables(0).Rows(0)("Version").ToString
End If
 If fileVersion = "" Then
   fileVersion = "not specified"
  End If
 If fileVersion = Global.XMLFileVersion AndAlso
Not dsSettings.GetXmlSchema() = dsXMLSchema.GetXmlSchema() Then
   Return False
 End If
End If
If IsMalformed OrElse fileVersion <> Global.XMLFileVersion Then
  If mshouldConvertFile Then
  ' Convert the file
  ConvertToCurrentVersion(IsMalformed)
Else
 Throw New XMLFileVersionException(fileVersion, Global.XMLFileVersion )
End If
End If
Return True
End Function

Figure: Code to illustrate how to check if the xml file is valid

Note: to allow backward compatibility, you should give the user an option to convert old xml files into the new version structure.

acknowledgements
related rules