Отметить определенные свойства как элементы CDATA для сериализации - PullRequest
2 голосов
/ 12 ноября 2008

При сериализации / десериализации определенных классов я столкнулся с необходимостью пометить или пометить определенные свойства как элементы 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 ]

3 голосов
/ 12 ноября 2008

Две вещи:

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 голос
/ 08 октября 2010

У меня была похожая проблема - клиенту нужен был XML от веб-сервиса со строками, обернутыми в ужасные теги CData, это совершенно не нужно, но они не хотели перекодировать своего клиента, поэтому мне пришлось привести свой XML в соответствие.

То, как я работал, состояло в том, чтобы заново набрать (строковые) свойства, которые я хотел отобразить как CDATA, для моего собственного пользовательского типа "XmlCDataString".

Затем я реализовал IXmlSerializable для этого типа и добавил пару перегрузок операторов сужения и расширения, чтобы свойства по-прежнему работали так же, как и строки.

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 

Это сработало для меня!

...