Flight data explorer
Mix.install([
{:tesla, "~> 1.7"},
{:sweet_xml, "~> 0.7.3"},
{:castore, "~> 1.0"},
{:plug_cowboy, "~> 2.6"}
])
Requests
import SweetXml
ba =
"https://gist.githubusercontent.com/kanmaniselvan/bb11edf031e254977b210c480a0bd89a/raw/ea9bcb65ba4bb2304580d6202ece88aee38540f8/ba_response_sample.xml"
klm =
"https://gist.githubusercontent.com/kanmaniselvan/bb11edf031e254977b210c480a0bd89a/raw/ea9bcb65ba4bb2304580d6202ece88aee38540f8/afklm_response_sample.xml"
Simple transformer helper
defmodule FlightsHelper do
def add_provider(
%{currency: currency, price: price, offer_id: offer_id, segment_ids: segment_ids},
provider
) do
Task.async(fn ->
%{
provider: provider |> to_string(),
currency: currency |> to_string(),
price: price |> to_string() |> String.to_float(),
offer_id: offer_id |> to_string(),
segment_ids: segment_ids |> Enum.uniq()
}
end)
end
end
Save responses
ba_response =
ba
|> Tesla.get!()
|> Map.get(:body)
# Air France
klm_response =
klm
|> Tesla.get!()
|> Map.get(:body)
Extract offers and flight segments
# British Airways
ba_prices =
ba_response
|> xpath(
~x"//AirlineOffers/AirlineOffer"l,
currency: ~x"./TotalPrice/SimpleCurrencyPrice/@Code",
price: ~x"./TotalPrice/SimpleCurrencyPrice/text()",
offer_id: ~x"./OfferID/text()",
segment_ids: ~x"./PricedOffer/Associations/ApplicableFlight/FlightSegmentReference/@ref"l
)
|> Enum.map(&FlightsHelper.add_provider(&1, "ba"))
|> Task.await_many()
# Air France
klm_prices =
klm_response
|> xpath(
~x"//ns2:OffersGroup/ns2:CarrierOffers/ns2:Offer"l,
currency: ~x"./ns2:OfferItem/ns2:Price/ns2:TotalAmount/@CurCode",
price: ~x"./ns2:OfferItem/ns2:Price/ns2:TotalAmount/text()",
offer_id: ~x"./ns2:OfferID/text()",
segment_ids: ~x"./ns2:OfferItem/ns2:FareDetail/ns2:FareComponent/ns2:PaxSegmentRefID/text()"l
)
|> Enum.map(&FlightsHelper.add_provider(&1, "klm"))
|> Task.await_many()
Extract flight segments
ba_segments =
ba_response
|> xpath(
~x"//DataLists/FlightSegmentList/FlightSegment"l,
segment_id: ~x"./@SegmentKey",
origin: ~x"./Departure/AirportCode/text()",
destination: ~x"./Arrival/AirportCode/text()",
departure_date: ~x"./Departure/Date/text()"
)
klm_segments =
klm_response
|> xpath(
~x"//ns2:DataLists/ns2:PaxSegmentList/ns2:PaxSegment"l,
segment_id: ~x"./ns2:PaxSegmentID/text()",
origin: ~x"./ns2:Dep/ns2:IATALocationCode/text()",
destination: ~x"./ns2:Arrival/ns2:IATALocationCode/text()",
departure_date: ~x"./ns2:Dep/ns2:AircraftScheduledDateTime/text()"
)
all_segments = ba_segments ++ klm_segments
Next is to create a map using segment id => segment
segment_mapping =
all_segments
|> Enum.group_by(fn %{segment_id: segment_id} ->
segment_id
end)
all_offers =
(ba_prices ++ klm_prices)
|> Enum.sort_by(fn %{price: price} -> price end, :asc)
all_offers
|> Enum.map(fn %{segment_ids: segment_ids} ->
segment_ids
|> Enum.map(fn sid ->
segment_mapping |> Map.get(sid)
end)
end)
Time to search
# sample query string - origin=BER&destination=LHR&departureDate=2019-07-17
origin = "MUC"
dest = "LCY"
date = "2021-09-28"
filtered_segments =
all_segments
|> Enum.filter(fn segment ->
to_string(segment.origin) == origin && to_string(segment.destination) == dest
end)
results =
if not is_nil(date) do
filtered_segments
|> Enum.filter(fn segment ->
segment.departure_date
|> to_string()
|> String.starts_with?(date)
end)
|> Enum.map(& &1.segment_id)
else
filtered_segments
|> Enum.map(& &1.segment_id)
end
sorted_results =
results
|> Enum.map(fn segment_id ->
all_offers
|> Enum.filter(fn offer ->
offer.segment_ids |> Enum.member?(segment_id |> to_charlist())
end)
end)
|> List.flatten()
|> Enum.group_by(fn %{price: price} ->
price
end)
key =
sorted_results
|> Map.keys()
|> Enum.at(0)
sorted_results |> Map.get(key)
# Enum.at(sorted_results, 0)
Plug.Conn.Query experiments
alias Plug.Conn.Query
Query.decode("origin=BER&destination=LHR&departureDate=2019-07-17")
defmodule DateMatcher do
def match(
<>
) do
IO.puts(year)
IO.puts(month)
IO.puts(day)
end
def match(_), do: :error
end
DateMatcher.match("2022-07-17")
IO.puts("------")
DateMatcher.match("2019-07-17T00:00:00")
IO.puts("------")
DateMatcher.match(nil)