File indexing completed on 2024-04-28 04:42:42

0001 /*
0002  * SPDX-FileCopyrightText: 2021 Han Young <hanyoung@protonmail.com>
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 #include "feedparser.h"
0007 #include "kweathercore_p.h"
0008 #include <QDateTime>
0009 #include <QJsonObject>
0010 namespace KWeatherCore
0011 {
0012 FeedParser::FeedParser(const QJsonDocument &configFile, QObject *parent)
0013     : QObject(parent)
0014 {
0015     setConfig(configFile);
0016 }
0017 
0018 void FeedParser::setConfig(const QJsonDocument &configFile)
0019 {
0020     const auto obj = configFile.object();
0021 
0022     m_url = QUrl(obj[QLatin1String("url")].toString());
0023     m_entryMarker = obj[QLatin1String("entry_marker")].toString();
0024     m_titleMarker = obj[QLatin1String("title")].toString();
0025 
0026     auto cap_it = obj.find(QLatin1String("cap"));
0027     if (cap_it != obj.end()) {
0028         m_hasCap = true;
0029         const auto cap_obj = cap_it->toObject();
0030         m_capLinkElementMarker = cap_obj[QLatin1String("element")].toString();
0031         m_capValueType = cap_obj[QLatin1String("type")].toString();
0032         m_capValueMarker = cap_obj[QLatin1String("value")].toString();
0033     } else {
0034         m_hasCap = false;
0035         m_capLinkElementMarker.clear();
0036         m_capValueMarker.clear();
0037         m_capValueType.clear();
0038     }
0039     m_summaryMarker = obj[QLatin1String("summary")].toString();
0040 
0041     auto area_it = obj.find(QLatin1String("area"));
0042     if (area_it != obj.end()) {
0043         m_hasArea = true;
0044         const auto area_obj = area_it->toObject();
0045         m_areaNameMarker = area_obj[QLatin1String("name")].toString();
0046         m_polygonMarker = area_obj[QLatin1String("polygon")].toString();
0047         m_FIPS6Marker = area_obj[QLatin1String("FIPS6")].toString();
0048         m_UGCMarker = area_obj[QLatin1String("UGC")].toString();
0049     } else {
0050         m_hasArea = false;
0051         m_areaNameMarker.clear();
0052         m_polygonMarker.clear();
0053         m_FIPS6Marker.clear();
0054         m_UGCMarker.clear();
0055     }
0056 
0057     m_urgencyMarker = obj[QLatin1String("urgency")].toString();
0058     m_severityMarker = obj[QLatin1String("severity")].toString();
0059     m_certaintyMarker = obj[QLatin1String("certainty")].toString();
0060 
0061     auto date_it = obj.find(QLatin1String("date"));
0062     if (date_it != obj.end()) {
0063         m_hasDate = true;
0064         const auto date_obj = date_it->toObject();
0065         m_dateFormat = date_obj[QLatin1String("format")].toString();
0066         m_dateMarker = date_obj[QLatin1String("element")].toString();
0067     } else {
0068         m_hasDate = false;
0069         m_dateFormat.clear();
0070         m_dateMarker.clear();
0071     }
0072 }
0073 std::unique_ptr<std::vector<std::unique_ptr<AlertFeedEntry>>> FeedParser::parse(const QByteArray &data) const
0074 {
0075     QXmlStreamReader reader(data);
0076     std::unique_ptr<std::vector<std::unique_ptr<AlertFeedEntry>>> result(new std::vector<std::unique_ptr<AlertFeedEntry>>());
0077 
0078     while (!reader.atEnd()) {
0079         result->push_back(parseOneEntry(reader));
0080     }
0081 
0082     return result;
0083 }
0084 std::unique_ptr<AlertFeedEntry> FeedParser::parseOneEntry(QXmlStreamReader &reader) const
0085 {
0086     std::unique_ptr<AlertFeedEntry> entry(new AlertFeedEntry);
0087     std::vector<std::pair<QString, QString>> areaCodes;
0088     while (reader.readNextStartElement()) {
0089         if (reader.name() == m_titleMarker) {
0090             entry->setTitle(reader.readElementText());
0091         } else if (reader.name() == m_summaryMarker) {
0092             entry->setSummary(reader.readElementText());
0093         } else if (reader.name() == m_urgencyMarker) {
0094             entry->setUrgency(KWeatherCorePrivate::urgencyStringToEnum(reader.readElementText()));
0095         } else if (reader.name() == m_severityMarker) {
0096             entry->setSeverity(KWeatherCorePrivate::severityStringToEnum(reader.readElementText()));
0097         } else if (reader.name() == m_certaintyMarker) {
0098             entry->setCertainty(KWeatherCorePrivate::certaintyStringToEnum(reader.readElementText()));
0099         } else if (m_hasCap && reader.name() == m_capLinkElementMarker) {
0100             entry->setUrl(parseCapElement(reader));
0101         } else if (m_hasArea && reader.name() == m_areaNameMarker) {
0102             entry->setArea(reader.readElementText());
0103         } else if (m_hasArea && reader.name() == m_polygonMarker) {
0104             parsePolygonElement(reader, *entry);
0105         } else if (m_hasArea && reader.name() == m_FIPS6Marker) {
0106             areaCodes.push_back({QStringLiteral("FIPS6"), reader.readElementText()});
0107         } else if (m_hasArea && reader.name() == m_UGCMarker) {
0108             areaCodes.push_back({QStringLiteral("UGC"), reader.readElementText()});
0109         } else if (m_hasDate && reader.name() == m_dateMarker) {
0110             if (m_dateFormat == QLatin1String("ISO-8601")) {
0111                 entry->setDate(QDateTime::fromString(reader.readElementText(), Qt::ISODate));
0112             } else {
0113                 entry->setDate(QDateTime::fromString(reader.readElementText(), m_dateFormat));
0114             }
0115         }
0116     }
0117 
0118     entry->setAreaCodes(areaCodes);
0119     return entry;
0120 }
0121 QUrl FeedParser::parseCapElement(QXmlStreamReader &reader) const
0122 {
0123     Q_ASSERT(m_hasCap && reader.isStartElement() && reader.name() == m_capLinkElementMarker);
0124 
0125     if (m_capValueType == QLatin1String("attribute")) {
0126         return QUrl(reader.attributes().value(m_capValueMarker).toString());
0127     } else if (m_capValueType == QLatin1String("text")) {
0128         return QUrl(reader.readElementText());
0129     } else {
0130         return QUrl();
0131     }
0132 }
0133 void FeedParser::parsePolygonElement(QXmlStreamReader &reader, AlertFeedEntry &entry) const
0134 {
0135     if (reader.name() == m_polygonMarker) {
0136         entry.setPolygon(KWeatherCorePrivate::stringToPolygon(reader.readElementText()));
0137     }
0138 }
0139 }
0140 
0141 #include "moc_feedparser.cpp"