예제 #1
0
        /// <summary>
        /// Parses an API response from the STATION API
        /// </summary>
        /// <param name="response">API response to parse</param>
        /// <returns>IEnumerable of ParserStatements</returns>
        public static IEnumerable <ParserStatement> Parse(APIResponse response)
        {
            if (!response.RequestSucceded)
            {
                yield return(new ErrorStatement(response, ErrorTypes.RequestUnsuccessful));

                yield break;
            }

            if (response.Result != null)
            {
                HtmlDocument document = new HtmlDocument();
                document.LoadHtml(HttpUtility.HtmlDecode(response.Result.ToString()));
                var table = document.DocumentNode.Descendants("table").Where(d => d.HasClass("af")).FirstOrDefault();
                if (table != null)
                {
                    var stationName = table.Descendants("th").Where(d => d.HasClass("title")).FirstOrDefault().ChildNodes.FirstOrDefault().InnerText;
                    var stationId   = new StationIdStatement(response, stationName, null);
                    yield return(stationId);

                    foreach (HtmlNode tr in table.ChildNodes.Where(n => n.Name == "tr" && n.Attributes["onmouseover"] != null && n.Attributes["onmouseout"] != null))
                    {
                        var tds                = tr.ChildNodes.Where(n => n.Name == "td").ToArray();
                        var arrival            = TimeTuple.Parse(tds[0]);
                        var departure          = TimeTuple.Parse(tds[1]);
                        var trainReference     = tds[tds.Length > 3 ? 3 : 2];
                        var trainRefStatements = ParseTrainReference(response, trainReference, stationId, arrival?.Scheduled, departure?.Scheduled).ToList();

                        foreach (var s in trainRefStatements)
                        {
                            yield return(s);
                        }

                        if (!(trainRefStatements.First() is TrainIdStatement trainId))
                        {
                            yield break;
                        }

                        var trainStationId = new TrainStationStatement(response, trainId, stationId, arrival, departure);
                        yield return(trainStationId);

                        var platform = tds.Length > 3 ? tds[2].InnerText.Trim() : null;
                        if (platform?.Length == 0)
                        {
                            platform = null;
                        }
                        yield return(new TrainStationPlatformStatement(response, trainStationId, platform));
                    }
                }
                else
                {
                    yield return(new ErrorStatement(response, ErrorTypes.NoTable));
                }
            }
            else
            {
                yield return(new ErrorStatement(response, ErrorTypes.NoResult));
            }
        }
예제 #2
0
        /// <summary>
        /// Processes the station rows in the HTML response
        /// </summary>
        /// <param name="response">API response</param>
        /// <param name="row">Station row tr</param>
        /// <param name="number">Number of the train station (ordinal)</param>
        /// <param name="id">Identifies the train</param>
        /// <param name="lastStation">Last station (to link sequential stations together)</param>
        /// <returns>Parser statements</returns>
        private static List <ParserStatement> ProcessStationTableRow(APIResponse response, HtmlNode row, TrainIdStatement id, ref StationIdStatement?lastStation)
        {
            List <ParserStatement> ret = new List <ParserStatement>();
            var tds         = row.ChildNodes.Where(n => n.Name == "td").ToArray();
            var stationLink = tds[1].Descendants("a").FirstOrDefault();
            var stationId   = StationIdStatement.FromScript(response, stationLink?.Attributes["onclick"]?.Value);

            if (stationId != null)
            {
                ret.Add(stationId);
            }
            else
            {
                ret.Add(new ErrorStatement(response, ErrorTypes.StationLinkUnparsable));
                ret.Add(stationId = new StationIdStatement(response, stationLink?.InnerText.Trim(), null));
            }

            var hit       = row.HasClass("row_past_odd") || row.HasClass("row_past_even");
            var distance  = CSExtensions.ParseInt(tds[0].InnerText);
            var arrival   = TimeTuple.Parse(tds[2]);
            var departure = TimeTuple.Parse(tds[3]);
            var platform  = (tds.Length > 4) ? tds[4].InnerText.Trim() : null;

            if (platform?.Length == 0)
            {
                platform = null;
            }

            var trainStationId = new TrainStationStatement(response, id, stationId, arrival, departure);

            ret.Add(trainStationId);
            if (lastStation != null)
            {
                ret.Add(new TrainStationLinkStatement(response, id, lastStation, stationId, true));
            }

            lastStation = stationId;

            ret.Add(new TrainStationDistanceStatement(response, trainStationId, distance));
            ret.Add(new TrainStationPlatformStatement(response, trainStationId, platform));
            ret.Add(new TrainStationHitStatement(response, trainStationId, hit));

            return(ret);
        }
예제 #3
0
        public static IEnumerable <ParserStatement> ParseTrainReference(APIResponse response, HtmlNode trainReference, StationIdStatement station, TimeSpan?arrival, TimeSpan?departure)
        {
            var enumerator = trainReference.ChildNodes.AsEnumerable().GetEnumerator();
            TrainIdStatement id;

            if (enumerator.MoveNext())
            {
                if (enumerator.Current.Name == "a")
                {
                    var trainNumber = CSExtensions.ParseInt(enumerator.Current.InnerText);
                    var elviraId    = ElviraIdFromScript(enumerator.Current.Attributes["onclick"]?.Value);

                    if (trainNumber != null)
                    {
                        yield return(id = new TrainIdStatement(response, trainNumber.Value, elviraId));
                    }
                    else
                    {
                        yield return(new ErrorStatement(response, ErrorTypes.TrainReferenceUnparsable));

                        yield break;
                    }
                }
                else
                {
                    yield return(new ErrorStatement(response, ErrorTypes.TrainReferenceUnparsable));

                    yield break;
                }
            }
            else
            {
                yield return(new ErrorStatement(response, ErrorTypes.TrainReferenceUnparsable));

                yield break;
            }

            if (enumerator.MoveNext())
            {
                var       textSplit = enumerator.Current.InnerText.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
                string?   name      = null;
                TrainType?type      = null;
                foreach (var part in textSplit)
                {
                    if ((type = TrainParser.DetermineTrainType(part)) != null)
                    {
                        break;
                    }
                    else
                    {
                        if (name == null)
                        {
                            name = part;
                        }
                        else
                        {
                            name += " " + part;
                        }
                    }
                }

                if (name != null)
                {
                    yield return(new TrainNameStatement(response, id, name));
                }

                if (type != null)
                {
                    yield return(new TrainTypeStatement(response, id, type.Value));
                }
                else
                {
                    throw new Exception("Type does not map!");
                }
            }
            else
            {
                yield break;
            }

            if (!enumerator.MoveNext())
            {
                yield break;
            }

            if (enumerator.MoveNext())
            {
                var text  = enumerator.Current.InnerText;
                var parts = text.Split(" -- ");
                parts[0] = parts[0].Trim();
                parts[1] = parts[1].Trim();

                if (parts[0] == "" && parts[1] == "")
                {
                    yield return(new ErrorStatement(response, ErrorTypes.TrainRelationUnparsable));

                    yield break;
                }

                var p0 = parts[0].Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
                var p1 = parts[1].Split(new char[0], StringSplitOptions.RemoveEmptyEntries);

                if (parts[0] != "")
                {
                    departure = null;
                }
                if (parts[1] != "")
                {
                    arrival = null;
                }

                if (departure == null && TimeSpan.TryParse(p0[0].Trim(), out TimeSpan fromTime))
                {
                    departure = fromTime;
                }

                if (arrival == null && TimeSpan.TryParse(p1[1].Trim(), out TimeSpan toTime))
                {
                    arrival = toTime;
                }

                var from = parts[0] != "" ? new StationIdStatement(response, p0[1].Trim(), null) : station;
                var to   = parts[1] != "" ? new StationIdStatement(response, p1[0].Trim(), null) : station;
                yield return(new TrainRelationStatement(response, id, from, to, departure, arrival));
            }
        }
