0

I'm trying to manually deserialize a hierarchy of data objects (full code down below), but getting an exception I do not understand.

  • DEMDataSet contains a collection of DemographicReportGroup objects.
  • DemographicReportGroup implements IXmlSerializable, contains Agency object.
  • Agency object contains the leaf data item dAgency.01, aka EMSAgencyUniqueStateID.

I'm working on implementing the ReadXml method for DemographicReportGroup, but I get an exception thrown as follows:

#region ReadXml
public void ReadXml(System.Xml.XmlReader xmlReader)
{
    xmlReader.MoveToContent();
    this.timeStamp = DateTime.Parse(xmlReader.GetAttribute("timeStamp"));
    if (xmlReader.IsEmptyElement) return;
    xmlReader.ReadStartElement();
    if (xmlReader.Name == "dAgency") 
    { 
        xmlReader.ReadStartElement("dAgency");
        // **Exception here: System.InvalidOperationException**
        this.Agency = new XmlSerializer(typeof(Agency)).Deserialize(xmlReader) as Agency; 
        xmlReader.ReadEndElement(); 
    }
    xmlReader.ReadEndElement();
}
#endregion

System.InvalidOperationException: <dAgency.01 xmlns='http://www.nemsis.org'> was not expected.

All the code samples I've found so far indicate that this should work... Perhaps it's a misconfiguration of the XML attributes?

Hopefully someone can help!

Also, in case you are curious:

  • Why are you implementing IXmlSerializable at all?
    • The timeStamp property is a date/time. If it was a plain DateTime, it would always have a value (1/1/0001) when it is serialized. The DateTime? type lets me know when it does not have a value, but it cannot be serialized as an attribute. The data standard that this example is a part of dictates that the time stamp must be an attribute.
  • What about implementing a ShouldSerializetimeStampValue?
    • That would make an extra property and extra method (timeStampValue and ShouldSerializetimeStampValue), which is too much code for one data item. Also, this is not the only time stamp I'm dealing with.

