【问题标题】:VB.Net Xml Deserialization into a ClassVB.Net Xml 反序列化成一个类
【发布时间】:2023-12-31 15:32:01
【问题描述】:

我在尝试将一些 XML 反序列化为我创建的类时遇到了一点问题。

我得到的错误是:

There is an error in XML document (1, 2).

   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(TextReader textReader)
   at CommonLayer.InvuManager.FindDocuments(String policy, String year) in C:\GIT\novus\CommonLayer\InvuManager.vb:line 194
   at Novus.NavigationControlRisk.UpdateInvuDocumentsFolderTitle(TreeListNode& documentsFolderNode, String policy, String year) in C:\GIT\novus\Dashboard\src\Dashboard\NavigationControls\NavigationControlRisk.vb:line 3125
   at Novus.NavigationControlRisk.PopulateFolders(TreeListNode parentNode, Boolean isAttachingPolicy, Boolean refreshData) in C:\GIT\novus\Dashboard\src\Dashboard\NavigationControls\NavigationControlRisk.vb:line 1280
   at Novus.NavigationControlRisk.PopulateNode(Boolean refreshData) in C:\GIT\novus\Dashboard\src\Dashboard\NavigationControls\NavigationControlRisk.vb:line 1158
   at Novus.NavigationControlRisk.mainTreeList_MouseClick(Object sender, MouseEventArgs e, Boolean refreshData) in C:\GIT\novus\Dashboard\src\Dashboard\NavigationControls\NavigationControlRisk.vb:line 2340
   at Novus.NavigationControlRisk._Lambda$__R25-1(Object a0, MouseEventArgs a1)
   at System.Windows.Forms.Control.OnMouseClick(MouseEventArgs e)
   at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at DevExpress.XtraEditors.Container.EditorContainer.WndProc(Message& m)
   at DevExpress.XtraTreeList.TreeList.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
   at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
   at Novus.My.MyApplication.Main(String[] Args) in :line 81
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

这是我创建的类,在这一点上没有什么花哨的,我只是想让它工作:

Imports System.Xml.Serialization

<Serializable, XmlRoot("Document")> _
Public Class Document
    <XmlElement("Type")> _
    Public Property Type As String
    <XmlElement("FileName")> _
    Public Property FileName As String
End Class

这是我正在使用的文件中的 XML:

<ArrayOfDocuments>
  <Document>
    <Type>Debit/Credit note</Type>
    <FileName>dbE12901_acc1.doc</FileName>
  </Document>
  <Document>
    <Type>Generic</Type>
    <FileName>a3_lmbc_categories.xls</FileName>
  </Document>
</ArrayOfDocuments>

最后,这是我正在使用的代码:

Dim foundDocuments As New List(Of Document)
Dim xmldoc As New XmlDocument
xmldoc.Load(InterfaceFilePath)
Dim allText As String = xmldoc.InnerXml

Using currentStringReader As New StringReader(allText)
   Dim xml as New XmlSerializer(GetType(List(Of Document)))
   foundDocuments = TryCast(xml.Deserialize(currentStringReader), List(Of Document))
End Using

我一辈子都无法弄清楚为什么它不会反序列化。我的应用程序中有不同类的其他实例,我已经检查过它们的结构方式是相同的,所以我不明白为什么它不起作用。

我需要另一双眼睛来检查我做了什么,有人有什么建议吗?

【问题讨论】:

  • 我也看不出有什么问题。但是尝试另辟蹊径。创建Documents 的列表,然后对其进行序列化并比较生成的 xml。这可能会让你知道什么是错的。 -- 现在想想,你xml的根不应该是&lt;ArrayOfDocument&gt;(单数)吗?
  • Son of a.....Spot on there mate,简直不敢相信就是这样。有时只需要多一双眼睛就能看到你的错误!

标签: xml vb.net deserialization xml-deserialization


【解决方案1】:

感谢 Chris Dunaway,他在上面的其中一个 cmets 中为我解决了这个问题。

是更改 ArrayOfDocuments => ArrayOfDocument

的简单案例

之后就完美了

【讨论】:

    【解决方案2】:

    您可以通过复制 xml 文本然后在 Visual Studio 中自动从 xml 生成类:

    编辑>>选择性粘贴>>将XML粘贴为类

    我这样做了,它产生了课程

    <System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True), _
     System.Xml.Serialization.XmlRootAttribute([Namespace]:="", IsNullable:=False)> _
    Partial Public Class ArrayOfDocuments
        Private documentField() As ArrayOfDocumentsDocument
        <System.Xml.Serialization.XmlElementAttribute("Document")> _
        Public Property Document() As ArrayOfDocumentsDocument()
            Get
                Return Me.documentField
            End Get
            Set(value As ArrayOfDocumentsDocument())
                Me.documentField = value
            End Set
        End Property
    End Class
    
    <System.Xml.Serialization.XmlTypeAttribute(AnonymousType:=True)> _
    Partial Public Class ArrayOfDocumentsDocument
        Private typeField As String
        Private fileNameField As String
        Public Property Type() As String
            Get
                Return Me.typeField
            End Get
            Set(value As String)
                Me.typeField = value
            End Set
        End Property
        Public Property FileName() As String
            Get
                Return Me.fileNameField
            End Get
            Set(value As String)
                Me.fileNameField = value
            End Set
        End Property
    End Class
    

    (手动将自动名称ArrayOfDocumentDocument更改为Document

    这很容易反序列化

    Imports System.Xml.Serialization
    Imports System.IO
    

    Dim s As New XmlSerializer(GetType(ArrayOfDocuments))
    Dim m As ArrayOfDocuments
    Using sr As New StreamReader("XMLFile1.xml")
        m = s.Deserialize(sr)
    End Using
    Dim foundDocuments = m.Document.ToList()
    

    【讨论】:

    • 哇,这是一个很棒的提示,我什至不知道 Visual Studio 中有这个提示,谢谢
    【解决方案3】:

    正如 Chris 在 cmets 中所提到的,用于 List(Of Document) 的根元素名称需要为 ArrayOfDocument(单数),因此如果 XML 包含 ArrayOfDocuments(复数)作为根,它不会自动工作元素。

    如果您需要按原样反序列化,一个简单的解决方案是创建一个 ArrayOfDocuments 类并反序列化为该类,而不是反序列化为 List(Of Document)

    Public Class Document
        Public Property Type As String
        Public Property FileName As String
    End Class
    
    Public Class ArrayOfDocuments
        <XmlElement>
        Public Property Document As Document()
    End Class
    

    然后:

    Dim xml As New XmlSerializer(GetType(ArrayOfDocuments))
    foundDocuments = TryCast(xml.Deserialize(currentStringReader), ArrayOfDocuments)
    

    【讨论】: