【问题标题】:XML serialize which had xml-attribute by xml-elementXML 序列化具有 xml-element 的 xml-attribute
【发布时间】:2020-04-09 15:52:11
【问题描述】:

我必须创建一个 XML 文档以便在其他软件中导入。导入过程不能修改,所以xml和他的结构是固定的。

我在visualstudio 中使用VB.net。我使用“Xml.Serialization.XmlSerializer”,过去对我来说效果很好。

对于这个主题,我通常将整个 xml 结构“重建”为带有“xml 修饰符”的类:

Public Class Xyz
    <xmlattribute> property id as integer
    <xmlelement> property name as string
    <xmlelement> property comment as string
    <xmlelement> property block as string
    <xmlelement> property test as List(of Test)

    Public Sub New()
        test = new List(of Test)
    End Sub
End Class

Public Class Test
    <xmlelement> property name as string
End Class

然后我得到这样的 xml 部分:

<Xyz id=0>
 <Name>Abc</Name>
 <Comment>Abc</Comment>
 <Block>Abc</Block>
 <Test>
  <Name>Abc</Name>
 </Test>
 <Test>
  <Name>Def</Name>
 </Test>
 <Test>
  <Name>Ghi</Name>
 </Test>
</Xyz>

但是现在我在 xml 中有两个问题,我需要任何人的一些启发。首先,“块”有一个直接值(像以前一样)和一个像“id_block”这样的属性。其次,“测试”元素有一个序列号。导入必须如下所示:

<Xyz id=0>
 <Name>Abc</Name>
 <Comment>Abc</Comment>
 <Block id_Block=5>Abc</Block>
 <Test_0>
  <Name>Abc</Name>
 </Test_0>
 <Test_1>
  <Name>Def</Name>
 </Test_1>
 <Test_2>
  <Name>Ghi</Name>
 </Test_2>
</Xyz>

如何实现这两个主题?

【问题讨论】:

  • 您向 Block 添加了一个属性。使用 XmlAttribute 和 XmlText 制作 Block 类
  • 此外,您可以将 Test_1、Test_2、... Test_n 序列化为具有 XmlAnyElement 属性的 Object 属性。但是你有对象......
  • 嘿 djv,您的第一条评论有效。你的第二个我不明白。 “测试”是一个单独的类。我有什么用,我可以修改名称?

标签: xml vb.net serialization xml-serialization xmlserializer


【解决方案1】:

使用 Xml Linq:

Imports System.Xml
Imports System.Xml.Linq
Module Module1
    Const FILENAME As String = "c:\temp\test.xml"
    Sub Main()
        Dim doc As XDocument = XDocument.Load(FILENAME)
        Dim xyz As Xyz = doc.Descendants("Xyz").Select(Function(x) New Xyz With { _
                                                        .id = CType(x.Attribute("id"), Integer), _
                                                        .name = CType(x.Element("Name"), String), _
                                                        .comment = CType(x.Element("Comment"), String), _
                                                        .block = CType(x.Element("Block"), String), _
                                                        .test = x.Elements().Where(Function(y) y.Name.LocalName.StartsWith("Test")).Select(Function(y) CType(y.Element("Name"), String)).ToList()
                                                    }).FirstOrDefault()

    End Sub

End Module
Public Class Xyz
    Property id As Integer
    Property name As String
    Property comment As String
    Property block As String
    Property test As List(Of String)

End Class

【讨论】:

  • 感谢您的解决方案,但我不想通过切换到 XDocument 来更改我的工具链。
  • 您必须创建一个自定义 xml 序列化类来处理 test_0、test_1、test_2,或者为每个索引号创建一个硬编码类。
  • “每个索引号的硬编码类”确实是最后的解决方案。您有 custom-xml-serialization-class 的示例吗?或者其他问题,“xmlarray”和“xmlarryitem”或“xmlanyelement”是什么?对我来说,可以在类中有一个额外的变量来提供所需的索引号。但我不知道,我如何使用这些数字名字。
  • 要使用数组,标签的名称必须相同。对于自定义序列化器,请参阅:docs.microsoft.com/en-us/dotnet/api/…
  • 你看到我的解决方案了吗?我必须在父级和子级中实现接口看起来不太好。有什么改进建议吗?
