Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

Hi,

 

I am now trying deserialize my employee objects in my XML document into an instance of a class.

 

Here is the class I wish to create an instance of:

Public Class EmployeeAdder

#Region "Declarations"
   Private _ID As Int32 = 0
   Private _Name As String = String.Empty
   Private _ActivityID As Int32 = 0
#End Region

#Region "Properties"
   Public Property ID() As Int32
       Get
           Return _ID
       End Get
       Set(ByVal value As Int32)
           _ID = value
       End Set
   End Property

   Public Property Name() As String
       Get
           Return _Name
       End Get
       Set(ByVal value As String)
           _Name = value
       End Set
   End Property

   Public Property ActivityID() As Int32
       Get
           Return _ActivityID
       End Get
       Set(ByVal value As Int32)
           _ActivityID = value
       End Set
   End Property
#End Region
End Class

 

Here is the XML document I am using:

<Employees xmlns="http://www.me.com">
 <Employee>
   <ID>11</ID>
   <Name>Dave Jones</Name>
   <ActivityID>9</ActivityID>
 </Employee>
 <Employee>
   <ID>111</ID>
   <Name>Wayne Wallice</Name>
   <ActivityID>1</ActivityID>
 </Employee>
 <Employee>
   <ID>1111</ID>
   <Name>Justin Davies</Name>
   <ActivityID>2</ActivityID>
 </Employee>
 <Employee>
   <ID>11111</ID>
   <Name>Matthew Jones</Name>
   <ActivityID>0</ActivityID>
 </Employee>
 <Employee>
   <ID>111111</ID>
   <Name>Steve Pear</Name>
   <ActivityID>2</ActivityID>
 </Employee>
</Employees>

 

Finally here is my function that I am trying to get to work:

 

   Private Function AddEmployee(ByVal xmlDoc As XmlDocument) As Boolean
       'Get root node and process its children.
       Try
           Dim xmlNodeEmployees As XmlNode = xmlDoc.FirstChild
           For Each node As XmlNode In xmlNodeEmployees.ChildNodes
               Dim buffer() As Byte = System.Text.ASCIIEncoding.ASCII.GetBytes(node.InnerXml)
               Dim memstrm As New System.IO.MemoryStream(buffer)
               Dim xmlReader As New XmlTextReader(memstrm)
               Dim employeeAdder As New EmployeeAdder
               Dim serializer As New XmlSerializer(GetType(EmployeeAdder))
               employeeAdder = CType(serializer.Deserialize(xmlReader), EmployeeAdder)
           Next
       Catch ex As Exception
           Return False
       End Try
   End Function

 

When it runs it get as far as employeeAdder = CType(serializer.Deserialize(xmlReader), EmployeeAdder) and then throws this exception:

InnerException = {"<ID xmlns='http://www.me.com'> was not expected."}

 

Does anyone know what I am doing wrong here?

 

Thanks, Dave.

Posted

Does anyone know what I am doing wrong here?

You're trying to deserialize a list of objects into a single object. It seems list you're also using XML that you created, not XML created by the serialization process. Try:

Dim lst As New List(Of EmployeeAdder)
Dim ser As New Xml.Serialization.XmlSerializer(GetType(List(Of EmployeeAdder)))
Dim reader As New System.IO.StreamReader(New System.IO.FileStream(Application.StartupPath & "\test.xml", IO.FileMode.Open))

lst = CType(ser.Deserialize(reader), List(Of EmployeeAdder))

using XML formatted like this:

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfEmployeeAdder xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
 <EmployeeAdder>
   <ID>1</ID>
   <Name>Test</Name>
   <ActivityID>1</ActivityID>
 </EmployeeAdder>
 <EmployeeAdder>
   <ID>2</ID>
   <Name>Test 2</Name>
   <ActivityID>2</ActivityID>
 </EmployeeAdder>
</ArrayOfEmployeeAdder>

Here's what I'm up to.
Posted

Hi,

 

Sorry Machaira I didn't get back to you sooner.

 

I am not trying to deserialize all of the objects at once. The code is getting all of the child nodes of the employees root node and creating an instance of each employee.

 

As this XML comes from a file already created, I didn't really want to use XML created by serialization. I assume this is possible?

 

