File indexing completed on 2024-05-05 16:49:21

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     auto obj = configFile.object();
0021 
0022     m_url = QUrl(obj[QStringLiteral("url")].toString());
0023     m_entryMarker = obj[QStringLiteral("entry_marker")].toString();
0024     m_titleMarker = obj[QStringLiteral("title")].toString();
0025 
0026     auto cap_it = obj.find(QStringLiteral("cap"));
0027     if (cap_it != obj.end()) {
0028         m_hasCap = true;
0029         auto cap_obj = cap_it->toObject();
0030         m_capLinkElementMarker = cap_obj[QStringLiteral("element")].toString();
0031         m_capValueType = cap_obj[QStringLiteral("type")].toString();
0032         m_capValueMarker = cap_obj[QStringLiteral("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[QStringLiteral("summary")].toString();
0040 
0041     auto area_it = obj.find(QStringLiteral("area"));
0042     if (area_it != obj.end()) {
0043         m_hasArea = true;
0044         auto area_obj = area_it->toObject();
0045         m_areaNameMarker = area_obj[QStringLiteral("name")].toString();
0046         m_polygonMarker = area_obj[QStringLiteral("polygon")].toString();
0047         m_FIPS6Marker = area_obj[QStringLiteral("FIPS6")].toString();
0048         m_UGCMarker = area_obj[QStringLiteral("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[QStringLiteral("urgency")].toString();
0058     m_severityMarker = obj[QStringLiteral("severity")].toString();
0059     m_certaintyMarker = obj[QStringLiteral("certainty")].toString();
0060 
0061     auto date_it = obj.find(QStringLiteral("date"));
0062     if (date_it != obj.end()) {
0063         m_hasDate = true;
0064         auto date_obj = date_it->toObject();
0065         m_dateFormat = date_obj[QStringLiteral("format")].toString();
0066         m_dateMarker = date_obj[QStringLiteral("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>>>
0074 FeedParser::parse(const QByteArray &data) const
0075 {
0076     QXmlStreamReader reader(data);
0077     std::unique_ptr<std::vector<std::unique_ptr<AlertFeedEntry>>> result(
0078         new std::vector<std::unique_ptr<AlertFeedEntry>>());
0079 
0080     while (!reader.atEnd()) {
0081         result->push_back(parseOneEntry(reader));
0082     }
0083 
0084     return result;
0085 }
0086 std::unique_ptr<AlertFeedEntry>
0087 FeedParser::parseOneEntry(QXmlStreamReader &reader) const
0088 {
0089     std::unique_ptr<AlertFeedEntry> entry(new AlertFeedEntry);
0090     std::vector<std::pair<QString, QString>> areaCodes;
0091     while (reader.readNextStartElement()) {
0092         if (reader.name() == m_titleMarker) {
0093             entry->setTitle(reader.readElementText());
0094         } else if (reader.name() == m_summaryMarker) {
0095             entry->setSummary(reader.readElementText());
0096         } else if (reader.name() == m_urgencyMarker) {
0097             entry->setUrgency(urgencyStrToEnum(reader.readElementText()));
0098         } else if (reader.name() == m_severityMarker) {
0099             entry->setSeverity(severityStrToEnum(reader.readElementText()));
0100         } else if (reader.name() == m_certaintyMarker) {
0101             entry->setCertainty(certaintyStrToEnum(reader.readElementText()));
0102         } else if (m_hasCap && reader.name() == m_capLinkElementMarker) {
0103             entry->setUrl(parseCapElement(reader));
0104         } else if (m_hasArea && reader.name() == m_areaNameMarker) {
0105             entry->setArea(reader.readElementText());
0106         } else if (m_hasArea && reader.name() == m_polygonMarker) {
0107             parsePolygonElement(reader, *entry);
0108         } else if (m_hasArea && reader.name() == m_FIPS6Marker) {
0109             areaCodes.push_back(
0110                 {QStringLiteral("FIPS6"), reader.readElementText()});
0111         } else if (m_hasArea && reader.name() == m_UGCMarker) {
0112             areaCodes.push_back(
0113                 {QStringLiteral("UGC"), reader.readElementText()});
0114         } else if (m_hasDate && reader.name() == m_dateMarker) {
0115             if (m_dateFormat == QStringLiteral("ISO-8601")) {
0116                 entry->setDate(QDateTime::fromString(reader.readElementText(),
0117                                                      Qt::ISODate));
0118             } else {
0119                 entry->setDate(QDateTime::fromString(reader.readElementText(),
0120                                                      m_dateFormat));
0121             }
0122         }
0123     }
0124 
0125     entry->setAreaCodes(areaCodes);
0126     return entry;
0127 }
0128 QUrl FeedParser::parseCapElement(QXmlStreamReader &reader) const
0129 {
0130     Q_ASSERT(m_hasCap && reader.isStartElement() &&
0131              reader.name() == m_capLinkElementMarker);
0132 
0133     if (m_capValueType == QStringLiteral("attribute")) {
0134         return QUrl(reader.attributes().value(m_capValueMarker).toString());
0135     } else if (m_capValueType == QStringLiteral("text"))
0136         return QUrl(reader.readElementText());
0137     else
0138         return QUrl();
0139 }
0140 void FeedParser::parsePolygonElement(QXmlStreamReader &reader,
0141                                      AlertFeedEntry &entry) const
0142 {
0143     if (reader.name() == m_polygonMarker) {
0144         entry.setPolygon(stringToPolygon(reader.readElementText()));
0145     }
0146 }
0147 }