Question

I have been assigned to implement an interface to an API that uses XML request/response. The API providers don't provide any xsd(s) for the XML calls.

I generated the C# classes using xsd.exe: .xml -> .xsd -> .cs However, I did not find the generated classes satisfactory, as the calls include a lot of lists, which xsd.exe doesn't handle properly.

Should I take the pain and create classes manually that maps to all the request/responses? That might help in maintaining the code easily later on. Or should I just use Xml classes given by .Net, and write methods to create the XML request/responses? That will take lesser time, but may become tough in the maintenance phase.

Here is a sample class that I have created for a corresponding XML element:

XML Element

<Product ID="41172" Description="2 Pers. With Breakfast" NonRefundable="YES" StartDate="2010-01-01" EndDate="2010-06-30" Rate="250.00" Minstay="1" />

The corresponding class

internal class ProductElement : IElement
{
    private const string ElementName = "Product";

    private const string IdAttribute = "ID";
    private const string DescriptionAttribute = "Description";
    private const string NonRefundableAttribute = "NonRefundable";
    private const string StartDateAttribute = "StartDate";
    private const string EndDateAttribute = "EndDate";
    private const string RateAttribute = "Rate";
    private const string MinStayAttribute = "Minstay";

    private string Id { get; private set; }
    internal string Description { get; private set; }
    internal bool IsNonRefundable { get; private set; }

    private DateRange _dateRange;
    private string ParseFormat = "yyyy-MM-dd";
    private decimal? _rate;
    private int? _minStay;

    internal ProductElement(string id, DateRange dateRange, decimal? rate, int? minStay)
    {
        this.Id = id;
        this._dateRange = dateRange;
        this._rate = rate;
        this._minStay = minStay;
    }
    internal ProductElement(XElement element)
    {
        this.Id = element.Attribute(IdAttribute).Value;
        this.Description = element.Attribute(DescriptionAttribute).Value;
        this.IsNonRefundable = element.Attribute(NonRefundableAttribute).Value.IsEqual("yes") ? true : false;
    }

    public XElement ToXElement()
    {
        var element = new XElement(ElementName);
        element.SetAttributeValue(IdAttribute, _id);
        element.SetAttributeValue(StartDateAttribute, _dateRange.Start.ToString(ParseFormat, CultureInfo.InvariantCulture));
        element.SetAttributeValue(EndDateAttribute, _dateRange.End.ToString(ParseFormat, CultureInfo.InvariantCulture));
        element.SetAttributeValue(RateAttribute, decimal.Round(_rate.Value, 2).ToString());
        element.SetAttributeValue(MinStayAttribute, _minStay.Value.ToString());

        return element;
    }
}

At times, I think I am taking too much pain. Sometimes, I think the pain is worth taking. What is your opinion, people? Also, any improvements in my class design?

Was it helpful?

Solution

You're really over thinking the problem... you can use the System.Xml.Serialization namespace to really save you time and do most of the work for you.

Use this instead:

public class Product
{
    [XmlAttribute()]
    public long Id { get; set; }
    [XmlAttribute()]
    public string Description { get; set; }
    [XmlAttribute()]
    public string NonRefundable { get; set; }
    [XmlAttribute()]
    public string StartDate { get; set; }
    [XmlAttribute()]
    public string EndDate { get; set; }
    [XmlAttribute()]
    public decimal Rate { get; set; }
    [XmlAttribute()]
    public bool Minstay { get; set; }
}

And the code to test:

class Program
{
    static void Main(string[] args)
    {
        string xml = "<Product ID=\"41172\" Description=\"2 Pers. With Breakfast\" NonRefundable=\"YES\" StartDate=\"2010-01-01\" EndDate=\"2010-06-30\" Rate=\"250.00\" Minstay=\"1\" />";
        XmlSerializer ser = new XmlSerializer(typeof(Product));

        using(MemoryStream memStream = new MemoryStream())
        {
            byte[] data = Encoding.Default.GetBytes(xml);
            memStream.Write(data, 0, data.Length);
            memStream.Position = 0;
            Product item = ser.Deserialize(memStream) as Product;
            Console.WriteLine(item.Description);
        }
    }
}

One final note, you will notice I didn't really bother doing anything overly fancy with the conversion for dates and such, but you can easily expand upon this for the additional details. The main thing you should take away from this is that you're really over-thinking this whole thing.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top