I have updated the method, and have a temporary fix to it by using X-Path to interrigate the nodes. But it would be much nicer to deserialize straight from the XML document.

 

The issue seems to be with the namespace but I cannot see what it is that is wrong.

 

Please help if you can.

 

Many thanks, Dave.

Posted

If you're using an XML format that the serializer can use you can't use serialization. Since you've already go the XMLDocument object you should just be able to iterate through the nodes and populate the properties of an employee object. I think you're making it harder than it needs to be by introducing things like the stream and XmlTextReader. Try this:

 

Dim lst As New List(Of EmployeeAdder)
	Dim emp As EmployeeAdder
	Dim doc As New Xml.XmlDocument
	Dim node As Xml.XmlNode

	doc.Load(Application.StartupPath & "\test.xml")

	For Each node In doc.DocumentElement

		emp = New EmployeeAdder

		emp.ActivityID = Convert.ToInt32(node.SelectSingleNode("descendant::ActivityID").InnerText)
		emp.ID = Convert.ToInt32(node.SelectSingleNode("descendant::ID").InnerText)
		emp.Name = node.SelectSingleNode("descendant::Name").InnerText

		lst.Add(emp)

	Next node

If you have to have the "xmlns="http://www.me.com", you'll need to add the code to recognize it.

Here's what I'm up to.
Posted

Hi,

 

I have already coded it to iterate through the document like you described and it works just fine. I would like to be able to manage the same task using deserialization instead for future projects etc.

 

I have Googled this quite a lot and it does seem like the class I am trying to create by deserializing the XML has to reference this namspace or else they do not match, giving this error.

 

Reading articles like http://www.microsoft.com/belux/msdn/nl/community/columns/jdruyts/wsproxy.mspx it appears in C# there is a way of adding attributes to classes and their properties to acheive this. However I cannot find a V.B. equivalent.

 

Looking the MSDN I found this: ms-help://MS.MSDNQTR.v80.en/MS.MSDN.v80/MS.NETDEVFX.v20.en/CPref19/html/C_System_Xml_Serialization_XmlTypeAttribute_ctor.htm

 

This lead me to this adoptation:

 

Private Sub AddEmployee(ByVal xmlDoc As XmlDocument, ByVal requestID As Int32)
       Dim nsm As New System.Xml.XmlNamespaceManager(xmlDoc.NameTable)
   
       nsm.AddNamespace("ns", Resources.Resource.AddEmployeeNameSpace)
       'Get root node and process its children.
       Dim xmlNodeEmployees As XmlNode = xmlDoc.SelectSingleNode("ns:Employees", nsm)
       For Each node As XmlNode In xmlNodeEmployees.ChildNodes
           Dim buffer() As Byte = System.Text.ASCIIEncoding.ASCII.GetBytes(node.OuterXml)
           Dim memstrm As New System.IO.MemoryStream(buffer)
           Dim xmlReader As New XmlTextReader(memstrm)

           Dim employeeAdder As New EmployeeAdder

           Dim employeeOverride As New XmlAttributeOverrides()
           Dim employeeAttributes As New XmlAttributes()
           Dim employeeType As New XmlTypeAttribute()

           employeeType.TypeName = "employeeAdder"
           employeeType.Namespace = Resources.Resource.AddEmployeeNameSpace

           employeeAttributes.XmlType = employeeType

           employeeOverride.Add(GetType(EmployeeAdder), employeeAttributes)

           Dim serializer As New XmlSerializer(GetType(EmployeeAdder), employeeOverride)

           Try
               employeeAdder = CType(serializer.Deserialize(xmlReader), EmployeeAdder)
           Catch ex As Exception
               Dim str As String = ex.ToString
           Finally
               memstrm.Close()
           End Try

        Next
   End Sub

 

But I just get the same error as I got at the start of this post.

 

Can anyone help?

 

Thanks, Dave.

Posted

Hi,

 

So where and how do I add these to the following class to give this class the namespace? I m only asking because I am starting to get lost.

 

I tried quite a few attempts with the angle brackets before and after the last post with no luck.

 

Any help would be appreciated!

 

#Region "Imports"
Imports System.Xml
#End Region

Public Class EmployeeAdder