Full code (as unit test for Visual Studio):

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;  // System.Xml.dll.
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Tests.Xml
{
    [TestClass]
    public class TestIXmlSerializable
    {
        [TestMethod]
        public void DeserializeChildElement()
        {
            var xml = @"<DEMDataSet xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://www.nemsis.org http://nemsis.org/media/XSD_v3/_nemsis_v3.3.1/3.3.1.130201/XSDs/NEMSIS_XSDs_v3.3.1.130201/DEMDataSet_v3.xsd""  xmlns=""http://www.nemsis.org"">
    <DemographicReport timeStamp=""1969-03-14T07:38:20+07:00"">
        <dAgency>
            <dAgency.01>M</dAgency.01>
        </dAgency>
    </DemographicReport>
</DEMDataSet>";

            var xmlSerializer = new XmlSerializer(typeof(DEMDataSet));

            DEMDataSet demDataSet = null;

            using (var streamReader = new StringReader(xml))
                demDataSet = xmlSerializer.Deserialize(streamReader) as DEMDataSet;

        }
    }

    [Serializable]
    /// <summary>Root Tag For Demographic DataSet</summary>
    [XmlType(AnonymousType = true, Namespace = "http://www.nemsis.org")]
    [XmlRoot(Namespace = "http://www.nemsis.org", IsNullable = false)]
    public partial class DEMDataSet
    {
        #region DemographicReportGroup
        private List<DemographicReportGroup> _demographicReportGroup;

        /// <summary>Container Tag to hold each instance of a demographic record</summary>
        [XmlElement("DemographicReport")]
        public List<DemographicReportGroup> DemographicReportGroup
        {
            get
            {
                return this._demographicReportGroup;
            }
            set
            {
                this._demographicReportGroup = value;
            }
        }
        #endregion

    }

    [Serializable]
    public partial class DemographicReportGroup : IXmlSerializable
    {
        #region Agency
        private Agency _agency;

        /// <summary></summary>
        [XmlElement("dAgency", IsNullable = false)]
        public Agency Agency
        {
            get
            {
                return this._agency;
            }
            set
            {
                this._agency = value;
            }
        }
        #endregion

        #region timeStamp
        private DateTime? _timeStamp;

        /// <summary></summary>
        [XmlAttribute]
        public DateTime? timeStamp
        {
            get
            {
                return this._timeStamp;
            }
            set
            {
                this._timeStamp = value;
            }
        }
        #endregion

        #region GetSchema
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }
        #endregion

        #region ReadXml
        public void ReadXml(System.Xml.XmlReader xmlReader)
        {
            xmlReader.MoveToContent();
            this.timeStamp = DateTime.Parse(xmlReader.GetAttribute("timeStamp"));
            if (xmlReader.IsEmptyElement) return;
            xmlReader.ReadStartElement();
            if (xmlReader.Name == "dAgency") { xmlReader.ReadStartElement("dAgency"); this.Agency = new XmlSerializer(typeof(Agency)).Deserialize(xmlReader) as Agency; xmlReader.ReadEndElement(); }
            xmlReader.ReadEndElement();
        }
        #endregion

        #region WriteXml
        public void WriteXml(System.Xml.XmlWriter xmlWriter)
        {
            if (this.timeStamp.HasValue) xmlWriter.WriteAttributeString("timeStamp", this.timeStamp.Value.ToString("o"));
            if (this.Agency != null) { xmlWriter.WriteStartElement("dAgency"); new XmlSerializer(typeof(Agency)); xmlWriter.WriteEndElement(); }
        }
        #endregion
    }

    [Serializable]
    /// <summary></summary>
    [XmlType(Namespace = "http://www.nemsis.org")]
    [XmlRoot(Namespace = "http://www.nemsis.org", IsNullable = true)]
    public partial class Agency
    {
        #region EMSAgencyUniqueStateID
        private string _emsAgencyUniqueStateID;

        /// <summary>The unique ID assigned to the EMS Agency which is associated with all state licensure numbers and information.</summary>
        [XmlElement("dAgency.01")]
        public string EMSAgencyUniqueStateID
        {
            get
            {
                return this._emsAgencyUniqueStateID;
            }
            set
            {
                this._emsAgencyUniqueStateID = value;
            }
        }
        #endregion
    }
}
dythim
  • 920
  • 7
  • 24
  • 1
    I would build a `DEMDataSet` object in memory and serialize it to a file to see what the result is. You'll probably find that your types specify a slightly different XmlSchema than the one you think (and the one you've therefore used in your test method). – phoog Apr 16 '13 at 17:15
  • This does seem to be the case. I'm getting an extra set of tags for Agency: M – dythim Apr 16 '13 at 17:59

1 Answers1

0

How about using Linq To Xml

var xml = @"<DEMDataSet xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xsi:schemaLocation=""http://www.nemsis.org http://nemsis.org/media/XSD_v3/_nemsis_v3.3.1/3.3.1.130201/XSDs/NEMSIS_XSDs_v3.3.1.130201/DEMDataSet_v3.xsd""  xmlns=""http://www.nemsis.org"">
                <DemographicReport timeStamp=""1969-03-14T07:38:20+07:00"">
                    <dAgency>
                        <dAgency.01>M</dAgency.01>
                    </dAgency>
                </DemographicReport>
            </DEMDataSet>";

var xDoc = XDocument.Parse(xml);
XNamespace ns = "http://www.nemsis.org";
var result = xDoc.Descendants(ns + "DemographicReport")
                .Select(d => new DemographicReportGroup
                {
                    timeStamp = (DateTime)d.Attribute("timeStamp"),
                    Agency = new Agency{EMSAgencyUniqueStateID = d.Descendants(ns + "dAgency.01").First().Value}
                })
                .ToList();

public class DemographicReportGroup
{
    public Agency Agency { set; get; }
    public DateTime timeStamp;
}

public class Agency
{
    public string EMSAgencyUniqueStateID { set; get; }
}
I4V
  • 34,891
  • 6
  • 67
  • 79