Serialization issue

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • !NoItAll
    Contributor
    • May 2006
    • 297

    #1

    Serialization issue

    I have a class that serializes my object to xml - it's working as expected. Here is how I am writing out the xml file:

    Code:
           'set up a blank namespace to eliminate unnecessary junk from the xml
            Dim nsBlank As New XmlSerializerNamespaces
            nsBlank.Add("", "")
    
            'create an object for the xml settings to control how the xml is written and appears
            Dim xSettings As New System.Xml.XmlWriterSettings
            With xSettings
                .Encoding = Encoding.UTF8
                .OmitXmlDeclaration = OmitXMLDecl
                .Indent = True
                .NewLineChars = Environment.NewLine
                .NewLineOnAttributes = False
                .ConformanceLevel = Xml.ConformanceLevel.Auto
                .CheckCharacters = False
            End With
    
            Try
                'create the xmlwriter object that will write the file out
                Dim xw As System.Xml.XmlWriter = Xml.XmlWriter.Create(FileName, xSettings)
    
    
                'create the xmlserializer that will serialize the object to XML
                Dim writer As New XmlSerializer(objType)
    
                'now write it out
                writer.Serialize(xw, DataToSerialize, nsBlank)
    
                'be sure to close it or it will remain open
                xw.Close()
    
                Return True
    
            Catch ex As Exception
    
                MsgBox(ex.Message)
                Return False
    
            End Try
    My problem is that one of the "nodes" that I am serializing contains XML text. The code above writes out the xml text, but changes all of the < and > to entities (e.g. < becomes &lt; and > becomes &gt;) which is not what I want - I need to keep the xml in this node as xml.
    Any clues as to what I need to do?
  • Joseph Martell
    Recognized Expert New Member
    • Jan 2010
    • 198

    #2
    I think there are two ways you could go.

    You could create a sub-class that parses the string into appropriate sub elements. For example, if your XML needs to look like this:

    <xmlDoc>
    <problemElement >
    some text <part1>with some elements</part1> inside
    </problemElement>
    </xmlDoc>

    Then you could have a sub-class that gives you the problemElement node:

    Code:
    'This code was written off-the-cuff, so it may contain syntactic errors! Sorry!
    public class MyClass
        private class ProblemXmlCreator
        end class
    
        Public problemElement as new ProblemXmlCreator();
    end class
    The serialization process would attempt to serialize the child object "problemElement ". You would have to define the sub class "ProblemXmlCrea tor" so that it produces the required text and elements.

    The other option that I can think of is implementing the IXmlSerializabl e interface and overriding the XmlRead and XmlWrite attributes. You would have to write code to handle the element that is causing you problems by parsing the string and creating new xml elements on the fly and feeding them to the xml writer object. You would have to write complimentary code for the XmlRead method to make sure your sub elements get translated back as text.

    Comment

    • !NoItAll
      Contributor
      • May 2006
      • 297

      #3
      I honestly have no idea what this means. Serialization of the entire object takes place inside the atomic writer method called serialize using the xmlwriter class. I don't see any opportunity to serialize pieces of the xml as separate pieces handling one piece one way and another piece differently. Essentially the writer.serializ e method is handed an object that is not XML yet, but appears to pipe it through the xml.xmlwriter class that turns the entire object into xml within the confines of the serializer.
      What I would like would be a setting parameter of UseEscapeChars as a boolean that turns off the methods internal behavior that changes "<" to "&lt;" etc. But nothing like this exists - probably because the xmlwriter MUST always deal with well-formed xml and the only way to guarantee this is to escape illegal chars on-the-fly. But I still hate it because it now means I really can't use serialization for my data structure and will have to hand-roll all the xml. This becomes an order of magnitude more difficult now.
      For want of a nail.. Grrrrrrrrrr....

      Comment

      • Joseph Martell
        Recognized Expert New Member
        • Jan 2010
        • 198

        #4
        It is true that there is no "UseEscapeChars " flag or parameter for the serialization process. You are left with handling this special case yoursefl. Implementing IXmlSerializabl e allows you to write custom code for your object's serialization but keeps the call to serialize your object the same.

        For an example, I created the following classes:
        Code:
        Public Class Widget1
        
            Private _id As Integer
            Public Property ID() As Integer
                Get
                    Return _id
                End Get
                Set(ByVal value As Integer)
                    _id = value
                End Set
            End Property
        
            'Revision
            'By definition, for this example, the Revision property will take the form:
            ' ###.##.##<ReleaseDate>2011-01-01</ReleaseDate>
            Private _revision As String
            Public Property Revision() As String
                Get
                    Return _revision
                End Get
                Set(ByVal value As String)
                    _revision = value
                End Set
            End Property
        
            Public Sub New()
                ID = 0
                Revision = "0000.00<ReleaseDate>" & Date.Now.ToString("yyyy-mm-dd") & "<ReleaseDate>"
            End Sub
        End Class
        
        'I didn't test the DESERIALIZATION of this class, so
        'be warned if you try to use it
        Public Class Widget2
            Implements IXmlSerializable
        
            Private _id As Integer
            Public Property ID() As Integer
                Get
                    Return _id
                End Get
                Set(ByVal value As Integer)
                    _id = value
                End Set
            End Property
        
            'Revision
            'By definition, for this example, the Revision property will take the form:
            ' ###.##.##<ReleaseDate>2011-01-01</ReleaseDate>
            Private _revision As String
            Public Property Revision() As String
                Get
                    Return _revision
                End Get
                Set(ByVal value As String)
                    _revision = value
                End Set
            End Property
        
            Public Sub New()
                ID = 0
                Revision = "0000.00<ReleaseDate>" & Date.Now.ToString("yyyy-mm-dd") & "<ReleaseDate>"
            End Sub
        
            Public Sub XmlWrite(ByVal writer As Xml.XmlWriter) Implements IXmlSerializable.WriteXml
        
                writer.WriteElementString("ID", ID.ToString())
                writer.WriteStartElement("Revision")
                writer.WriteRaw(Revision.ToCharArray(), 0, Revision.Length)
                writer.WriteEndElement()
            End Sub
        
            Public Sub ReadXml(ByVal reader As Xml.XmlReader) Implements IXmlSerializable.ReadXml
        
                While (reader.Read())
                    Select Case reader.Name
                        Case "ID"
                            ID = System.Convert.ToInt32(reader.Value)
                        Case "Revision"
                            Revision = reader.ReadString
                    End Select
                End While
        
            End Sub
        
            Public Function GetSchema() As Xml.Schema.XmlSchema Implements IXmlSerializable.GetSchema
                Return Nothing
            End Function
        End Class
        And the following test code (on a test form with a text box and a button to trigger the serializations) :
        Code:
            Private Sub Widget1Test()
                Dim myWidget As New Widget1()
                Dim strWriter As New System.IO.StringWriter()
                Dim XmlSer As New System.Xml.Serialization.XmlSerializer(myWidget.GetType())
                XmlSer.Serialize(strWriter, myWidget)
        
                TextBox1.Text = strWriter.GetStringBuilder.ToString()
        
            End Sub
        
        
            Private Sub Widget2Test()
                Dim myWidget As New Widget2()
                Dim strWriter As New System.IO.StringWriter()
                Dim XmlSer As New System.Xml.Serialization.XmlSerializer(myWidget.GetType())
                XmlSer.Serialize(strWriter, myWidget)
        
                TextBox1.Text = strWriter.GetStringBuilder.ToString()
        
            End Sub
        Try it out. I think you will be happy with the results (well, the results of the second example anyway):

        Code:
        <?xml version="1.0" encoding="utf-16"?>
        <Widget1 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
          <ID>0</ID>
          <Revision>0000.00&lt;ReleaseDate&gt;2011-54-14&lt;ReleaseDate&gt;</Revision>
        </Widget1>
        
        <?xml version="1.0" encoding="utf-16"?>
        <Widget2>
          <ID>0</ID>
          <Revision>0000.00<ReleaseDate>2011-55-14<ReleaseDate></Revision>
        </Widget2>
        Using the WriteRaw method writes the < and > without translating them to their respective encoding sequences. The second class does require you to write your own serialization code, which can be quite a pain depending on the size of your class, but it is an option. If this doesn't work then I can show you how a sub class can work.

        Comment

        Working...