I'm making my first class and then serializing it. I've never worked with serialization and I'm having some problems. Here is the class code:
<XmlRoot([Namespace]:="FatturaElettronica")>
Public Class FatturaElettronica
Public quantity As Integer
Sub New()
FatturaElettronicaHeader = New FatturaElettronicaHeader
End Sub
Property FatturaElettronicaHeader As FatturaElettronicaHeader
End Class
Public Class FatturaElettronicaHeader
Sub New()
DatiTrasmissione = New DatiTrasmissione
End Sub
Property DatiTrasmissione As DatiTrasmissione
End Class
Public Class DatiTrasmissione
Sub New()
Idtrasmittente = New idTrasmittente
ContattiTrasmittente = New ContattiTrasmittente
End Sub
Property Idtrasmittente As idTrasmittente
Property ProgressivoInvio As String
Property FormatoTrasmissione As FormatoTrasmissioneType
Property CodiceDestinatario As String
Property ContattiTrasmittente As ContattiTrasmittente
Property PecDestinatario As String
End Class
Public Class idTrasmittente
Property IdPaese As String
Property IdCodice As String
End Class
Public Class ContattiTrasmittente
Property Telefono As String
Property Email As String
End Class
Public Enum FormatoTrasmissioneType
FPA12
FPR12
End Enum
Here is a bit of code that I use for testing:
Dim fattEle As New FatturaElettronica
Dim ns2 As New Xml.Serialization.XmlSerializerNamespaces()
ns2.Add("p", "FatturaElettronica")
Dim ser As Xml.Serialization.XmlSerializer = New Xml.Serialization.XmlSerializer(fattEle.GetType)
Dim stream As New IO.FileStream("c:/lavoro/example2.xml", IO.FileMode.Create)
ser.Serialize(stream, fattEle, ns2)
stream.Close()
And this is my output XML:
<?xml version="1.0"?>
<p:FatturaElettronica xmlns:p="FatturaElettronica">
<p:FatturaElettronicaHeader>
<p:DatiTrasmissione>
<p:Idtrasmittente />
<p:FormatoTrasmissione>FPA12</p:FormatoTrasmissione>
<p:ContattiTrasmittente />
</p:DatiTrasmissione>
</p:FatturaElettronicaHeader>
</p:FatturaElettronica>
First, I would like to add the p:
only before FatturaElettronica
, the root.
Second, the FormatoTrasmissione
property is an Enum
, but in my code isn't being set to anything. So, why is the serialization assuming the value FPA12
without that value being assigned?
Last but, not least... I would like to not serialize the properties that are not filled. The ContattiTrasmittente
property is empty, but serialized. Why?
You have three separate questions here. Let's break then down.
First , I would like to add p:
only before FatturaElettronica
, the root. This is happening because the namespace specified via the XmlRootAttribute.Namespace
attribute applies to all child elements recursively unless otherwise overridden .
Since you don't want this, the easiest way to prevent it is to apply <XmlType([Namespace]:="")>
to FatturaElettronica
as well. This applies the empty namespace to all child elements of FatturaElettronica
, superseding XmlRootAttribute.Namespace
which will now only apply to the root element itself.
Second , the FormatoTrasmissione
property is an Enum
, but in my code isn't being set to anything. So, why is the serialization assuming the value FPA12
without that value being assigned?
By default, XmlSerializer
serializes all non-null public properties and fields. Since an enum
is a value type, it is non-null by definition, and thus enum-valued properties are always serialized.
Since you don't want this, you can use the {propertyName}Specified
conditional serialization pattern that is documented in XML Schema Binding Support: MinOccurs Attribute Binding Support and add a FormatoTrasmissioneSpecified
Boolean property that tracks whether the FormatoTrasmissione
property was ever explicitly set. If not, the serializer will not serialize the property.
Third , I would like to not serialize the properties that are not filled. The ContattiTrasmittente
property is empty, but serialized. Why? This is happening for the same reason that the FormatoTrasmissione
property is serialized: XmlSerializer
will serialize all non-null public properties, and you explicitly allocated a value for ContattiTrasmittente
in the DatiTrasmissione
constructor:
Public Class DatiTrasmissione
Sub New()
Idtrasmittente = New idTrasmittente
ContattiTrasmittente = New ContattiTrasmittente
End Sub
Since you don't want this, you can use the ShouldSerialize{PropertyName}()
conditional serialization pattern which is documented in Properties in Windows Forms Controls: Defining Default Values with the ShouldSerialize and Reset Methods , and add a Boolean method ShouldSerializeContattiTrasmittente()
that returns false when ContattiTrasmittente
is null, or all its properties are null. As you have multiple properties you are allocating without setting any child values, you may need to add multiple such methods. Alternatively, you might re-think your design and only allocate nested properties when actually needed.
For more details on the two conditional serialization patterns see ShouldSerialize*() vs *Specified Conditional Serialization Pattern .
Putting all this together, you code should looks something like:
<XmlRoot([Namespace]:="FatturaElettronica")>
<XmlType([Namespace]:="")> ' Fixed added empty namespace for all elements.
Public Class FatturaElettronica
Public quantity As Integer
Sub New()
FatturaElettronicaHeader = New FatturaElettronicaHeader
End Sub
Property FatturaElettronicaHeader As FatturaElettronicaHeader
End Class
Public Class FatturaElettronicaHeader
Sub New()
DatiTrasmissione = New DatiTrasmissione
End Sub
Property DatiTrasmissione As DatiTrasmissione
End Class
Public Class DatiTrasmissione
Sub New()
Idtrasmittente = New idTrasmittente
' By allocating ContattiTrasmittente you cause its value to be serialized by default
ContattiTrasmittente = New ContattiTrasmittente
End Sub
Property Idtrasmittente As idTrasmittente
Property ProgressivoInvio As String
' Fixed added FormatoTrasmissioneSpecified and made FormatoTrasmissione an explicitly implemented property
Private m_FormatoTrasmissione as FormatoTrasmissioneType
<XmlIgnore>
Public Property FormatoTrasmissioneSpecified as Boolean
Property FormatoTrasmissione As FormatoTrasmissioneType
Get
Return m_FormatoTrasmissione
End Get
Set
' For convenience set FormatoTrasmissioneSpecified automatically when the property is set publicly.
FormatoTrasmissioneSpecified = true
m_FormatoTrasmissione = value
End Set
End Property
Property CodiceDestinatario As String
' Fixed added ShouldSerializeContattiTrasmittente()
Property ContattiTrasmittente As ContattiTrasmittente
Public Function ShouldSerializeContattiTrasmittente() as Boolean
Return ContattiTrasmittente.ShouldSerialize()
End Function
Property PecDestinatario As String
End Class
Public Class idTrasmittente
Property IdPaese As String
Property IdCodice As String
End Class
Public Class ContattiTrasmittente
Property Telefono As String
Property Email As String
End Class
' Fixed added an extension method to test whether a ContattiTrasmittente should be serialized.
Public Module ContattiTrasmittenteExtensions
<System.Runtime.CompilerServices.Extension()> _
Public Function ShouldSerialize(ByVal ContattiTrasmittente as ContattiTrasmittente) as Boolean
Return ContattiTrasmittente IsNot Nothing And (ContattiTrasmittente.Telefono IsNot Nothing Or ContattiTrasmittente.Email IsNot Nothing)
End Function
End Module
Public Enum FormatoTrasmissioneType
FPA12
FPR12
End Enum
Working vb.net fiddle here .
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.