2016-10-12 171 views
0

我已經由一個用戶更改了下面的XML文檔:更新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> 

一些用戶更改語言來「 DE-DE」。屬性「版本」已更新。

用戶修改後的文檔序列化爲下面的類:

<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文件,我將覆蓋的自定義設置語言。

這裏是我想達到的目標:

<?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> 

我已經嘗試過

有一個更新的ConnectionString

新的配置文件如下: how to Update a node in xml? 這實際上工作,但我無法實現它進入我的懶類。 這也是我也發現的:How would you compare two XML Documents? 我所有這些解決方案的主要問題是,我無法在初始化期間結合序列化來管理惰性類。

回答

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> 

我希望這會幫助別人somewhen。我會很樂意爲任何補充或優化。