I am calling an API that returns in XML format.
I have opted to keep the data in XML and not convert to Json.
I am receiving the data back and an instance of each list of data returned.
I have a basic XML class to take a piece of data from it.
I need to extend this to take a lat, long and some other data.
Is there an automated service for XML like Quicktype.io for Json? I am unable to find one and not sure how to structure my Class
This is my call
try{
var response = await client.get(Uri.parse(
'https_call'));
if (response.statusCode == 200) {
final doc = XmlDocument.parse(utf8.decode(response.bodyBytes));
final vehicleActivity = doc
.findAllElements('VehicleActivity')
.map((e) => VehicleActivity.fromElement(e))
.toList();
print(vehicleActivity);
Which functions.
My Class so far
import 'package:xml/xml.dart';
class VehicleActivity {
VehicleActivity({
this.recordedAtTime,
this.itemIdentifier,
this.validUntilTime,
});
DateTime? recordedAtTime;
String? itemIdentifier;
DateTime? validUntilTime;
factory VehicleActivity.fromElement(XmlElement vaElement) => VehicleActivity(
recordedAtTime: DateTime.parse(
vaElement.findElements('RecordedAtTime').first.text,
),
itemIdentifier: vaElement.findElements('ItemIdentifier').first.text,
validUntilTime: DateTime.parse(
vaElement.findElements('ValidUntilTime').first.text,
),
);
}
Example of the XML returned (I need to call lat, long and some other data depending)
<VehicleActivity>
<RecordedAtTime>2022-01-18T14:16:17 00:00</RecordedAtTime>
<ItemIdentifier>f452f348-72f2-4bc4-b7d8-de65e591cf70</ItemIdentifier>
<ValidUntilTime>2022-01-18T14:22:14.063676</ValidUntilTime>
<MonitoredVehicleJourney>
<LineRef>4</LineRef>
<DirectionRef>inbound</DirectionRef>
<FramedVehicleJourneyRef>
<DataFrameRef>2022-01-18</DataFrameRef>
<DatedVehicleJourneyRef>4_20220118_14_15</DatedVehicleJourneyRef>
</FramedVehicleJourneyRef>
<PublishedLineName>4</PublishedLineName>
<OperatorRef>FTVA</OperatorRef>
<DestinationRef>4900801620</DestinationRef>
<VehicleLocation>
<Longitude>-0.720648</Longitude>
<Latitude>51.518651</Latitude>
</VehicleLocation>
<BlockRef>701130</BlockRef>
<VehicleRef>69388</VehicleRef>
</MonitoredVehicleJourney>
<Extensions>
<VehicleJourney>
<Operational>
<TicketMachine>
<TicketMachineServiceCode>B4</TicketMachineServiceCode>
<JourneyCode>1420</JourneyCode>
</TicketMachine>
</Operational>
<VehicleUniqueId>69388</VehicleUniqueId>
<DriverRef>701130</DriverRef>
</VehicleJourney>
</Extensions>
</VehicleActivity>
Thank you
Update
Have attempted to build a class for extracting Lat,long.
Error
Exception Happened: Bad state: No element
Should String be Double?? I can't get double to function
import 'package:xml/xml.dart';
class VehicleLocation{
VehicleLocation({
this.latitude,
this.longitude,
});
String? latitude;
String? longitude;
factory VehicleLocation.fromElement(XmlElement vaElement) => VehicleLocation(
latitude: vaElement.findElements('latitude').first.text,
longitude: vaElement.findElements('longitude').first.text,
);
}
Adapted call testing for lat
final doc = XmlDocument.parse(utf8.decode(response.bodyBytes));
final vehicleActivity = doc
.findAllElements('Latitude')
.map((e) => VehicleLocation.fromElement(e))
.toList();
print(vehicleActivity);
Update #2
I am calling the fetch and then implementing a mapmarker. The future to call and then place the marker is returning issues on vehicleactivity such as
The type 'VehicleActivity' used in the 'for' loop must implement Iterable.
Future<void> showMapMarkers() async {
_unTiltMap();
var vehicleActivity = await fetchLiveLocations();
for (VehicleActivity vehicleActivity in vehicleActivity!) {
GeoCoordinates geoCoordinates = GeoCoordinates (vehicleActivity.latitude, vehicleActivity.latitude);
_addMapMarker(geoCoordinates, 1);
}
}
This same method has worked well for me with different API calls returning Json. Thank you
CodePudding user response:
Update you class to:
class VehicleActivity {
VehicleActivity({
this.recordedAtTime,
this.itemIdentifier,
this.validUntilTime,
this.latitude,
});
DateTime? recordedAtTime;
String? itemIdentifier;
DateTime? validUntilTime;
double? latitude;
factory VehicleActivity.fromElement(XmlElement vaElement) => VehicleActivity(
recordedAtTime: DateTime.parse(
vaElement.findElements('RecordedAtTime').first.text,
),
itemIdentifier: vaElement.findElements('ItemIdentifier').first.text,
validUntilTime: DateTime.parse(
vaElement.findElements('ValidUntilTime').first.text,
),
latitude:
double.tryParse(vaElement.findAllElements('Latitude').first.text),
);
}
Notice that you need to use findAllElements because Latitude is inside a tag <VehicleLocation>. Equally, you could find the VehicleLocation tag and then find the lat/long tags inside that.
I think it would help you to visualise the data better if you format the XML (say in your IDE or browser) to indent it in the traditional way.
<VehicleActivity>
<RecordedAtTime>2021-12-03T18:10:01 00:00</RecordedAtTime>
<ItemIdentifier>ad2c7031-ceac-4e7c-bc0c-9e667ad00dfe</ItemIdentifier>
<ValidUntilTime>2021-12-03T18:16:05.408968</ValidUntilTime>
<MonitoredVehicleJourney>
<LineRef>4</LineRef>
<DirectionRef>inbound</DirectionRef>
<FramedVehicleJourneyRef>
<DataFrameRef>2021-12-03</DataFrameRef>
<DatedVehicleJourneyRef>4_20211203_18_04</DatedVehicleJourneyRef>
</FramedVehicleJourneyRef>
<PublishedLineName>4</PublishedLineName>
<OperatorRef>FTVA</OperatorRef>
<DestinationRef>03700324</DestinationRef>
<VehicleLocation>
<Longitude>-0.719601</Longitude>
<Latitude>51.520305</Latitude>
</VehicleLocation>
<Bearing>30.0</Bearing>
<BlockRef>801312</BlockRef>
<VehicleRef>69921</VehicleRef>
</MonitoredVehicleJourney>
