6

I have the following XML structure. The theElement element can contain theOptionalList element, or not:

<theElement attrOne="valueOne" attrTwo="valueTwo">
    <theOptionalList>
        <theListItem attrA="valueA" />
        <theListItem attrA="anotherValue" />
        <theListItem attrA="stillAnother" />
    </theOptionalList>
</theElement>
<theElement attrOne="anotherOne" attrTwo="anotherTwo" />

What is a clean way to express the corresponding class structure?

I'm pretty sure of the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace MyNamespace
{
    public class TheOptionalList
    {
        [XmlAttributeAttribute("attrOne")]
        public string AttrOne { get; set; }

        [XmlAttributeAttribute("attrTwo")]
        public string AttrTwo { get; set; }

        [XmlArrayItem("theListItem", typeof(TheListItem))]
        public TheListItem[] theListItems{ get; set; }

        public override string ToString()
        {
            StringBuilder outText = new StringBuilder();

            outText.Append("attrOne = " + AttrOne + " attrTwo = " + AttrTwo + "\r\n");

            foreach (TheListItem li in theListItems)
            {
                outText.Append(li.ToString());
            }

            return outText.ToString();
        }
    }
}

As well as:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Serialization;

namespace MyNamespace
{
    public class TheListItem
    {
        [XmlAttributeAttribute("attrA")]
        public string AttrA { get; set; }

        public override string ToString()
        {
            StringBuilder outText = new StringBuilder();

            outText.Append("  attrA = " + AttrA + "\r\n");                
            return outText.ToString();
        }
    }
}

But what about for theElement? Do I take the theOptionalList element as an array type to have it read what it finds in the file (either nothing, or one) and then check in code whether it's there or not? Or is there another decorator that I can supply? Or does it just work?

EDIT: I ended up using information from this answer.

Community
  • 1
  • 1
John
  • 15,990
  • 10
  • 70
  • 110

3 Answers3

10

Try adding IsNullable = true to the XmlArrayItem attribute.

James Johnson
  • 45,496
  • 8
  • 73
  • 110
  • Thanks for the response James. I'm guessing this would handle a `theOptionalList` element with no elements, but would it handle `theOptionalList` not existing at all? (I might not understand what you're suggesting.) Also, there's no schema for my format; it's all by verbal agreement between me and another developer. :) – John Oct 28 '11 at 21:37
  • I'm not positive, but I think using `IsNullable` would exclude it if the array is null. – James Johnson Oct 28 '11 at 21:42
  • 1
    Consider a schema. It is mightily useful, however small and is a great piece for your 'toolkit'. – Gusdor Apr 02 '13 at 11:32
6

It looks like you can use another bool to specify to include an element or not.

Another option is to use a special pattern to create a Boolean field recognized by the XmlSerializer, and to apply the XmlIgnoreAttribute to the field. The pattern is created in the form of propertyNameSpecified. For example, if there is a field named "MyFirstName" you would also create a field named "MyFirstNameSpecified" that instructs the XmlSerializer whether to generate the XML element named "MyFirstName". This is shown in the following example.

public class OptionalOrder
{
    // This field should not be serialized 
    // if it is uninitialized.
    public string FirstOrder;

    // Use the XmlIgnoreAttribute to ignore the 
    // special field named "FirstOrderSpecified".
    [System.Xml.Serialization.XmlIgnoreAttribute]
    public bool FirstOrderSpecified;
}

http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlserializer.aspx

K2so
  • 952
  • 1
  • 6
  • 14
  • 1
    Thanks for the response. This example deals with serialization, which is part of what I'm facing. The other part is deserialization. What if I call `Deserialize()` on a file with this format? Because I don't think I can tell the `XmlSerializer` for the file as a whole what to expect per element. In other words, is there a default behavior if I deserialize and it doesn't see a member that is specified in the class? – John Oct 28 '11 at 20:53
  • Yes, there is a default behavior: The default constructor of the class. When you deserialize your XML, the `XMLSerializer` calls the default constructor to create your objects, so you can set your defaults here. It is generally helpful to set defaults for properties in the default contructor and append `: this()` on your other constructors to ensure your defaults are set first. – JCH2k Dec 18 '13 at 12:14
1

Additional to the XxySpecifed property, there is also a method with a ShouldSerialize prefix

[XmlElement]
public List<string> OptionalXyz {get; set;}

public bool ShouldSerializeOptionaXyz() {
    return OptionalXyz != null && OptionalXyz.Count > 0 ;
}
Kux
  • 1,362
  • 1
  • 16
  • 31