我有一個類似于以下內容的 XML 檔案,它是從一組模型和屬性上的 XML 注釋序列化的。
<?xml version="1.0"?>
<RootElement xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SomeAttribute="123">
<ChildElementList>
<SampleElement xsi:type="SampleElementX" SampleElementSomeAttribute="456">
<AnotherSampleElementList/>
</SampleElement >
</ChildElementList>
</RootElement >
我嘗試使用新創建的 POCO 結構反序列化現有 XML 檔案。
為了能夠反序列化檔案,我需要將元素和屬性名稱與我的 POCO 物件匹配,但是,更改 POCO 類的名稱和屬性不是一個選項,因此我決定在期間重命名必要的元素和屬性讀操作。
我可以毫無問題地讀取和反序列化 RootElement 的屬性。
當我使用 XML Reader 讀取 XML 檔案時,每當我到達“ChildElementList”時,代碼都會進入 Skip。但是,我還想讀取和反序列化該串列中的每個元素。為什么會發生這種情況,我該如何解決這個問題?我真的很感激一些幫助。
我有一個類似于以下的結構
XML 閱讀器覆寫
Public Class CustomTextReader
Inherits XmlTextReader
Protected ReadOnly provider As XmlReadWriteProvider
Public Sub New(input As Stream)
MyBase.New(input)
End Sub
Public Sub New(provider As XmlReadWriteProvider, input As Stream)
MyBase.New(input)
Me.provider = provider
End Sub
Public Overrides Sub Skip()
MyBase.Skip()
End Sub
Public Overrides ReadOnly Property LocalName As String
Get
Return GetElementName(MyBase.LocalName)
End Get
End Property
Public Overrides ReadOnly Property Name As String
Get
Return GetElementName(MyBase.Name)
End Get
End Property
Public Overrides Function GetAttribute(localName As String, namespaceURI As String) As String
Dim att As String = MyBase.GetAttribute(localName, namespaceURI)
Return If(att IsNot Nothing, If(att = att.EndsWith("X"), att.Replace(att.Substring(-1, 1), "POCO"), att "POCO"), att)
End Function
Function IsExcludedNode(nodeName As String) As Boolean
Return excludeNodes.Contains(nodeName)
End Function
Function GetElementName(elementName As String) As String
If MyBase.NodeType <> XmlNodeType.Element Then Return elementName
If IsExcludedNode(elementName) Then Return elementName
Return elementName "POCO"
End Function
End Class
序列化
Public Shared Function Deserialize(Of T)(fileName As String, extraTypes As Type()) As T
Using xmlFileStream As FileStream = New FileStream(fileName, FileMode.Open)
Using customXmlReader As XmlReader = XmlReadWriteProvider.GetXmlReader(GetType(T), xmlFileStream)
Dim xmlSerializer As XmlSerializer = GetXmlSerializer(GetType(T), GetXmlAttributeOverrides(extraTypes), extraTypes, Nothing, Nothing)
Deserialize = CType(xmlSerializer.Deserialize(customXmlReader), T)
End Using
End Using
Return Deserialize
End Function
Shared Function GetXmlSerializer(type As Type, [overrides] As XmlAttributeOverrides, extraTypes() As Type, root As XmlRootAttribute, defaultNamespace As String) As XmlSerializer
Dim customXmlSerializer As XmlSerializer = Nothing
customXmlSerializer = New XmlSerializer(type, [overrides], extraTypes, root, defaultNamespace)
Return customXmlSerializer
End Function
'Add XML attribute tag to the properties of all known extra types.
Private Shared Function GetXmlAttributeOverrides(extraTypes As Type()) As XmlAttributeOverrides
Dim xmlAttributeOverrides = New XmlAttributeOverrides
For Each type In extraTypes
AddAttributeOverrides(type, xmlAttributeOverrides)
Next
Return xmlAttributeOverrides
End Function
Private Shared Sub AddAttributeOverrides(type As Type, xmlAttributeOverrides As XmlAttributeOverrides)
For Each propertyInfo In type.GetProperties
xmlAttributeOverrides.Add(type, propertyInfo.Name, GetXmlAttribute(propertyInfo))
Next
End Sub
'If object is a primitive type it's an attribute, if it's a list it's an element
Shared Function GetXmlAttribute(propertyInfo As PropertyInfo) As XmlAttributes
If propertyInfo.IsPrimitive() Then
Return New XmlAttributes With {.XmlAttribute = New XmlAttributeAttribute With {.AttributeName = propertyInfo.Name}}
End If
If GetType(IEnumerable).IsAssignableFrom(propertyInfo.PropertyType) Then
Return New XmlAttributes With {.XmlArray = New XmlArrayAttribute With {.ElementName = propertyInfo.Name}}
End If
Return New XmlAttributes
End Function
<System.Runtime.CompilerServices.Extension>
Private Function IsPrimitiveInternal(t As Type) As Boolean
Return t.IsPrimitive OrElse t.IsValueType OrElse (t = GetType(String))
End Function
<System.Runtime.CompilerServices.Extension>
Function IsPrimitive(p As MemberInfo) As Boolean
Return IsPrimitiveInternal(If(TryCast(p, PropertyInfo)?.PropertyType, p))
End Function
<System.Runtime.CompilerServices.Extension>
Public Function GetListItemType(IEnumerableType As Type) As Type
If IEnumerableType.IsGenericType AndAlso IEnumerableType.GetGenericTypeDefinition() Is GetType(List(Of)) Then
Return IEnumerableType.GetGenericArguments(0)
End If
Return Nothing
End Function
更新: 我意識到不修改元素名稱時它可以正常作業。
考慮到我的 POCO 類名是“SampleObjectPOCO”,請參見以下行
Return elementName "POCO"
以下
Function GetElementName(elementName As String) As String
If MyBase.NodeType <> XmlNodeType.Element Then Return elementName
If IsExcludedNode(elementName) Then Return elementName
Return elementName "POCO" 'Not Working when the XML property name is "SampleElement"
End Function
如果我的 XML 檔案具有元素名稱“SampleElementPOCO”而不是“SampleElement”,則它可以正常作業。當我在上面的行中動態更改它時,它停止作業。
Function GetElementName(elementName As String) As String
If MyBase.NodeType <> XmlNodeType.Element Then Return elementName
If IsExcludedNode(elementName) Then Return elementName
Return elementName 'Working when the XML property name is "SampleElementPOCO"
End Function
uj5u.com熱心網友回復:
最后,我發現 XmlTextReader 不支持更改 XML 元素的名稱。
我使用 Xml.Linq 將 XML 檔案讀入 XDocument 并執行以下操作
Public Shared Function XMLTransformer(filepath As String) As XDocument
Dim doc = XDocument.Load(filepath)
Dim xsiNameSpace As XNamespace = "http://www.w3.org/2001/XMLSchema-instance"
For Each element As XElement In doc.Descendants
Dim typeAttribute As XAttribute = element.Attribute(xsiNameSpace "type")
If typeAttribute IsNot Nothing Then
typeAttribute.Value = If(typeAttribute.Value.EndsWith("X"), typeAttribute.Value.Replace(typeAttribute.Value.Substring(typeAttribute.Value.Length - 1, 1), "POCO"), typeAttribute.Value "POCO")
End If
If element.NodeType = XmlNodeType.Element AndAlso element.Attributes.Count > 0 Then
element.Name = element.Name.ToString "POCO"
End If
Next
End Function
然后我把它交給序列化器如下
SerializationManager.Deserialize(Of T)(SerializationHelper.GetExtraTypes,SerializationHelper.XMLTransformer(fileName))
我還創建了一個反序列化多載,如下所示
Public Shared Function Deserialize(Of T)(extraTypes As Type(), xmlContent As XDocument) As T
Dim xmlSerializer As XmlSerializer = New XmlSerializer(GetType(T), GetXmlAttributeOverrides(extraTypes), extraTypes, Nothing, Nothing)
Return CType(xmlSerializer.Deserialize(xmlContent.Root.CreateReader), T)
End Function
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/505911.html
標籤:xml VB.net 序列化 xml 解析 xml阅读器
上一篇:MicronautJAR拋出BeanInstantiationException,但在使用IntelliJ運行時不會
下一篇:Linux 壓縮、解壓縮命令