예제 #4
0
        /// <summary>
        /// Processes the train header part of the HTML response
        /// </summary>
        /// <param name="response">API response</param>
        /// <param name="table">Table HtmlNode</param>
        /// <param name="id">Identifies the train</param>
        /// <param name="elviraId"></param>
        /// <returns>List of parser statements</returns>
        private static List <ParserStatement> ProcessHeader(APIResponse response, HtmlNode table, ref TrainIdStatement?id, string?elviraId)
        {
            List <ParserStatement> ret = new List <ParserStatement>();
            TrainType?type             = null;
            var       headerRow        = table.ChildNodes.Where(n => n.Name == "tr").FirstOrDefault();

            if (headerRow == null)
            {
                ret.Add(new ErrorStatement(response, ErrorTypes.NoTableRows));
                return(ret);
            }

            var headerEnum = headerRow.ChildNodes.Elements().GetEnumerator();

            if (!headerEnum.MoveNext())
            {
                ret.Add(new ErrorStatement(response, ErrorTypes.HeaderEmpty));
                return(ret);
            }

            var headerTextSplit = headerEnum.Current.InnerText.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);

            if (id == null)
            {
                int?trainNumber = null;
                if (headerTextSplit.Length > 0)
                {
                    trainNumber = CSExtensions.ParseInt(headerTextSplit[0]);
                }

                if (trainNumber != null)
                {
                    ret.Add(id = new TrainIdStatement(response, trainNumber.Value, elviraId));
                }
                else
                {
                    ret.Add(new ErrorStatement(response, ErrorTypes.NoTrainIdentification));
                }
            }

            if (id == null)
            {
                return(ret);
            }

            string?name = null;

            for (int i = 1; i < headerTextSplit.Length; i++)
            {
                if ((type = DetermineTrainType(headerTextSplit[i])) != null)
                {
                    break;
                }
                else
                {
                    if (name == null)
                    {
                        name = headerTextSplit[i];
                    }
                    else
                    {
                        name += " " + headerTextSplit[i];
                    }
                }
            }

            ret.Add(new TrainNameStatement(response, id, name));

            while (headerEnum.MoveNext())
            {
                TrainType?detType = DetermineTrainType(headerEnum.Current);

                if (detType != null)
                {
                    if (type != null)
                    {
                        type = detType;
                    }
                }
                else if (headerEnum.Current.Name == "span" && headerEnum.Current.HasClass("viszszam2"))
                {
                    ret.Add(new TrainViszStatement(response, id, headerEnum.Current.InnerText));
                }
                else if (headerEnum.Current.Name == "font")
                {
                    var relationText = headerEnum.Current.InnerText.Substr(1, -1).Split(',')[0].Trim();
                    var stationNames = relationText.Split(" - ").Select(s => s.Trim()).ToArray();

                    var from = new StationIdStatement(response, stationNames[0], null);
                    var to   = new StationIdStatement(response, stationNames[1], null);
                    ret.Add(from);
                    ret.Add(to);
                    ret.Add(new TrainRelationStatement(response, id, from, to));

                    if (type != null)
                    {
                        ret.Add(new TrainTypeStatement(response, id, type.Value));
                    }
                }
                else if (headerEnum.Current.Name == "ul")
                {
                    StationIdStatement?firstFrom = null;
                    StationIdStatement?lastTo    = null;
                    foreach (HtmlNode li in headerEnum.Current.ChildNodes.Where(n => n.Name == "li"))
                    {
                        var       liEnum = li.ChildNodes.AsEnumerable().GetEnumerator();
                        string?   fromStation = null, toStation = null;
                        TrainType?relType = null;
                        if (liEnum.MoveNext())
                        {
                            var text          = liEnum.Current.InnerText.Trim();
                            var colonSplit    = text.Split(':');
                            var relationSplit = colonSplit[0].Split(" - ");
                            fromStation = relationSplit[0].Trim();
                            toStation   = relationSplit[1].Trim();
                            relType     = DetermineTrainType(colonSplit[1].Trim());
                        }
                        if (liEnum.MoveNext())
                        {
                            if (liEnum.Current.Name == "img")
                            {
                                relType = DetermineTrainType(liEnum.Current);
                            }
                        }
                        if (fromStation != null && toStation != null && relType != null)
                        {
                            var from = new StationIdStatement(response, fromStation, null);
                            if (firstFrom != null)
                            {
                                firstFrom = from;
                            }
                            var to = new StationIdStatement(response, toStation, null);
                            lastTo = to;
                            ret.Add(from);
                            ret.Add(to);
                            ret.Add(new TrainSubrelationStatement(response, id, from, to, relType.Value));
                        }
                    }

                    if (firstFrom != null && lastTo != null)
                    {
                        ret.Add(new TrainRelationStatement(response, id, firstFrom, lastTo));
                    }
                }
            }

            return(ret);
        }