我有以下用户更改的XML文档:
<?xml version="1.0" encoding="utf-8" ?>
<Cfg xmlns="AddIn" version="161012">
<SQLConnectionString version="161012">SomeConnectionString</SQLConnectionString>
<Locale version="161012">
<Language version="161013">de-DE</Language>
<LocalSetting version="161012">en-US</LocalSetting>
</Locale>
</Cfg>
这是最初的文件:
<?xml version="1.0" encoding="utf-8" ?>
<Cfg xmlns="AddIn" version="161012">
<SQLConnectionString version="161012">SomeConnectionString</SQLConnectionString>
<Locale version="161012">
<Language version="161012">en-US</Language>
<LocalSetting version="161012">en-US</LocalSetting>
</Locale>
</Cfg>
有些用户将语言更改为&#34; de-DE&#34;。属性&#34;版本&#34;已更新。
用户修改的文档已序列化为以下类:
<Serializable()>
Public Class Cfg
Private Shared CONFIG_LOCATION As String = GetFolderPath(SpecialFolder.ApplicationData) & "\MyProgram\"
Private Shared CONFIG_FNAME As String = "Cfg.xml"
Private Shared CONFIG_FULLPATH As String = CONFIG_LOCATION & CONFIG_FNAME
Private Shared CONFIG_ASSEMBLY_PATH As String = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) & "\cfg\"
#Region "Singleton"
Private Shared ReadOnly _instance As New System.Lazy(Of Cfg)(Function()
'Write and read
Dim _Cfg As New Cfg
If Not File.Exists(CONFIG_FULLPATH) Then
'copy xml config file
If Not Directory.Exists(CONFIG_LOCATION) Then
Directory.CreateDirectory(CONFIG_LOCATION)
End If
File.Copy(CONFIG_ASSEMBLY_PATH & CONFIG_FNAME, CONFIG_FULLPATH)
Else
'This is the point where I need to apply the updates to the xml document
End If
Dim helper = New XmlSerializerHelper(Of Cfg)()
_Cfg = helper.Read(CONFIG_FULLPATH)
Return _Cfg
End Function, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication)
Public Shared ReadOnly Property Instance() As Cfg
Get
Return _instance.Value
End Get
End Property
#End Region
Private _Locale As Locale
Private _SQLConnectionString As String
Public Property Locale() As Locale
Get
Return _Locale
End Get
Set(value As Locale)
_Locale = value
End Set
End Property
Public Property SQLConnectionString As String
Get
Return _SQLConnectionString
End Get
Set(value As String)
_SQLConnectionString = value
End Set
End Property
Private Sub New()
End Sub
Public Function SaveConfigData() As Boolean
Dim helper = New XmlSerializerHelper(Of Cfg)()
Dim obj = Me
helper.Save(CONFIG_FNAME, obj)
Return True
End Function
End Class
<Serializable()>
Public Class Locale
Private _Language As String
Public Property Language As String
Get
Return _Language
End Get
Set(value As String)
_Language = value
End Set
End Property
Private _LocalSetting As String
Public Property LocalSetting As String
Get
Return _LocalSetting
End Get
Set(value As String)
_LocalSetting = value
End Set
End Property
Public Sub New()
End Sub
End Class
我现在的问题是,如果由于SQL连接字符串已更改而更新源XML文件,我将覆盖该语言的自定义设置。
具有更新的ConnectionString的新配置文件:
<?xml version="1.0" encoding="utf-8" ?>
<Cfg xmlns="AddIn" version="161012">
<SQLConnectionString version="161013">ThisIsTheNewConnectionString</SQLConnectionString>
<Locale version="161012">
<Language version="161012">en-US</Language>
<LocalSetting version="161012">en-US</LocalSetting>
</Locale>
</Cfg>
这应该是这样的:
<?xml version="1.0" encoding="utf-8" ?>
<Cfg xmlns="AddIn" version="161012">
<SQLConnectionString version="161013">ThisIsTheNewConnectionString</SQLConnectionString>
<Locale version="161012">
<Language version="161013">de-DE</Language>
<LocalSetting version="161012">en-US</LocalSetting>
</Locale>
</Cfg>
我已经尝试过以下方法: how to Update a node in xml? 这实际上有效,但我无法将其实现到我的懒惰类中。 这也是我发现的:How would you compare two XML Documents? 我对所有这些解决方案的主要问题是,我无法在初始化期间结合序列化来管理惰性类。
答案 0 :(得分:0)
因为我无法在没有帮助的情况下从上面保留XML布局,所以这就是我想出来的,实际上它就像魅力一样!
<Serializable>
<XmlRoot(ElementName:="Cfg", [Namespace]:="YourNSGoesHere")>
Public Class Cfg
Private Shared CONFIG_LOCATION As String = GetFolderPath(SpecialFolder.ApplicationData) & "\MyProgram\"
Private Shared CONFIG_FNAME As String = "Cfg.xml"
Private Shared CONFIG_FULLPATH As String = CONFIG_LOCATION & CONFIG_FNAME
Private Shared CONFIG_ASSEMBLY_PATH As String = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) & "\cfg\"
#Region "Singleton"
Private Shared ReadOnly _instance As New System.Lazy(Of Cfg)(Function()
Dim _Cfg As New Cfg
Dim helper = New XmlSerializerHelper(Of Cfg)()
Dim bDirtyFlag As Boolean
'check if config file already exists
If Not File.Exists(CONFIG_FULLPATH) Then
If Not Directory.Exists(CONFIG_LOCATION) Then
Directory.CreateDirectory(CONFIG_LOCATION)
End If
'if not, serialize standard data
helper.Save(CONFIG_FULLPATH, _Cfg)
Else
'This is the point where I need to apply the updates to the xml document
End If
'else, read xml file
_Cfg = helper.ReadUserConfig(CONFIG_FULLPATH)
'example patch routine to update obsolete data in stored user files
If _Cfg.SQLConnectionString.Version < DEF_SQLConnectionString.Version Then
_Cfg.SQLConnectionString = DEF_SQLConnectionString
bDirtyFlag = True
End If
If bDirtyFlag Then
helper.Save(CONFIG_FULLPATH, _Cfg)
End If
Return _Cfg
End Function, System.Threading.LazyThreadSafetyMode.ExecutionAndPublication)
Public Shared ReadOnly Property Instance() As Cfg
Get
Return _instance.Value
End Get
End Property
#End Region
Private _SQLConnectionString As String
Private _Locale As Locale
Public Property SQLConnectionString() As PropertyModel(Of String)
Get
Return _SQLConnectionString
End Get
Set
_SQLConnectionString = Value
End Set
End Property
Public Property Locale() As Locale
Get
Return _Locale
End Get
Set
_Locale = Value
End Set
End Property
#Region "DefaultData"
Private Shared ReadOnly DEF_Locale = New Locale() With {
.LocalSetting = New PropertyModel(Of String)() With {
.Value = "en-US",
.Version = 1476434998759
},
.Language = New PropertyModel(Of String)() With {
.Value = "en-US",
.Version = 1476434998759
}
}
Private Shared ReadOnly DEF_SQLConnectionString = New PropertyModel(Of String)() With {
.Value = "SomeConnectionString",
.Version = 1476434998791 'Timestamp of the creation. If a new value has to be applied by default, just update the timestamp
}
Private Sub New()
_SQLConnectionString = DEF_SQLConnectionString
_Locale = DEF_Locale
End Sub
#End Region
Public Function SaveConfigData() As Boolean
Dim helper = New XmlSerializerHelper(Of Cfg)()
Dim obj = Me
helper.Save(CONFIG_FNAME, obj)
Return True
End Function
End Class
<Serializable>
Public Class PropertyModel(Of T)
Private _Version As Long
Private _Value As T
<XmlAttribute>
Public Property Value() As T
Get
Return _Value
End Get
Set
_Value = Value
End Set
End Property
<XmlAttribute>
Public Property Version() As Long
Get
Return _Version
End Get
Set
_Version = Value
End Set
End Property
End Class
<Serializable>
Public Class Locale
Private _Language As PropertyModel(Of String)
Private _LocalSetting As PropertyModel(Of String)
Public Property Language() As PropertyModel(Of String)
Get
Return _Language
End Get
Set
_Language = Value
End Set
End Property
Public Property LocalSetting() As PropertyModel(Of String)
Get
Return _LocalSetting
End Get
Set
_LocalSetting = Value
End Set
End Property
End Class
'i got this code from SO but i can't remember where, credits go out to creator!
Public Class XmlSerializerHelper(Of T)
Public _type As Type
Public Sub New()
_type = GetType(T)
End Sub
Public Sub Save(ByVal SavePath As String, obj As Object)
Using textWriter As TextWriter = New StreamWriter(SavePath)
Dim serializer As New XmlSerializer(_type)
serializer.Serialize(textWriter, obj)
End Using
End Sub
Public Function ReadUserConfig(ByVal LocalXMLPath As String) As T
Dim result As T
Using textReader As TextReader = New StreamReader(LocalXMLPath)
Dim deserializer As New XmlSerializer(_type)
Try
result = DirectCast(deserializer.Deserialize(textReader), T)
Catch ex As Exception
MsgBox(ex.Message & Chr(13) & ex.StackTrace)
End Try
End Using
Return result
End Function
End Class
这会产生以下XML输出:
<?xml version="1.0" encoding="utf-8"?>
<Cfg xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="YourNSGoesHere">
<Locale>
<Language Value="en-US" Version="1476434998759" />
<LocalSetting Value="en-US" Version="1476434998759" />
</Locale>
<SQLConnectionString Value="SomeConnectionString" Version="1476434998791" />
</Cfg>
我希望这会帮助别人。我会很高兴任何补充或优化。