Serialization Question

  • Thread starter Thread starter Terry Holland
  • Start date Start date
T

Terry Holland

When I call the SerializeObject method in Test.clsPerson the following XML
is saved to file

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<PostCode>WC1 1AA</PostCode>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
</Address>
</Address>
</Person>


How could I change things so the the XML file produced is of this format:

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
<PostCode>WC1 1AA</PostCode>
</Address>
</Person>

The changes required are
1) The <Address> element does not get repeated for the Address property of
clsPerson and the Address arraylist in clsAddress.
2) The <PostCode> element appears below the <Line> elements

tia

Terry Holland


'=========================================================
Imports System.IO
Imports System.Xml.Serialization

Namespace Test

<XmlRoot("Person", [Namespace]:="", IsNullable:=False)> _
Public Class clsPerson

Public Name As String = ""
Public Address As clsAddress

Public Sub New()
Name = "John Smith"
Address = New clsAddress
End Sub

Public Sub SerializeObject()
Try
' Create a new XmlSerializer instance.
Dim s As New
Xml.Serialization.XmlSerializer(GetType(clsPerson))

' Writing the XML file to disk requires a TextWriter.
Dim writer As New StreamWriter("C:\Test.xml")

' Serialize the object, and close the StreamWriter.
s.Serialize(writer, Me)
writer.Close()

Catch x As System.InvalidOperationException
Throw x
End Try

End Sub

End Class

Public Class clsAddress
Private m_alLine As New ArrayList
Public PostCode As String = ""

Public Sub New()
m_alLine.Add("1 Acacia Avenue")
m_alLine.Add("London")
PostCode = "WC1 1AA"
End Sub

<XmlArray("Address"), XmlArrayItem("Line", GetType(String))> _
Public Property Address() As ArrayList
Get
Return m_alLine
End Get
Set(ByVal value As ArrayList)
m_alLine = value
End Set
End Property

End Class

End Namespace
 
First Question: Why are you setting up the address as lines. That is a
string formatting issue and not a property of an address object. What you
are essentially saying is you can format the address with as many lines as
you desire, but you are forcing it at the business object layer and not the
user layer.

If it were me, I would probably have an object like so:

AddressLine1
AddressLine2
City
StateProvince, only when applicable, so this does not fit all countries
PostalCode

I can then set up the output according to country, so your address would be

AddressLine1
AddressLine2 (optional)
City
PostalCode

For the US it would be

AddressLine1
AddressLine2 (optional)
City, StateProvince PostalCode

Question 2: Why is format of the XML important?

The only reason I can see is you are trying to serialize this information
and present it, via some sort of service boundary, as XML, not as a
serialized object. If so, I would take the XML through a transformation to
get the format you desire rather than attempt to have the object serialize
differently.

NOTE:
The reason why your XML is not like this:
<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
<PostCode>WC1 1AA</PostCode>
</Address>
</Person>

is two fold:

1. The inner "Address" nodes represent another object. In this case, it is
an ArrayList, but it could have been Array(of String) or other type of list
object, while the PostalCode is a separate property.
2. The ordering, I believe, comes from the order in the object, so you can
end up with the Address lines before the postal code by changing order of
the list and the string. If this does not work, there is a hierarchy that
simple types are rendered prior to complex types, but I do not think this is
the case.

--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

Blog:
http://feeds.feedburner.com/GregoryBeamer

*************************************************
| Think outside the box! |
*************************************************

Terry Holland said:
When I call the SerializeObject method in Test.clsPerson the following XML
is saved to file

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<PostCode>WC1 1AA</PostCode>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
</Address>
</Address>
</Person>


How could I change things so the the XML file produced is of this format:

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
<PostCode>WC1 1AA</PostCode>
</Address>
</Person>

The changes required are
1) The <Address> element does not get repeated for the Address property of
clsPerson and the Address arraylist in clsAddress.
2) The <PostCode> element appears below the <Line> elements

tia

Terry Holland


'=========================================================
Imports System.IO
Imports System.Xml.Serialization

Namespace Test

<XmlRoot("Person", [Namespace]:="", IsNullable:=False)> _
Public Class clsPerson

Public Name As String = ""
Public Address As clsAddress

Public Sub New()
Name = "John Smith"
Address = New clsAddress
End Sub

Public Sub SerializeObject()
Try
' Create a new XmlSerializer instance.
Dim s As New
Xml.Serialization.XmlSerializer(GetType(clsPerson))

' Writing the XML file to disk requires a TextWriter.
Dim writer As New StreamWriter("C:\Test.xml")

' Serialize the object, and close the StreamWriter.
s.Serialize(writer, Me)
writer.Close()

Catch x As System.InvalidOperationException
Throw x
End Try

End Sub

End Class

Public Class clsAddress
Private m_alLine As New ArrayList
Public PostCode As String = ""

Public Sub New()
m_alLine.Add("1 Acacia Avenue")
m_alLine.Add("London")
PostCode = "WC1 1AA"
End Sub

