File indexing completed on 2024-04-14 03:58:25

0001 /*
0002     This file is part of the syndication library
0003     SPDX-FileCopyrightText: 2006 Frank Osterfeld <osterfeld@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "document.h"
0009 #include "atomtools.h"
0010 #include "category.h"
0011 #include "constants.h"
0012 #include "entry.h"
0013 #include "generator.h"
0014 #include "link.h"
0015 #include "person.h"
0016 
0017 #include <documentvisitor.h>
0018 #include <tools.h>
0019 
0020 #include <QDomElement>
0021 #include <QList>
0022 #include <QString>
0023 
0024 #include <vector>
0025 
0026 namespace Syndication
0027 {
0028 namespace Atom
0029 {
0030 FeedDocument::FeedDocument()
0031     : ElementWrapper()
0032 {
0033 }
0034 
0035 FeedDocument::FeedDocument(const QDomElement &element)
0036     : ElementWrapper(element)
0037 {
0038 }
0039 
0040 bool FeedDocument::accept(DocumentVisitor *visitor)
0041 {
0042     return visitor->visitAtomFeedDocument(this);
0043 }
0044 
0045 QList<Person> FeedDocument::authors() const
0046 {
0047     const QList<QDomElement> a = elementsByTagNameNS(atom1Namespace(), QStringLiteral("author"));
0048     QList<Person> list;
0049     list.reserve(a.count());
0050 
0051     std::transform(a.cbegin(), a.cend(), std::back_inserter(list), [](const QDomElement &element) {
0052         return Person(element);
0053     });
0054 
0055     return list;
0056 }
0057 
0058 QList<Person> FeedDocument::contributors() const
0059 {
0060     const QList<QDomElement> a = elementsByTagNameNS(atom1Namespace(), QStringLiteral("contributor"));
0061     QList<Person> list;
0062     list.reserve(a.count());
0063 
0064     std::transform(a.cbegin(), a.cend(), std::back_inserter(list), [](const QDomElement &element) {
0065         return Person(element);
0066     });
0067 
0068     return list;
0069 }
0070 
0071 QList<Category> FeedDocument::categories() const
0072 {
0073     const QList<QDomElement> a = elementsByTagNameNS(atom1Namespace(), QStringLiteral("category"));
0074     QList<Category> list;
0075     list.reserve(a.count());
0076 
0077     std::transform(a.cbegin(), a.cend(), std::back_inserter(list), [](const QDomElement &element) {
0078         return Category(element);
0079     });
0080 
0081     return list;
0082 }
0083 
0084 Generator FeedDocument::generator() const
0085 {
0086     return Generator(firstElementByTagNameNS(atom1Namespace(), QStringLiteral("generator")));
0087 }
0088 
0089 QString FeedDocument::icon() const
0090 {
0091     const QString iconPath = extractElementTextNS(atom1Namespace(), QStringLiteral("icon"));
0092     if (iconPath.isEmpty()) {
0093         return {};
0094     }
0095     return completeURI(iconPath);
0096 }
0097 
0098 QString FeedDocument::logo() const
0099 {
0100     return completeURI(extractElementTextNS(atom1Namespace(), QStringLiteral("logo")));
0101 }
0102 
0103 QString FeedDocument::id() const
0104 {
0105     return extractElementTextNS(atom1Namespace(), QStringLiteral("id"));
0106 }
0107 
0108 QString FeedDocument::rights() const
0109 {
0110     return extractAtomText(*this, QStringLiteral("rights"));
0111 }
0112 
0113 QString FeedDocument::title() const
0114 {
0115     return extractAtomText(*this, QStringLiteral("title"));
0116 }
0117 
0118 QString FeedDocument::subtitle() const
0119 {
0120     return extractAtomText(*this, QStringLiteral("subtitle"));
0121 }
0122 
0123 time_t FeedDocument::updated() const
0124 {
0125     QString upd = extractElementTextNS(atom1Namespace(), QStringLiteral("updated"));
0126     return parseDate(upd, ISODate);
0127 }
0128 
0129 QList<Link> FeedDocument::links() const
0130 {
0131     const QList<QDomElement> a = elementsByTagNameNS(atom1Namespace(), QStringLiteral("link"));
0132     QList<Link> list;
0133     list.reserve(a.count());
0134 
0135     std::transform(a.cbegin(), a.cend(), std::back_inserter(list), [](const QDomElement &element) {
0136         return Link(element);
0137     });
0138 
0139     return list;
0140 }
0141 
0142 QList<Entry> FeedDocument::entries() const
0143 {
0144     const QList<QDomElement> a = elementsByTagNameNS(atom1Namespace(), QStringLiteral("entry"));
0145     QList<Entry> list;
0146     list.reserve(a.count());
0147 
0148     const QList<Person> feedAuthors = authors();
0149 
0150     std::transform(a.cbegin(), a.cend(), std::back_inserter(list), [&feedAuthors](const QDomElement &element) {
0151         Entry entry(element);
0152         entry.setFeedAuthors(feedAuthors);
0153         return entry;
0154     });
0155 
0156     return list;
0157 }
0158 
0159 QList<QDomElement> FeedDocument::unhandledElements() const
0160 {
0161     // TODO: do not hardcode this list here
0162     static std::vector<ElementType> handled; // QVector would require a default ctor, and ElementType is too big for QList
0163     if (handled.empty()) {
0164         handled.reserve(13);
0165         handled.push_back(ElementType(QStringLiteral("author"), atom1Namespace()));
0166         handled.push_back(ElementType(QStringLiteral("contributor"), atom1Namespace()));
0167         handled.push_back(ElementType(QStringLiteral("category"), atom1Namespace()));
0168         handled.push_back(ElementType(QStringLiteral("generator"), atom1Namespace()));
0169         handled.push_back(ElementType(QStringLiteral("icon"), atom1Namespace()));
0170         handled.push_back(ElementType(QStringLiteral("logo"), atom1Namespace()));
0171         handled.push_back(ElementType(QStringLiteral("id"), atom1Namespace()));
0172         handled.push_back(ElementType(QStringLiteral("rights"), atom1Namespace()));
0173         handled.push_back(ElementType(QStringLiteral("title"), atom1Namespace()));
0174         handled.push_back(ElementType(QStringLiteral("subtitle"), atom1Namespace()));
0175         handled.push_back(ElementType(QStringLiteral("updated"), atom1Namespace()));
0176         handled.push_back(ElementType(QStringLiteral("link"), atom1Namespace()));
0177         handled.push_back(ElementType(QStringLiteral("entry"), atom1Namespace()));
0178     }
0179 
0180     QList<QDomElement> notHandled;
0181 
0182     QDomNodeList children = element().childNodes();
0183     const int numChildren = children.size();
0184     for (int i = 0; i < numChildren; ++i) {
0185         QDomElement el = children.at(i).toElement();
0186         if (!el.isNull() //
0187             && std::find(handled.cbegin(), handled.cend(), ElementType(el.localName(), el.namespaceURI())) == handled.cend()) {
0188             notHandled.append(el);
0189         }
0190     }
0191 
0192     return notHandled;
0193 }
0194 
0195 bool FeedDocument::isValid() const
0196 {
0197     return !isNull();
0198 }
0199 
0200 QString FeedDocument::debugInfo() const
0201 {
0202     QString info = QLatin1String("### FeedDocument: ###################\n");
0203     if (!title().isEmpty()) {
0204         info += QLatin1String("title: #") + title() + QLatin1String("#\n");
0205     }
0206     if (!subtitle().isEmpty()) {
0207         info += QLatin1String("subtitle: #") + subtitle() + QLatin1String("#\n");
0208     }
0209     if (!id().isEmpty()) {
0210         info += QLatin1String("id: #") + id() + QLatin1String("#\n");
0211     }
0212 
0213     if (!rights().isEmpty()) {
0214         info += QLatin1String("rights: #") + rights() + QLatin1String("#\n");
0215     }
0216     if (!icon().isEmpty()) {
0217         info += QLatin1String("icon: #") + icon() + QLatin1String("#\n");
0218     }
0219     if (!logo().isEmpty()) {
0220         info += QLatin1String("logo: #") + logo() + QLatin1String("#\n");
0221     }
0222     if (!generator().isNull()) {
0223         info += generator().debugInfo();
0224     }
0225 
0226     QString dupdated = dateTimeToString(updated());
0227     if (!dupdated.isNull()) {
0228         info += QLatin1String("updated: #") + dupdated + QLatin1String("#\n");
0229     }
0230 
0231     const QList<Link> dlinks = links();
0232     for (const auto &link : dlinks) {
0233         info += link.debugInfo();
0234     }
0235 
0236     const QList<Category> dcats = categories();
0237     for (const auto &cat : dcats) {
0238         info += cat.debugInfo();
0239     }
0240 
0241     info += QLatin1String("### Authors: ###################\n");
0242 
0243     const QList<Person> dauthors = authors();
0244     for (const auto &author : dauthors) {
0245         info += author.debugInfo();
0246     }
0247 
0248     info += QLatin1String("### Contributors: ###################\n");
0249 
0250     const QList<Person> dcontri = contributors();
0251     for (const auto &person : dcontri) {
0252         info += person.debugInfo();
0253     }
0254 
0255     const QList<Entry> dentries = entries();
0256     for (const auto &entry : dentries) {
0257         info += entry.debugInfo();
0258     }
0259 
0260     info += QLatin1String("### FeedDocument end ################\n");
0261 
0262     return info;
0263 }
0264 
0265 EntryDocument::EntryDocument()
0266     : ElementWrapper()
0267 {
0268 }
0269 
0270 EntryDocument::EntryDocument(const QDomElement &element)
0271     : ElementWrapper(element)
0272 {
0273 }
0274 
0275 bool EntryDocument::accept(DocumentVisitor *visitor)
0276 {
0277     return visitor->visitAtomEntryDocument(this);
0278 }
0279 
0280 Entry EntryDocument::entry() const
0281 {
0282     return Entry(element());
0283 }
0284 
0285 bool EntryDocument::isValid() const
0286 {
0287     return !isNull();
0288 }
0289 
0290 QString EntryDocument::debugInfo() const
0291 {
0292     QString info;
0293     info += QLatin1String("### EntryDocument: ##################\n");
0294 
0295     Entry dentry = entry();
0296     if (!dentry.isNull()) {
0297         info += dentry.debugInfo();
0298     }
0299 
0300     info += QLatin1String("### EntryDocument end ###############\n");
0301     return info;
0302 }
0303 
0304 } // namespace Atom
0305 } // namespace Syndication