Reputation: 793
I wanted to deserialize TCX files containing sport data into some my local/temporary object. I used XSD schema describing such format and created classes using xsd2code.
After that I was able to deserialize XML into proper object and the deserialzator didn't throw any exception. But when I started to expand behaviour of component I noticed that some fields are not properly fullfield.
The problem is about reading the tags Track. Deserialized Lap in substructure shows all data properly, but the Tracks number is displayed as 0.
Is there any way to trigger deserializer to interpret it properly? Did I miss some attribute? Why it is not reading it properly even if there was no exception.
I know, it is hard to explain and put all needed classes into comment - so I share my current status here and just write that: GetUnifiedData_WhenTrackPointsAreGivenInTcx_UnifiedTrackPointShouldRetreiveIt() is not passing and shows my problem.
<Activities>
<Activity Sport="Running">
<Id>2015-01-25T12:14:34Z</Id>
<Lap StartTime="2015-01-25T12:14:34Z">
<TotalTimeSeconds>507.0989990</TotalTimeSeconds>
<DistanceMeters>1000.0000000</DistanceMeters>
<MaximumSpeed>2.5790000</MaximumSpeed>
<Calories>95</Calories>
<AverageHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>155</Value>
</AverageHeartRateBpm>
<MaximumHeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>173</Value>
</MaximumHeartRateBpm>
<Intensity>Resting</Intensity>
<TriggerMethod>Distance</TriggerMethod>
<Track>
<Trackpoint>
<Time>2015-01-25T12:14:34Z</Time>
<Position>
<LatitudeDegrees>50.8918607</LatitudeDegrees>
<LongitudeDegrees>16.7403161</LongitudeDegrees>
</Position>
<AltitudeMeters>233.1999969</AltitudeMeters>
<DistanceMeters>0.0000000</DistanceMeters>
<HeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t">
<Value>88</Value>
</HeartRateBpm>
<Extensions>
<TPX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2" CadenceSensor="Footpod">
<Speed>0.0000000</Speed>
</TPX>
</Extensions>
</Trackpoint>
</Track>
<Track>
</Track>
<Extensions>
<FatCalories xmlns="http://www.garmin.com/xmlschemas/FatCalories/v1">
<Value>0</Value>
</FatCalories>
<LX xmlns="http://www.garmin.com/xmlschemas/ActivityExtension/v2">
<AvgSpeed>1.9720000</AvgSpeed>
</LX>
</Extensions>
</Lap>
</Activity>
</Activities>
Upvotes: 0
Views: 434
Reputation: 116526
The problem is that your data model is wrong. In the below excerpt, you will see two Track
elements below the Lap
element:
<?xml version="1.0" encoding="utf-16" standalone="no"?>
<TrainingCenterDatabase xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.garmin.com/xmlschemas/ActivityExtension/v2 http://www.garmin.com/xmlschemas/ActivityExtensionv2.xsd http://www.garmin.com/xmlschemas/FatCalories/v1 http://www.garmin.com/xmlschemas/fatcalorieextensionv1.xsd http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd">
<Activities>
<Activity Sport="Running">
<Id>2015-01-25T12:14:34Z</Id>
<Lap StartTime="2015-01-25T12:14:34Z">
<Track>
<Trackpoint>
<Time>2015-01-25T12:14:34Z</Time>
... etc etc
</Trackpoint>
<Trackpoint>
... etc etc
</Trackpoint>
</Track>
<Track>
<Trackpoint>
... etc etc
<Trackpoint>
</Track>
However, in your data model Track
is a singleton property of Lap
containing an array of TrackPoint_t
entries. When XmlSerializer
encounters more than one Track
elements it fails to deserialize them.
Thus your data model needs to be as follows. Introduce an intermediate class Track_t
:
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2")]
public class Track_t
{
public Track_t()
{
this.Track = new List<Trackpoint_t>();
}
[System.Xml.Serialization.XmlElement("TrackPoint", typeof(Trackpoint_t), IsNullable = false)]
public List<Trackpoint_t> Track { get; set; }
}
And modify ActivityLap_t
as follows:
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.0.30319.34234")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2")
]
public partial class ActivityLap_t
{
private List<Track_t> _track; // Change type to `Track_t`
public ActivityLap_t()
{
this._extensions = new Extensions_t();
this._track = new List<Track_t>(); // Change type to `Track_t`
this._maximumHeartRateBpm = new HeartRateInBeatsPerMinute_t();
this._averageHeartRateBpm = new HeartRateInBeatsPerMinute_t();
}
// Change type to `Track_t` and change attribute to `XmlElement`
[System.Xml.Serialization.XmlElement("Track", typeof(Track_t), IsNullable = false)]
public List<Track_t> Track
{
get { return this._track; }
set { this._track = value; }
}
// Remainder unchanged.
}
You will also need to modify Course_t
in the same way.
The xsd
does specify the existence of a type Track_t
and that ActivityLap_t
can contain an unbounded number of Track
elements of this type, so somehow the XSD was transformed into classes incorrectly:
<xsd:complexType name="ActivityLap_t">
<xsd:sequence>
<xsd:element name="TotalTimeSeconds" type="xsd:double" />
<xsd:element name="DistanceMeters" type="xsd:double" />
<xsd:element name="MaximumSpeed" type="xsd:double" minOccurs="0" />
<xsd:element name="Calories" type="xsd:unsignedShort" />
<xsd:element name="AverageHeartRateBpm" type="HeartRateInBeatsPerMinute_t" minOccurs="0" />
<xsd:element name="MaximumHeartRateBpm" type="HeartRateInBeatsPerMinute_t" minOccurs="0" />
<xsd:element name="Intensity" type="Intensity_t" />
<xsd:element name="Cadence" type="CadenceValue_t" minOccurs="0" />
<xsd:element name="TriggerMethod" type="TriggerMethod_t" />
<xsd:element name="Track" type="Track_t" minOccurs="0" maxOccurs="unbounded" /> <!-- Notice that maxOccurs is unbounded so "Track" needs to be a list -->
<xsd:element name="Notes" type="xsd:string" minOccurs="0" />
<xsd:element name="Extensions" type="Extensions_t" minOccurs="0">
<xsd:annotation>
<xsd:documentation>
You can extend Training Center by adding your own elements from another schema here.
</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="StartTime" type="xsd:dateTime" use="required" />
</xsd:complexType>
and
<xsd:complexType name="Track_t">
<xsd:sequence>
<xsd:element name="TrackPoint" type="TrackPoint_t" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
Upvotes: 1