<XmlArray("Address"), XmlArrayItem("Line", GetType(String))> _
Public Property Address() As ArrayList
Get
Return m_alLine
End Get
Set(ByVal value As ArrayList)
m_alLine = value
End Set
End Property

End Class

End Namespace
 
If it were me, I would probably have an object like so:
AddressLine1
AddressLine2
City
StateProvince, only when applicable, so this does not fit all countries
PostalCode

I can then set up the output according to country, so your address would
be

AddressLine1
AddressLine2 (optional)
City
PostalCode

I'll give you a bit more of the background. Our company need to transmit
files to a partner organisation and they are expecting an XML file of the
format I described. In particular their scheme definition for the address
is defined below
<xs:element name="Address" type="UKPostalAddressStructure"/>

.....
<xs:complexType name="UKPostalAddressStructure">

<xs:sequence>

<xs:element name="Line" type="xs:string" minOccurs="2" maxOccurs="6"/>

<xs:element name="PostCode" type="xs:string"/>

</xs:sequence>

Question 2: Why is format of the XML important?

The only reason I can see is you are trying to serialize this information
and present it, via some sort of service boundary, as XML, not as a
serialized object. If so, I would take the XML through a transformation to
get the format you desire rather than attempt to have the object serialize
differently.

You are correct that the format is based on an external requirement. Im not
too hot on XML so when you say "...take the XML through a transformation...
" could you expand a bit on this. I have overcome my problem in the
immediate term by manually creating an XMLDocument in the desired format and
transmitting this document (I needed to get something out urgently). I
would however be interested in exploring transformations for when I refactor

NOTE:
The reason why your XML is not like this:


is two fold:
1. The inner "Address" nodes represent another object. In this case, it is
an ArrayList, but it could have been Array(of String) or other type of
list object, while the PostalCode is a separate property.
If I had Address as Array(of String) then all parts of address would have
serialized as said:
2. The ordering, I believe, comes from the order in the object, so you can
end up with the Address lines before the postal code by changing order of
the list and the string. If this does not work, there is a hierarchy that
simple types are rendered prior to complex types, but I do not think this
is the case.
The order in the class doesnt seem to make any difference ie Postcode
property appears after Address property in class but before in the
serialized file
--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

Blog:
http://feeds.feedburner.com/GregoryBeamer

*************************************************
| Think outside the box! |
*************************************************

Terry Holland said:
When I call the SerializeObject method in Test.clsPerson the following
XML
is saved to file

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<PostCode>WC1 1AA</PostCode>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
</Address>
</Address>
</Person>


How could I change things so the the XML file produced is of this format:

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
<PostCode>WC1 1AA</PostCode>
</Address>
</Person>

The changes required are
1) The <Address> element does not get repeated for the Address property
of
clsPerson and the Address arraylist in clsAddress.
2) The <PostCode> element appears below the <Line> elements

tia

Terry Holland


'=========================================================
Imports System.IO
Imports System.Xml.Serialization

Namespace Test

<XmlRoot("Person", [Namespace]:="", IsNullable:=False)> _
Public Class clsPerson

Public Name As String = ""
Public Address As clsAddress

Public Sub New()
Name = "John Smith"
Address = New clsAddress
End Sub

Public Sub SerializeObject()
Try
' Create a new XmlSerializer instance.
Dim s As New
Xml.Serialization.XmlSerializer(GetType(clsPerson))

' Writing the XML file to disk requires a TextWriter.
Dim writer As New StreamWriter("C:\Test.xml")

' Serialize the object, and close the StreamWriter.
s.Serialize(writer, Me)
writer.Close()

Catch x As System.InvalidOperationException
Throw x
End Try

End Sub

End Class

Public Class clsAddress
Private m_alLine As New ArrayList
Public PostCode As String = ""

Public Sub New()
m_alLine.Add("1 Acacia Avenue")
m_alLine.Add("London")
PostCode = "WC1 1AA"
End Sub

<XmlArray("Address"), XmlArrayItem("Line", GetType(String))> _
Public Property Address() As ArrayList
Get
Return m_alLine
End Get
Set(ByVal value As ArrayList)
m_alLine = value
End Set
End Property

End Class

End Namespace
 
There are a couple of options, depending on which is easier for your team.

1. Go ahead and serialize and then run the serialized XML through a XSL
transformation to fit the format they require. This means you are manually
calling the serialization and using a XSLTransform object. Note that this
option can get tricky, as you are going to return an XML string from the web
service method, which may not work for them.

The basics of transform are here:
http://www.csharpfriends.com/Articles/getArticle.aspx?articleID=63

You do not have to write to a file, of course. I looked to see if there was
a good web service XML Transform example on the web, but I have not seen it.
If I get a chance, I will play a bit and blog it.

2. Create a custom serialization for your client. This is a bit deep and
would not be my first choice, as you would be both changing out some
attributes and inheriting from the normal .NET serialization bits.