#Region "Declarations"
   Private _KronosID As Int32 = 0
   Private _Name As String = String.Empty
   Private _ActivityID As Int32 = 0
#End Region

#Region "Properties"
   Public Property KronosID() As Int32
       Get
           Return _KronosID
       End Get
       Set(ByVal value As Int32)
           _KronosID = value
       End Set
   End Property

   Public Property Name() As String
       Get
           Return _Name
       End Get
       Set(ByVal value As String)
           _Name = value
       End Set
   End Property

   Public Property ActivityID() As Int32
       Get
           Return _ActivityID
       End Get
       Set(ByVal value As Int32)
           _ActivityID = value
       End Set
   End Property
#End Region

End Class

Posted

Public Class EmployeeAdder

   <XmlAttribute("KronosID")> _
   Public KronosID As Int32 = 0    
   <XmlAttribute("Name")> _
   Public Name As String = String.Empty    
   <XmlAttribute("ActivityID")> _
   Public ActivityID As Int32 = 0

End Class

Since you're not doing any validation in the property accessors just make the members public.

 

I still don't understand the reasoning behind making things more difficult than you need to.

Here's what I'm up to.
Posted

Hi,

 

If I put the above code into my solution including import System.XML I get the error: 'XmlAttribute' cannot be used as an attribute because it does not inherit from 'System.Attribute'.

 

I appreciate you thinking I am making this harder than it needs be. But the reason for wanting to get this to work is so that in future I can deserialize xml with namspaces into objects etc.

 

Many thanks to everyone especially Machaira for their help so far.

 

Any ideas what this error is caused by?

 

Cheers, Dave.

Posted
You should be able to use the code I gave in post #4, you just need to take the namespace into account. Maybe I'm just missing something about exactly why you're trying to do it the way you're doing it. :(
Here's what I'm up to.
Posted

Hi Machaira,

 

Okay, let me explain why I want to acheive this the way I am trying to.

 

This code is part of a small web service I have wrote. The service currently serves 3 public functions that, adds an employee, updates an employee, deletes an employee. Each takes an xml document as a parameter.

 

Each of the calls firstly validates the xml document passed in. This is why the namespace is included in the xml, to tie the xml to to XSD stored on the server. If the xml does not validate the service exits, if it validates then the process continues.

 

Currently I am doing the process in the way you suggested in post #4 in that I am iterating through the nodes and getting values for name and ID etc to populate an instance of the class. This is fine and works well, but lets say there are not 3 possible classes we need to create and therefore have to iterate through the xml structure, but 30.

 

That means I would need to write 30 routines that iterate through each specific node structure. Although this is possible I think the following is a more desired fix.

 

We have a generic sub that gets passed the xml document and enum that tells the sub what the request type something like the following:

 

Private Sub AddEmployee(ByVal xmlDoc As XmlDocument, ByVal requestID As Int32)
       Dim nsm As New System.Xml.XmlNamespaceManager(xmlDoc.NameTable)
       Dim obj As New Object

       Select Case requestID
           Case requestType.insert
               obj = New EmployeeAdder
               nsm.AddNamespace("ns", Resources.Resource.AddEmployeeNameSpace)
           Case requestType.update
               obj = New EmployeeUpdater
               nsm.AddNamespace("ns", Resources.Resource.UpdateEmployeeNameSpace)
           Case requestType.delete
               obj = New EmployeeDeleter
               nsm.AddNamespace("ns", Resources.Resource.DeleteEmployeeNameSpace)
       End Select

       'Get root node and process its children.
       Dim xmlNodeEmployees As XmlNode = xmlDoc.SelectSingleNode("ns:Employees", nsm)
       For Each node As XmlNode In xmlNodeEmployees.ChildNodes

           'Deserialize somehow?

           Dim result As Int32 = _BusinessServices.AddEmployee(obj)
       Next
   End Sub

 

Once the code gets the correct namespace at the start of the sub we can also create our class as well, it would then be sensible/generic to use the current xml node to deserialize this to create instance of this class.

 

This approach to me seems a pain to get to work initially, but in the long run so much easier to maintain etc.

 

I hope that I have made more sense this time. I know once I get into something it is very easy to assume that everyone else knows what your'e trying to do. :D

 

Thanks for all your help so far, Dave. :D

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...