How can I use XMLSerializer and XML attributes to deserialize "numbered array"?

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • Shea
    New Member
    • Apr 2011
    • 2

    How can I use XMLSerializer and XML attributes to deserialize "numbered array"?

    I am trying to deserialize an non-standard XML array, returned by some sort of Perl web script, in a VB.NET client application.

    Take for example, the following XML:
    Code:
    <MyObject>
      <...other fields...>
      <MyItems>
        <Item1>abcdefg</Item1>
        <Length1>7</Length1>
        <Item2>abcd</Item2>
        <Length2>4</Length2>
        <Item3>abcdefghijk</Item3>
        <Length3>11</Length3>
      </MyItems>
    </MyObject>
    Below is the class that I've attempted to build to read this XML, simplified of course:
    Code:
    <Serializeable()> _
    Public Class MyObject
    
      'Other fields here
    
      <XmlArray(ElementName:="MyItems", IsNullable:=True), _
       XmlArrayItem(Type:=GetType(String)), _
       XmlArrayItem(Type:=GetType(Integer))> _
      Public MyItems As ArrayList
    
    End Class
    I would like to stick with the XMLSerializer model, instead of using a dataset or LINQ, but I'm open to suggestions.

    Thanks in advance,
    Shea
  • Sfreak
    New Member
    • Mar 2010
    • 64

    #2
    You can serialize and deserialize the entire class by doing this:
    Code:
          public static string GenerateXML(this object ObjetoXML)
            {
                MemoryStream MemStream = new MemoryStream();
                StringBuilder xm = new StringBuilder();
                XmlSerializer Serializador = new XmlSerializer(ObjetoXML.GetType());
                XmlTextWriter XmlWrite = new XmlTextWriter(MemStream, Encoding.UTF8);
                long st = MemStream.Length;
                Serializador.Serialize(XmlWrite, ObjetoXML);
                MemStream.Position = 0;
                MemStream.GetHashCode();
    
                xm.Append(UTF8ByteArrayToString(MemStream.ToArray()));
                return xm.ToString();
            }
    
       public static object LoadXML(this object Obj, string StrXML)
            {
                XmlSerializer xs = new XmlSerializer(Obj.GetType());
                MemoryStream ms = new MemoryStream(StringToUTF8ByteArray(StrXML));
                Obj = xs.Deserialize(ms);
                return Obj;
            }
    
            private static String UTF8ByteArrayToString(Byte[] characters)
            {
                UTF8Encoding encoding = new UTF8Encoding();
                String constructedString = encoding.GetString(characters);
                return (constructedString);
            }
            private static Byte[] StringToUTF8ByteArray(String pXmlString)
            {
                UTF8Encoding encoding = new UTF8Encoding();
                Byte[] byteArray = encoding.GetBytes(pXmlString);
                return byteArray;
            }
    Note that they are extension methods and must be declared in a static class, but you can use the way you want.

    Hope this helps

    Fernando

    Comment

    • Shea
      New Member
      • Apr 2011
      • 2

      #3
      RE: You can serialize and deserialize the entire class by doing this:

      Fernando,
      Thank you for the quick response. I am already using similar code to deserialize/serialize my objects. I forgot to illustrate that. I use a generic class, that I made (feel free to copy), to encapsulate the serialization code. See below:
      Code:
      <Serializable()> _
      Public MustInherit Class XMLSerializable(Of T)
      
        Public Shared Function XMLDeserialize(ByVal sXML As String) As T
          Dim _ret As T = Nothing
          Dim _xmlBytes() As Byte = Nothing
          Dim _xmlStream As MemoryStream = Nothing
          Dim _serializer As XmlSerializer = Nothing
          Try
            _xmlBytes = UTF8.GetBytes(sXML)
            _xmlStream = New MemoryStream(_xmlBytes)
            _serializer = New XmlSerializer(GetType(T))
            _ret = _serializer.Deserialize(_xmlStream)
          Catch ex As Exception
            _ret = Nothing
          Finally 'Cleanup
            _serializer = Nothing
            If Not IsNothing(_xmlStream) Then
              _xmlStream.Close()
              _xmlStream = Nothing
            End If
            Erase _xmlBytes
            XMLDeserialize = _ret
          End Try
        End Function
      
        Public Function XMLSerialize() As String
          Dim _ret As String = vbNullString
          Dim _xmlBytes() As Byte = Nothing
          Dim _xmlStream As MemoryStream = Nothing
          Dim _serializer As XmlSerializer = Nothing
          Try
            _xmlStream = New MemoryStream
            _serializer = New XmlSerializer(GetType(T))
            _serializer.Serialize(_xmlStream, Me)
            _xmlStream.Position = 0 'Reset cursor to beginning of stream, after writing serialized object to stream
            ReDim _xmlBytes(_xmlStream.Length - 1) 'Allocate space
            If _xmlStream.Read(_xmlBytes, 0, _xmlStream.Length) Then 'Read the data in the stream
              _ret = UTF8.GetString(_xmlBytes) 'Convert the data, in bytes, to an xml string
              'Take out unneeded xmlns attributes
              _ret = _ret.Replace(" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""", vbNullString)
              _ret = _ret.Replace("<?xml version=""1.0""?>", vbNullString)
            End If
          Catch ex As Exception
            _ret = vbNullString
          Finally
            XMLSerialize = _ret
          End Try
        End Function
      
      End Class
      The MyObject class inherits XMLSerializeabl e(of MyObject). This works for me in many other places. It really should look like this:

      Code:
      <Serializeable()> _ 
      Public Class MyObject
        Inherits XMLSerializeable(of MyObject)
        
        'Other fields here 
        
        <XmlArray(ElementName:="MyItems", IsNullable:=True), _ 
         XmlArrayItem(Type:=GetType(String)), _ 
         XmlArrayItem(Type:=GetType(Integer))> _ 
        Public MyItems As ArrayList 
        
      End Class
      To clarify, the problem is that the XML, contains two "numbered" arrays, inside the MyItems object. When I try to deserialize, MyItems is empty and I get no exception. I've even tried to specifiy the ElementNames, such as "Item" and "Length", but that does the same thing. The numbers in the name seem to throw it off, somehow. Is there any way to append the array index to the name of array item elements?

      P.S. I have a sloppy solution that works, but I have to modify the incoming XML to take out the numbers in the names. I don't want to do that. I would like to use an XML attribute to control serialization, to make the code more reliable over time.

      Thanks again,
      Shea

      Comment

      • Sfreak
        New Member
        • Mar 2010
        • 64

        #4
        Shea,

        I cant figure it out what you want yet.

        Notice that this code that i wrote serializes all kind of classes (even your own types with complex or primitive attributes) by applying an extension to the Object class (in the end all we have is an object)

        So if you show us what are exactly these numbered arrays we can see it cleary.

        att,

        Fernando

        Comment

        Working...