Do you version your .xml files?

Last updated by Brady Stroud [SSW] over 1 year ago.See history

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>

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>

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.

We open source. Powered by GitHub