thanks, I think I understand scan
a little better now. Played around a bit more and ended up with:
(defn xml->tracks
[xml]
(m/search
xml
{:tag ::tx/tfmDataService
:content ({:tag ::tx/fltdOutput
:content (m/scan
{:tag ::fdm/fltdMessage
:attrs {:msgType "trackInformation"
:flightRef ?flight-ref
:acid ?aircraft-id
:airline ?airline
:depArpt ?departure-airport
:arrArpt ?arrival-airport
:sourceTimeStamp ?message-ts}
:content ({:tag ::fdm/trackInformation
:content (m/scan
{:tag ::nxcm/qualifiedAircraftId}
{:tag ::nxcm/speed
:content (?speed)}
{:tag ::nxcm/reportedAltitude
:content ({:tag ::nxce/assignedAltitude
:content ((m/or
{:tag ::nxce/simpleAltitude
:content (?altitude)}
{:tag ::nxce/blockedAltitude
:attrs {:min (?altitude)}}
{:tag ::nxce/visualFlightRules
:attrs {:altitude ?altitude}}
{:tag ::nxce/altitudeFixAltitude
:attrs {:preFixAltitude ?altitude}}))})}
{:tag ::nxcm/position
:content (m/scan
{:tag ::nxce/latitude
:content ({:tag ::nxce/latitudeDMS
:attrs ?latitude-dms})}
{:tag ::nxce/longitude
:content ({:tag ::nxce/longitudeDMS
:attrs ?longitude-dms})})}
{:tag ::nxcm/timeAtPosition
:content (?track-ts)}
.
(m/or
{:tag ::nxcm/ncsmTrackData
:content (m/seqable
.
(m/or
{:tag ::nxcm/nextEvent
:attrs {:latitudeDecimal ?next-lat
:longitudeDecimal ?next-long}}
(m/let [?next-lat nil ?next-long nil]))
..1)}
{:tag ::nxcm/ncsmRouteData
:content (m/scan
{:tag ::nxcm/nextPosition
:attrs {:latitudeDecimal ?next-lat
:longitudeDecimal ?next-long}})}))})})})}
(merge {:flight/ref (Long/parseLong ?flight-ref)
:flight/aircraft-id ?aircraft-id
:flight/airline ?airline
:flight/arrival-airport ?arrival-airport
:flight/departure-airport ?departure-airport
:track/speed (Integer/parseInt ?speed)}
(when (and ?next-lat ?next-long)
{:track/next-latitude (Double/parseDouble ?next-lat)
:track/next-longitude (Double/parseDouble ?next-long)}))))
Not especially happy with the last bit, but haven't been able to figure out a better way that doesn't generate 'extra' entries. What I'm trying to express is that the element after timeAtPosition
will be either a ncsmTrackData
or ncsmRouteData
tag, but if it's a ncsmTrackData
it may or may not contain a nextEvent
with a lat/long.