.NET使用XmlSerializer动态地向元素添加属性

时间:2013-01-24 16:31:13

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

我正在创建一个带序列化的XML,当我需要动态地为元素创建属性时,我遇到了问题。我正在添加包含价格数据的日期元素。我的XML类结构如下所示:

 <XmlRoot(ElementName:="root")>
    Public Class DateXML
        <XmlElement(ElementName:="date")> _
        Public Property Dates As List(Of DatePrice)
    End Class

    Public Class DatePrice
        <XmlAttribute("value")> _
        Public Property DateValue As String
        <XmlElement("price")> _
        Public Property Price As String
    End Class

例如,XML将如下所示:

<root>
    <date value="2013-01-01">
        <price>100.00</price>
    </date>
    <date value="2013-01-02">
        <price>100.00</price>
    </date>
    <date value="2013-01-03">
        <price>100.00</price>
    </date>
    <date value="2013-01-04">
        <price>100.00</price>
    </date>
    <date value="2013-01-08">
        <price>100.00</price>
    </date>
    <date value="2013-01-12">
        <price>100.00</price>
    </date>
</root>

我的问题是需要XML。如果我有多个具有相同价格的日期值,我应该使用value1="2013-01-01" value2="2013-01-02"等将它们放在一个节点中。此外,如果日期相互关联,我应该使用from="" to=""属性,我可以混合使用这些属性。目标是使用属性尽可能少地创建日期节点。所以上面的例子应该是这样的:

<root>
    <date from="2013-01-01" to="2013-01-04">
        <price>100.00</price>
    </date>
    <date value1="2013-01-08" value2="2013-01-12">
        <price>100.00</price>
    </date>
</root>

我应该如何创建DatePrice类来完成此要求?我从数据库中获取每个日期的数据。我可以将from和to属性作为属性添加到类中,但是是否可以为value1,value2动态添加属性...?

编辑:

在发现如何序列化字典后,我现在离我更近了。这是我尝试过的:

<XmlRoot(ElementName:="root")>
Public Class XmlObject
    <XmlElement(ElementName:="element")> _
    Public Property element As String 
    Public Property elementAttributes As ValueAttributes
End Class

Public Class ValueAttributes
    Public Property values As SerializableDictionary(Of String, String)
End Class

实现IXmlSerializable的字典类:

Public Class SerializableDictionary(Of AttributeName, AttributeValue)
    Inherits Dictionary(Of String, String)
    Implements IXmlSerializable

    Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
        Return Nothing
    End Function

    Public Sub ReadXml(reader As System.Xml.XmlReader) Implements System.Xml.Serialization.IXmlSerializable.ReadXml 
        If reader.HasAttributes Then
            While reader.MoveToNextAttribute()

                Dim key As String = reader.Name
                Dim value As String = reader.Value
                Me.Add(key, value)
            End While

            reader.MoveToElement()
        End If
    End Sub

    Public Sub WriteXml(writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml     
        For Each kvp As KeyValuePair(Of String, String) In Me
            writer.WriteAttributeString(kvp.Key, kvp.Value)
        Next
    End Sub

End Class

使用这些我会得到一个如下所示的XML:

<root>
  <element>the element value</element>
  <elementAttributes>
    <values value1="1" value2="2" value3="3" />
  </elementAttributes>
</root>

现在我只需要以某种方式计算如何将属性移动到element而不是写elementAttributes结构。

1 个答案:

答案 0 :(得分:0)

要回答我自己的问题,因为我有一个解决方案,我认为我现在可以忍受,或者至少要尝试一下,看看它是否足够。因此,为了创建节点并动态地向它们添加属性,我创建了一个如下所示的类:

Public Class DateElement
    Implements IXmlSerializable

    Public Property DateValueAttributes As Dictionary(Of String, String)
    Public Property Price As String

    Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
        Return Nothing
    End Function

    Public Sub ReadXml(reader As System.Xml.XmlReader) Implements System.Xml.Serialization.IXmlSerializable.ReadXml
        If reader.HasAttributes Then
            DateValueAttributes = New Dictionary(Of String, String)
            While reader.MoveToNextAttribute()
                DateValueAttributes.Add(reader.Name, reader.Value)
            End While

            reader.MoveToElement()
        End If

        Dim wasEmpty As Boolean = reader.IsEmptyElement
        reader.Read()

        If wasEmpty Then
            Return
        End If

        While reader.NodeType <> System.Xml.XmlNodeType.EndElement
            reader.ReadStartElement("price")
            Price = reader.ReadString()
            reader.ReadEndElement()
        End While

        reader.ReadEndElement()

    End Sub

    Public Sub WriteXml(writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml
        For Each kvp As KeyValuePair(Of String, String) In Me.DateValueAttributes
            writer.WriteAttributeString(kvp.Key, kvp.Value)
        Next

        If Price IsNot Nothing Then
            writer.WriteStartElement("price")
            writer.WriteString(Price)
            writer.WriteEndElement()
        End If

    End Sub
End Class

我可以在我的xml对象中使用此类,例如:

<XmlRoot(ElementName:="root")>
Public Class XmlObject
    <XmlElement("date")>
    Public Property [element] As DateElement
End Class

然后在代码中创建对象,例如:

Dim xml As New XmlObject()
        xml.element = New DateElement()
        xml.element.DateValueAttributes = New Dictionary(Of String, String)
        xml.element.DateValueAttributes.Add("value1", "2013-01-01")
        xml.element.DateValueAttributes.Add("value2", "2013-01-02")
        xml.element.DateValueAttributes.Add("value3", "2013-01-03")
        xml.element.Price = "100.00"

将提供如下所示的结果XML:

<root>
  <date value1="2013-01-01" value2="2013-01-02" value3="2013-01-03">
    <price>100.00</price>
  </date>
</root>

我认为我现在已经足够接近,所以我可以解决这个问题。如果有人有任何想法,我会非常乐意听到他们。