Home All Groups Group Topic Archive Search About

Re: How do you prevent null elements from being serialized?

Author
17 Nov 2004 3:50 PM
Dino Chiesa [Microsoft]
Kenny, you don't show your code, but something fishy is going on.

1.  De-serializing from
>
> <person>
>            <name>Joe</name>
>            <age>37</age>
> </person>
>

....I get name=Joe, Age=37 and AgeSpecified = true (not false as you report).

Also, changing the Name from Joe to Bob should not affect Age or
AgeSpecified, as you report.   Also, changing Age does not directly affect
AgeSpecified.  These things are true, unless you have put some non-default
handling in the property getter/setter.


> What I would like to see happen is if ValueSpecified is false, then just
> leave that element off altogether.  Is there a way to do this?

This is the default behavior?, so I don't understand why you are asking
this.  The code enclosed below demonstrates this, and some other interesting
things in XML serialization.

In fact you have to do something special in order to get an empty element
(eg "<Age />")  to appear in an XML stream output from the .NET XML
Serializer.   If you use isnullable:=True in the XmlElementAttribute, you
will get <Age xsi:nil="true" />, which is not quite the same thing.


-Dino




----- Begin Code -----
// XmlIgnoreTest.cs
//
// Exercises some of the XmlIgnore stuff
//
// compile with:
//
// (c) Ionic Shade
// Wed, 17 Nov 2004  10:02
//

using System.IO;
using System.Xml.Serialization;


// This is the default class generated from xsd.exe
[System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)]
public class Person {

  [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
  public string Name;

  [System.Xml.Serialization.XmlElementAttribute(Form=System.Xml.Schema.XmlSchemaForm.Unqualified)]
  public System.Single Age;

  [System.Xml.Serialization.XmlIgnoreAttribute()]
  public bool AgeSpecified;
}




namespace Ionic {

  public class XmlTextWriterFormattedNoDeclaration :
System.Xml.XmlTextWriter {
    public XmlTextWriterFormattedNoDeclaration (System.IO.TextWriter w) :
base(w) { Formatting= System.Xml.Formatting.Indented;}
    public override void WriteStartDocument () { }
  }


  public class TestDriver {

    static void Main(string[] args) {

      try {

        string OriginalXml=
          "<Person>\n" +
          "  <Name>Joe</Name>\n" +
          "  <Age>37</Age>\n" +
          "</Person>\n" +
          "";

        System.Console.WriteLine("\n============================================\nOriginal
XML:\n"+ OriginalXml);

        XmlSerializer s1 = new XmlSerializer(typeof(Person));
        Person p= null;
        using (System.IO.StringReader sr= new
System.IO.StringReader(OriginalXml)) {
          p = (Person) s1.Deserialize(sr);
        }



        // suppress default namespace entries in the root elt
        XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
        ns.Add( "", "" );

        // use a custom TextWriter to suppress the XML declaration

        System.Console.WriteLine("\n============================================\nOriginal
values:");
        s1.Serialize(new
XmlTextWriterFormattedNoDeclaration(System.Console.Out), p, ns);
        System.Console.WriteLine("\n");

        System.Console.WriteLine("\n============================================\nChanging
the name does not change the age:");
        p.Name= "Bob";
        s1.Serialize(new
XmlTextWriterFormattedNoDeclaration(System.Console.Out), p, ns);
        System.Console.WriteLine("\n");


        System.Console.WriteLine("\n============================================\nUn-specifying
the Age results in this:");
        p.AgeSpecified= false;
        s1.Serialize(new
XmlTextWriterFormattedNoDeclaration(System.Console.Out), p, ns);
        System.Console.WriteLine("\n");


        string OriginalXml2=
          "<Person>\n" +
          "  <Name>Shirley</Name>\n" +
          "  <Age />\n" +
          "</Person>\n" +
          "";
        System.Console.WriteLine("\n============================================\nCase
2: Original XML:\n"+ OriginalXml2);
        p=null;
        try {
          System.Console.WriteLine("\n(De-serializing from this will
fail...)\n");
          using (System.IO.StringReader sr= new
System.IO.StringReader(OriginalXml2)) {
            p = (Person) s1.Deserialize(sr);
          }
        }
        catch (System.InvalidOperationException ex1) {
          System.Console.WriteLine("As Expected, an Exception was generated:
" + ex1);

        }

        if (p!= null) {
          System.Console.WriteLine("\n============================================\nOriginal
values:");
          s1.Serialize(new
XmlTextWriterFormattedNoDeclaration(System.Console.Out), p, ns);
          System.Console.WriteLine("\n");
        }

        p= new Person();
        p.Name= "Henry";
        System.Console.WriteLine("\n============================================\nNew
Instance, setting only Name:");
        s1.Serialize(new
XmlTextWriterFormattedNoDeclaration(System.Console.Out), p, ns);
        System.Console.WriteLine("\n");

        p.Age= 66;
        System.Console.WriteLine("\n============================================\nalso
setting Ageon that instance:");
        s1.Serialize(new
XmlTextWriterFormattedNoDeclaration(System.Console.Out), p, ns);
        System.Console.WriteLine("\n");

        p.AgeSpecified= true;
        System.Console.WriteLine("\n============================================\nand
now setting AgeSpecified:");
        s1.Serialize(new
XmlTextWriterFormattedNoDeclaration(System.Console.Out), p, ns);
        System.Console.WriteLine("\n");

      }
      catch (System.Exception e1) {
        System.Console.WriteLine("Exception!\n" + e1);
      }
    }
  }
}

----- End Code -----


Show quote
"Kenny Mullican" <nospam-kenny!@nowayemonarch.net> wrote in message
news:%23uvw%23J$xEHA.4040@TK2MSFTNGP11.phx.gbl...
>I am using complex types in order to support serialization/deserialization
>of floating point numbers, since floating points can't be null.
>
>
> I've seen how to suppress attributes that are "not specified", such as
> having a float member called Value, and a bool member called
> ValueSpecified. This instructs the XML Serializer to omit that attribute
> altogether if it wasn't "Specified".  But how can I tell it to omit the
> XML element altogether?
>
>
> Here's the problem:
>
>
> I deserialize an object that looks like this:
>
>
> <person>
>
>            <name>Joe</name>
>
>            <age>37</age>
>
> </person>
>
>
>
> When deserialized, I get an object of type person, with a field age of
> type floatType which has Value = 37 and ValueSpecified = false.
>
>
> If I change name to "Bob" (p.name = "Bob"), and then immediately serialize
> that object to XML, I get:
>
>
> <person>
>
>            <name>Bob</name>
>
>            <age />
>
> </person>
>
>
>
> This indicates that age should now be null (if I pass this off to a SOAP
> server for instance), or if that value is not allowed to be nulled, then I
> get a SOAP exception.
>
>
> If I explicitly set p.age.ValueSpecified = true or set p.age.Value = 36
> (which implicitly sets ValueSpecified to true)
>
>
> Then I get the expected
>
>
> <person>
>
>            <name>Bob</name>
>
>            <age>36</age>
>
> </person>
>
>
>
> What I would like to see happen is if ValueSpecified is false, then just
> leave that element off altogether.  Is there a way to do this?
>
>
> Thanks for your help
>
> Kenny
>
>

AddThis Social Bookmark Button