将某些属性标记为CDATA元素以进行序列化

时间:2008-11-12 15:46:49

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

在序列化/反序列化某些类时,我遇到了将某些属性标记或标记为CDATA元素的需要(由于它们的内容)。我目前正在这样处理:

    <XmlElement("MessageText")> _
    Public Property XmlContentLeft() As XmlCDataSection
        Get
            Dim doc As New XmlDataDocument()
            Dim cd As XmlCDataSection = doc.CreateCDataSection(Me.MessageText)
            Return cd
        End Get
        Set(ByVal value As XmlCDataSection)
            Me.MessageText = value.Value
        End Set
    End Property

    <XmlIgnore()> _
    Public Property MessageText() As String
        Get
            Return _messageText
        End Get
        Set(ByVal value As String)
            _messageText= value
        End Set
    End Property

现在虽然这很有效但它有缺点 - 我现在有任何我希望成为CDATA元素的重复属性,我必须为这些属性编写额外的代码。

所以我的问题是,是否有更好的方法来做到这一点?我不想为每个类编写自定义模式或序列化例程。在理想情况下,我可以为这些属性添加属性,以便将它们自动视为CDATA元素。

2 个答案:

答案 0 :(得分:3)

两件事:

1)您可以像这样简化现有的CDATA代码:

<XmlElement("MessageText")> _
Public Property XmlContentLeft() As XmlCDataSection
    Get
        return GetCData(Me.MessageText)
    End Get
    Set(ByVal value As XmlCDataSection)
        Me.MessageText = value.Value
    End Set
End Property

' this method is re-usable by any property that needs CData
Private Function GetCData(ByVal value As String) As XmlCDataSection
    Static doc As New XmlDataDocument() 
    return doc.CreateCDataSection(value)
End Function

<XmlIgnore()> _
Public Property MessageText() As String
    Get
        Return _messageText
    End Get
    Set(ByVal value As String)
        _messageText= value
    End Set
End Property

当然,这实际上比您发布的代码更多,但请注意您的CData属性现在更加简单。另外,我对Static的使用不是拼写错误或C#错误。 VB.Net有一个鲜为人知的Static关键字,用于在函数中创建成员。这样,XmlDataDocument只为整个类创建一次,并且不会污染类的私有名称空间。

2)序列化程序应该已正确转义字符数据。你真的需要它成为CData吗?您序列化的任何内容都应该正确反序列化以匹配原始内容,甚至是代码字符串之类的东西。我可以需要 CDATA部分的唯一情况是,如果你必须符合期望它的模式。

答案 1 :(得分:1)

我遇到了类似的问题 - 客户端需要来自Web服务的XML,其中的字符串包含在可怕的CData标签中,这是完全不必要的,但他们不想重新编码他们的客户端,所以我必须使我的XML符合。

我的工作方式是将我想要显示为CDATA的(字符串)属性重新键入我自己的自定义类型“XmlCDataString”。

然后我在该类型上实现了IXmlSerializable并推送了一些Narrowing和Widening转换运算符重载,以便属性仍然像Strings一样工作。

Imports System.Xml.Serialization
Imports System.Xml
<Serializable()> _
Public Class XmlCDataString
  Implements IXmlSerializable

  Private _strValue As String = Nothing

  Public Sub New()

  End Sub

  Public Sub New(ByVal strValue As String)
    _strValue = strValue
  End Sub

  Public Property StringValue() As String
    Get
      Return _strValue
    End Get
    Set(ByVal value As String)
      _strValue = value
    End Set
  End Property

  Public Shared Widening Operator CType(ByVal strValue As String) As XmlCDataString
    Return New XmlCDataString(strValue)
  End Operator

  Public Shared Narrowing Operator CType(ByVal cdata As XmlCDataString) As String
    Return cdata.StringValue
  End Operator

  Public Function GetSchema() As System.Xml.Schema.XmlSchema Implements System.Xml.Serialization.IXmlSerializable.GetSchema
    Throw New NotImplementedException
  End Function

  Public Sub ReadXml(ByVal reader As System.Xml.XmlReader) Implements System.Xml.Serialization.IXmlSerializable.ReadXml
    ' TODO
  End Sub

  Public Sub WriteXml(ByVal writer As System.Xml.XmlWriter) Implements System.Xml.Serialization.IXmlSerializable.WriteXml
    Dim doc As XmlDocument
    Dim xmlCData As XmlCDataSection
    Dim serializer As XmlSerializer

    doc = New XmlDataDocument()
    xmlCData = doc.CreateCDataSection(_strValue)
    serializer = New XmlSerializer(GetType(XmlCDataSection))
    serializer.Serialize(writer, xmlCData)

  End Sub
End Class

我正在序列化为CData的属性我必须重新键入如下(使用您的示例):

Private _messageText As XmlCDataString  

Public Property MessageText() As XmlCDataString 
    Get 
        Return _messageText 
    End Get 
    Set(ByVal value As XmlCDataString) 
        _messageText= value 
    End Set 
End Property 

这对我有用!