3. Create another object that has the clients format and transfer the
information from your object to that object when the web routine that this
client uses is hit. This is a bit wasteful, of course, but it is fairly
simple in terms of setting up the web service. And, you can move to a better
system. If the client accepts XML that is not typed as an object, then XML
is a better option, as you do not go through hoops to have the WSDL appear
to have an address object.

The other is to retool your object to fit the XML you desire, which will
probably end up with some O/R mapping to translate to your database schema
so you can work with the object too. If you have already invested a lot in
the format you have currently, this path is not a wise direction, unless you
need to refactor the system anyway.

I hope I am getting you closer.

--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

Blog:
http://feeds.feedburner.com/GregoryBeamer

*************************************************
| Think outside the box! |
*************************************************

Terry Holland said:
If it were me, I would probably have an object like so:

AddressLine1
AddressLine2
City
StateProvince, only when applicable, so this does not fit all countries
PostalCode

I can then set up the output according to country, so your address would
be

AddressLine1
AddressLine2 (optional)
City
PostalCode

I'll give you a bit more of the background. Our company need to transmit
files to a partner organisation and they are expecting an XML file of the
format I described. In particular their scheme definition for the address
is defined below
<xs:element name="Address" type="UKPostalAddressStructure"/>

....
<xs:complexType name="UKPostalAddressStructure">

<xs:sequence>

<xs:element name="Line" type="xs:string" minOccurs="2" maxOccurs="6"/>

<xs:element name="PostCode" type="xs:string"/>

</xs:sequence>

Question 2: Why is format of the XML important?

The only reason I can see is you are trying to serialize this information
and present it, via some sort of service boundary, as XML, not as a
serialized object. If so, I would take the XML through a transformation
to get the format you desire rather than attempt to have the object
serialize differently.

You are correct that the format is based on an external requirement. Im
not too hot on XML so when you say "...take the XML through a
transformation... " could you expand a bit on this. I have overcome my
problem in the immediate term by manually creating an XMLDocument in the
desired format and transmitting this document (I needed to get something
out urgently). I would however be interested in exploring transformations
for when I refactor

NOTE:
The reason why your XML is not like this:


is two fold:
1. The inner "Address" nodes represent another object. In this case, it
is an ArrayList, but it could have been Array(of String) or other type of
list object, while the PostalCode is a separate property.
If I had Address as Array(of String) then all parts of address would have
serialized as said:
2. The ordering, I believe, comes from the order in the object, so you
can end up with the Address lines before the postal code by changing
order of the list and the string. If this does not work, there is a
hierarchy that simple types are rendered prior to complex types, but I do
not think this is the case.
The order in the class doesnt seem to make any difference ie Postcode
property appears after Address property in class but before in the
serialized file
--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

Blog:
http://feeds.feedburner.com/GregoryBeamer

*************************************************
| Think outside the box! |
*************************************************

Terry Holland said:
When I call the SerializeObject method in Test.clsPerson the following
XML
is saved to file

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<PostCode>WC1 1AA</PostCode>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
</Address>
</Address>
</Person>


How could I change things so the the XML file produced is of this
format:

<?xml version="1.0" encoding="utf-8"?>
<Person xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Smith</Name>
<Address>
<Line>1 Acacia Avenue</Line>
<Line>London</Line>
<PostCode>WC1 1AA</PostCode>
</Address>
</Person>

The changes required are
1) The <Address> element does not get repeated for the Address property
of
clsPerson and the Address arraylist in clsAddress.
2) The <PostCode> element appears below the <Line> elements

tia

Terry Holland


'=========================================================
Imports System.IO
Imports System.Xml.Serialization

Namespace Test

<XmlRoot("Person", [Namespace]:="", IsNullable:=False)> _
Public Class clsPerson

Public Name As String = ""
Public Address As clsAddress

Public Sub New()
Name = "John Smith"
Address = New clsAddress
End Sub

Public Sub SerializeObject()
Try
' Create a new XmlSerializer instance.
Dim s As New
Xml.Serialization.XmlSerializer(GetType(clsPerson))

' Writing the XML file to disk requires a TextWriter.
Dim writer As New StreamWriter("C:\Test.xml")

' Serialize the object, and close the StreamWriter.
s.Serialize(writer, Me)
writer.Close()

Catch x As System.InvalidOperationException
Throw x
End Try

End Sub

End Class

Public Class clsAddress
Private m_alLine As New ArrayList
Public PostCode As String = ""

Public Sub New()
m_alLine.Add("1 Acacia Avenue")
m_alLine.Add("London")
PostCode = "WC1 1AA"
End Sub

<XmlArray("Address"), XmlArrayItem("Line", GetType(String))> _
Public Property Address() As ArrayList
Get
Return m_alLine
End Get
Set(ByVal value As ArrayList)
m_alLine = value
End Set
End Property

End Class

End Namespace
 
Back
Top