XmlSerializer Empty Element - NULL value

  • Thread starter Thread starter kumar.senthil
  • Start date Start date
K

kumar.senthil

Hi,
I'm using XmlSerializer to create an object from the XML string. I
would like to know whether I can get a null value for an empty XML
element.
Actually the XmlSerializer assigns "" (empty string) for a string
if the corresponding element is missing in the XML.

Input XML:
<DemoClass><A>some value</A><B></B><DemoClass>

Class Structure:
public class DemoClass
{
public string A;
public string B;
}


It creates the object with the proper value for "A" and empty
string B.

Is there any way I can get null for "B" instead of "" (empty
string) ?

Thanks,
Kumar
 
Actually the XmlSerializer assigns "" (empty string) for a string
if the corresponding element is missing in the XML.

"Missing" is very different to "empty"; your B is empty, not missing.

Anyway, no: it doesn't; first it initialises the class using the field
initialisers and the default ctor. Then it applies all the *found* items,
else applies the [DefaultValue] (if one) to any that were omitted. If it
isn't in the xml it isn't set, so it would remain null. I guess your *real*
class is initialising it to "", or the data is in the xml.

If you really want to turn an *included* (blank) <B></B> to a null, then:

If *all* "" values should become null you could simply use a property setter
of the form {...set {b = value == "" ? null : value;}}. Almost an inverse
coalesce...

If this only applies during desrialization, well, for binary serialization
you could hook some combination of [OnDeserializing], [OnDeserialized] and
IDeserializationCallback... but xml is trickier... you could possibly
implement IXmlSerializable, but this isn't trivial.

Marc
 
As this little program shows everything works fine in your code.
The only thing that is wrong is your input string for deserialization.

public class MainClass
{
public static void Main(string[] argv) {
System.Text.StringBuilder sb = new System.Text.StringBuilder();
System.Xml.Serialization.XmlSerializer ser = new
System.Xml.Serialization.XmlSerializer(typeof(DemoClass));

Console.WriteLine("Not null");
DemoClass demo = new DemoClass();
demo.B = "Not Null";
ser.Serialize(new System.IO.StringWriter(sb), demo);
Console.WriteLine(sb.ToString());
demo = ser.Deserialize(new System.IO.StringReader(sb.ToString()))
as DemoClass;
Console.WriteLine(demo.ToString());
Console.WriteLine();

Console.WriteLine("Null");
sb = new System.Text.StringBuilder();
demo = new DemoClass();
ser.Serialize(new System.IO.StringWriter(sb), demo);
Console.WriteLine(sb.ToString());
demo = ser.Deserialize(new System.IO.StringReader(sb.ToString()))
as DemoClass;
Console.WriteLine(demo.ToString());

Console.Read();
}

public class DemoClass
{
private string a = "Hello, World";
private string b;

public string A {
get { return a; }
set { a = value; }
}

public string B {
get { return b; }
set { b = value; }
}

public override string ToString()
{
return "A = " + a + Environment.NewLine + "B = " + b;
}
}
 
Hi Roman Wagner/ Marc Gravell,
Many thanks for your replies.

I should not have written "missing". Actually, It's an empty
element.

As you said, i can use setter method to control the value. However,
i've a problem in that.

If the element is missing, then XmlSerializer tries to set the
default values (0 for int, false for bool) to the properties. Actually,
i should get "null" value if the element is passed as empty.

If i pass the empty element, the CLR throws exception in case if the
elment corresponds to types like int or bool.

More over i wanted to have null values for all the elements which
are sent as empty elements. The class can have any type of properties
like int, bool or another type of class. Since i wanted to have null
for all the properties which are sent as empty elements, i used
nullable types for primitive types like int? (for int).

The problem happens when the XmlSerializer tries to create the
object. Since the empty element is not the correct value for int? type,
it throws error even before coming to the setter method only.

Marc, by saying i need to implement IXmlSerializable, do you mean i
mean i need to implement the interface for all the entities(classes) i
need to crate from XML? It would not be ideal as i've to create many
classes from XML.

Thanks,
Kumar


Marc said:
Actually the XmlSerializer assigns "" (empty string) for a string
if the corresponding element is missing in the XML.

"Missing" is very different to "empty"; your B is empty, not missing.

Anyway, no: it doesn't; first it initialises the class using the field
initialisers and the default ctor. Then it applies all the *found* items,
else applies the [DefaultValue] (if one) to any that were omitted. If it
isn't in the xml it isn't set, so it would remain null. I guess your *real*
class is initialising it to "", or the data is in the xml.

If you really want to turn an *included* (blank) <B></B> to a null, then:

If *all* "" values should become null you could simply use a property setter
of the form {...set {b = value == "" ? null : value;}}. Almost an inverse
coalesce...

If this only applies during desrialization, well, for binary serialization
you could hook some combination of [OnDeserializing], [OnDeserialized] and
IDeserializationCallback... but xml is trickier... you could possibly
implement IXmlSerializable, but this isn't trivial.

Marc
 
Well, at the end of the day what you are describing is not the standard xml
serialization in the XmlSerializer sense. So to compensate, I see various
routes:
1: write your own serializer (hard work)
2: forget serializers and just do manual xml parsing yourself (also work)
3: have your objects implement IXmlSeriazable (hard work lots of times)
4: run the transmitted xml through e.g. xslt to convert between the form
that XmlSerializer likes and the form that you like... not sure how this
would compensate for missing xml fields that you need to generate an xsi:nul
entry for...
5: press to change the xml format? (not always achievable)

....

unfortunately, XmlSerializer is not as free-form as binary serialization,
which allows a few more tricks more easily (such as the before/after
"events" (attributed methods).

Marc
 
And an afterthought...

in most common usage, <element></element> would be read "element is defined
as having a blank (i.e. empty string) value", which is what XmlSerializer is
doing. The omission of an element commonly means "leave it alone" / "default
value", with nullable types being handled a bit more subtly...

Just an observation...

Marc
 
Hi Marc,
The reason for this kind of requirement is that the same XML is used
for both insert and update actions. During the update I may get only
the updated elements. More over if the element is set to null, i'll get
an empty element. I need this empty element to distinguish from the
other non updated elements.

Many thanks for all your replies.

Regards,
Kumar
 
Then presumably you are either doing the "WriteXml" step yourself
already, or consuming an existing feed that you aren't editing. In this
scenario, I might start looking at a simple, re-usable custom xml
parser using the component model... something as simple as:

* read (object) xml element
* identify object name [some custom mapping]
* read (property) xml element
* identify property name
* obtain object project via reflection / component-model
* set value
* loop property
* loop object

This would give you full control to interpret blank / missing as
whatever you want, yet without requiring custom code at an
object-by-object basis. Fundamentally this is very similar to the
approach taken by XmlSerializer. The other advantage is that it allows
you to decide very early on whether you are constructing a new object,
or applying the xml [effectively a diffgram] to an existing object;
XmlSerializer can only create.

On a purist note, I also like to distinguish between the empty string
and a null, but if this treatment works for your purposes...

Marc
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top