我有一個XSD架構和用於在運行時構建組件的XML文件。這些對象可以具有自定義設置。在XSD文件,這被定義爲:如何使用<x/>而非<x>來反序列化一個空的XML元素</x>
<xs:complexType name="ComponentSettings">
<xs:sequence>
<xs:any minOccurs="0"/>
</xs:sequence>
</xs:complexType>
,並在XSD實例化爲:
<xs:complexType name="Component">
<xs:sequence>
<xs:element name="Version" type="VersionRecord"/>
<xs:element name="Settings" type="ComponentSettings"/>
</xs:sequence>
<xs:attribute name="Name" type="xs:string" use="required"/>
</xs:complexType>
反序列化XML文件時,我邂逅了一個有趣的問題。如果我有一個沒有設置的組件,並且XML看起來像這樣:
<Settings></Settings>
我沒有問題。
然而,如果在XML看起來是這樣的:
<Settings/>
然後反序列化將失敗默默跟隨這個標記和我結束了一個不完整的記錄。
我使用xsd2code產生下面的代碼:
<System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.18060"), _
System.SerializableAttribute(), _
System.ComponentModel.DesignerCategoryAttribute("code"), _
System.Xml.Serialization.XmlRootAttribute([Namespace]:="", IsNullable:=True)> _
Partial Public Class Component
Implements System.ComponentModel.INotifyPropertyChanged
Private versionField As VersionRecord
Private settingsField As System.Xml.XmlElement
Private nameField As String
Private Shared sSerializer As System.Xml.Serialization.XmlSerializer
'''<summary>
'''Component class constructor
'''</summary>
Public Sub New()
MyBase.New()
Me.versionField = New VersionRecord()
End Sub
<System.Xml.Serialization.XmlElementAttribute(Order:=0)> _
Public Property Version() As VersionRecord
Get
Return Me.versionField
End Get
Set(value As VersionRecord)
If (Not (Me.versionField) Is Nothing) Then
If (versionField.Equals(value) <> True) Then
Me.versionField = value
Me.OnPropertyChanged("Version")
End If
Else
Me.versionField = value
Me.OnPropertyChanged("Version")
End If
End Set
End Property
<System.Xml.Serialization.XmlElementAttribute(Order:=2)> _
Public Property Settings() As System.Xml.XmlElement
Get
Return Me.settingsField
End Get
Set(value As System.Xml.XmlElement)
If (Not (Me.settingsField) Is Nothing) Then
If (settingsField.Equals(value) <> True) Then
Me.settingsField = value
Me.OnPropertyChanged("Settings")
End If
Else
Me.settingsField = value
Me.OnPropertyChanged("Settings")
End If
End Set
End Property
<System.Xml.Serialization.XmlAttributeAttribute()> _
Public Property Name() As String
Get
Return Me.nameField
End Get
Set(value As String)
If (Not (Me.nameField) Is Nothing) Then
If (nameField.Equals(value) <> True) Then
Me.nameField = value
Me.OnPropertyChanged("Name")
End If
Else
Me.nameField = value
Me.OnPropertyChanged("Name")
End If
End Set
End Property
#Region "Serialize/Deserialize"
'''<summary>
'''Serializes current Component object into an XML document
'''</summary>
'''<returns>string XML value</returns>
Public Overridable Overloads Function Serialize(ByVal encoding As System.Text.Encoding) As String
Dim streamReader As System.IO.StreamReader = Nothing
Dim memoryStream As System.IO.MemoryStream = Nothing
Try
memoryStream = New System.IO.MemoryStream()
Dim xmlWriterSettings As System.Xml.XmlWriterSettings = New System.Xml.XmlWriterSettings()
xmlWriterSettings.Encoding = encoding
Dim xmlWriter As System.Xml.XmlWriter = xmlWriter.Create(memoryStream, xmlWriterSettings)
Serializer.Serialize(xmlWriter, Me)
memoryStream.Seek(0, System.IO.SeekOrigin.Begin)
streamReader = New System.IO.StreamReader(memoryStream)
Return streamReader.ReadToEnd
Finally
If (Not (streamReader) Is Nothing) Then
streamReader.Dispose()
End If
If (Not (memoryStream) Is Nothing) Then
memoryStream.Dispose()
End If
End Try
End Function
Public Overridable Overloads Function Serialize() As String
Return Serialize(Encoding.UTF8)
End Function
'''<summary>
'''Deserializes workflow markup into an Component object
'''</summary>
'''<param name="xml">string workflow markup to deserialize</param>
'''<param name="obj">Output Component object</param>
'''<param name="exception">output Exception value if deserialize failed</param>
'''<returns>true if this XmlSerializer can deserialize the object; otherwise, false</returns>
Public Overloads Shared Function Deserialize(ByVal xml As String, ByRef obj As Component, ByRef exception As System.Exception) As Boolean
exception = Nothing
obj = CType(Nothing, Component)
Try
obj = Deserialize(xml)
Return True
Catch ex As System.Exception
exception = ex
Return False
End Try
End Function
Public Overloads Shared Function Deserialize(ByVal xml As String, ByRef obj As Component) As Boolean
Dim exception As System.Exception = Nothing
Return Deserialize(xml, obj, exception)
End Function
Public Overloads Shared Function Deserialize(ByVal xml As String) As Component
Dim stringReader As System.IO.StringReader = Nothing
Try
stringReader = New System.IO.StringReader(xml)
Return CType(Serializer.Deserialize(System.Xml.XmlReader.Create(stringReader)), Component)
Finally
If (Not (stringReader) Is Nothing) Then
stringReader.Dispose()
End If
End Try
End Function
'''<summary>
'''Serializes current Component object into file
'''</summary>
'''<param name="fileName">full path of outupt xml file</param>
'''<param name="exception">output Exception value if failed</param>
'''<returns>true if can serialize and save into file; otherwise, false</returns>
Public Overridable Overloads Function SaveToFile(ByVal fileName As String, ByVal encoding As System.Text.Encoding, ByRef exception As System.Exception) As Boolean
exception = Nothing
Try
SaveToFile(fileName, encoding)
Return True
Catch e As System.Exception
exception = e
Return False
End Try
End Function
Public Overridable Overloads Function SaveToFile(ByVal fileName As String, ByRef exception As System.Exception) As Boolean
Return SaveToFile(fileName, Encoding.UTF8, exception)
End Function
Public Overridable Overloads Sub SaveToFile(ByVal fileName As String)
SaveToFile(fileName, Encoding.UTF8)
End Sub
Public Overridable Overloads Sub SaveToFile(ByVal fileName As String, ByVal encoding As System.Text.Encoding)
Dim streamWriter As System.IO.StreamWriter = Nothing
Try
Dim xmlString As String = Serialize(encoding)
streamWriter = New System.IO.StreamWriter(fileName, False, encoding.UTF8)
streamWriter.WriteLine(xmlString)
streamWriter.Close()
Finally
If (Not (streamWriter) Is Nothing) Then
streamWriter.Dispose()
End If
End Try
End Sub
'''<summary>
'''Deserializes xml markup from file into an Component object
'''</summary>
'''<param name="fileName">string xml file to load and deserialize</param>
'''<param name="obj">Output Component object</param>
'''<param name="exception">output Exception value if deserialize failed</param>
'''<returns>true if this XmlSerializer can deserialize the object; otherwise, false</returns>
Public Overloads Shared Function LoadFromFile(ByVal fileName As String, ByVal encoding As System.Text.Encoding, ByRef obj As Component, ByRef exception As System.Exception) As Boolean
exception = Nothing
obj = CType(Nothing, Component)
Try
obj = LoadFromFile(fileName, encoding)
Return True
Catch ex As System.Exception
exception = ex
Return False
End Try
End Function
Public Overloads Shared Function LoadFromFile(ByVal fileName As String, ByRef obj As Component, ByRef exception As System.Exception) As Boolean
Return LoadFromFile(fileName, Encoding.UTF8, obj, exception)
End Function
Public Overloads Shared Function LoadFromFile(ByVal fileName As String, ByRef obj As Component) As Boolean
Dim exception As System.Exception = Nothing
Return LoadFromFile(fileName, obj, exception)
End Function
Public Overloads Shared Function LoadFromFile(ByVal fileName As String) As Component
Return LoadFromFile(fileName, Encoding.UTF8)
End Function
Public Overloads Shared Function LoadFromFile(ByVal fileName As String, ByVal encoding As System.Text.Encoding) As Component
Dim file As System.IO.FileStream = Nothing
Dim sr As System.IO.StreamReader = Nothing
Try
file = New System.IO.FileStream(fileName, FileMode.Open, FileAccess.Read)
sr = New System.IO.StreamReader(file, encoding)
Dim xmlString As String = sr.ReadToEnd
sr.Close()
file.Close()
Return Deserialize(xmlString)
Finally
If (Not (file) Is Nothing) Then
file.Dispose()
End If
If (Not (sr) Is Nothing) Then
sr.Dispose()
End If
End Try
End Function
#End Region
#Region "Clone method"
'''<summary>
'''Create a clone of this Component object
'''</summary>
Public Overridable Function Clone() As Component
Return CType(Me.MemberwiseClone, Component)
End Function
#End Region
End Class
我很好奇爲什麼發生這種情況,以及是否有辦法不遇到此。
作爲一個說明,我知道我可以做之前,反序列化一個正則表達式替換。我正在尋找更具體的東西。 – VoteCoffee