【解决方案2】:

您在下面看到的我的解决方案。它对我有用,但是...

我不明白,为什么我需要在父类和(索引)子类中使用 IXMLSERIALIZER。我进行了其他测试,但它不起作用。每次都是例如里面的“test”标签,而不仅仅是“test_1”标签。对此或其他/更好的解决方案有什么好的解释吗?

我的代码:

  Public Class Xyz
        Inherits IndexedParent

        <XmlAttribute> Property id As Integer
        <XmlElement> Property name As String
        <XmlElement> Property comment As String
        <XmlElement> Property block As String
        <XmlIgnore> Property test As List(Of Test)
        <XmlIgnore> Property tryNext As List(Of TryNext)


        Public Sub New()
            test = New List(Of Test)
            tryNext = New List(Of TryNext)
            RegisterIndexedChildList(test)
            RegisterIndexedChildList(tryNext)
        End Sub

    End Class

    Public Class Test
        Inherits IndexedChild

        <XmlElement> Property Name As String
        <XmlElement> Property Name2 As String


    End Class


    Public Class TryNext
        Inherits IndexedChild

        <XmlElement> Property N As String
        <XmlElement> Property N2 As String

    End Class

    Public MustInherit Class IndexedParent
        Implements IXmlSerializable

        Private registeredChildLists As List(Of IEnumerable(Of IndexedChild))

        Public Sub RegisterIndexedChildList(pChildList As IEnumerable(Of IndexedChild))
            If registeredChildLists Is Nothing Then
                registeredChildLists = New List(Of IEnumerable(Of IndexedChild))
            End If
            registeredChildLists.Add(pChildList)
        End Sub


        Public Function GetSchema() As XmlSchema Implements IXmlSerializable.GetSchema
            Return Nothing
        End Function

        Public Sub ReadXml(reader As XmlReader) Implements IXmlSerializable.ReadXml
            Throw New NotImplementedException()
        End Sub

        Public Sub WriteXml(writer As XmlWriter) Implements IXmlSerializable.WriteXml

            IndexedChild.WritePropertiesAsXml(writer, Me)

            For Each childList As IEnumerable(Of IndexedChild) In registeredChildLists
                IndexedChild.WriteAllXmlElements(writer, childList)
            Next

        End Sub

    End Class


    Public MustInherit Class IndexedChild
        Implements IXmlSerializable

        Public Shared Function WriteAllXmlElements(pWriter As XmlWriter, pList As IEnumerable(Of IndexedChild))
            For Each item As IXmlSerializable In pList
                pWriter.WriteStartElement(item.GetType.Name.ToString.ToLower + pList.ToList.IndexOf(item).ToString)
                item.WriteXml(pWriter)
                pWriter.WriteEndElement()
            Next
        End Function

        Public Shared Function WritePropertiesAsXml(pWriter As XmlWriter, pObj As Object)
            For Each prop As Reflection.PropertyInfo In pObj.GetType().GetProperties
                If Attribute.IsDefined(prop, GetType(XmlElementAttribute)) Then
                    pWriter.WriteElementString(prop.Name, prop.GetValue(pObj, Nothing))
                ElseIf Attribute.IsDefined(prop, GetType(XmlAttributeAttribute)) Then
                    pWriter.WriteAttributeString(prop.Name, prop.GetValue(pObj, Nothing))
                End If
            Next
        End Function

        Public Sub ReadXml(reader As XmlReader) Implements IXmlSerializable.ReadXml
            Throw New NotImplementedException
        End Sub

        Public Sub WriteXml(writer As XmlWriter) Implements IXmlSerializable.WriteXml
            WritePropertiesAsXml(writer, Me)
        End Sub

        Public Function GetSchema() As XmlSchema Implements IXmlSerializable.GetSchema
            Return Nothing
        End Function
    End Class

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-08-01
    • 1970-01-01
    • 2023-03-08
    • 2023-04-07
    • 1970-01-01
    • 2010-11-17
    • 2012-08-11
    • 1970-01-01
    相关资源
    最近更新 更多