1/*
2 This file is part of the syndication library
3 SPDX-FileCopyrightText: 2006 Frank Osterfeld <osterfeld@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "document.h"
9#include "atomtools.h"
10#include "category.h"
11#include "constants.h"
12#include "entry.h"
13#include "generator.h"
14#include "link.h"
15#include "person.h"
16
17#include <documentvisitor.h>
18#include <tools.h>
19
20#include <QDomElement>
21#include <QList>
22#include <QString>
23
24#include <vector>
25
26namespace Syndication
27{
28namespace Atom
29{
30FeedDocument::FeedDocument()
31 : ElementWrapper()
32{
33}
34
35FeedDocument::FeedDocument(const QDomElement &element)
36 : ElementWrapper(element)
37{
38}
39
40bool FeedDocument::accept(DocumentVisitor *visitor)
41{
42 return visitor->visitAtomFeedDocument(document: this);
43}
44
45QList<Person> FeedDocument::authors() const
46{
47 const QList<QDomElement> a = elementsByTagNameNS(nsURI: atom1Namespace(), QStringLiteral("author"));
48 QList<Person> list;
49 list.reserve(asize: a.count());
50
51 std::transform(first: a.cbegin(), last: a.cend(), result: std::back_inserter(x&: list), unary_op: [](const QDomElement &element) {
52 return Person(element);
53 });
54
55 return list;
56}
57
58QList<Person> FeedDocument::contributors() const
59{
60 const QList<QDomElement> a = elementsByTagNameNS(nsURI: atom1Namespace(), QStringLiteral("contributor"));
61 QList<Person> list;
62 list.reserve(asize: a.count());
63
64 std::transform(first: a.cbegin(), last: a.cend(), result: std::back_inserter(x&: list), unary_op: [](const QDomElement &element) {
65 return Person(element);
66 });
67
68 return list;
69}
70
71QList<Category> FeedDocument::categories() const
72{
73 const QList<QDomElement> a = elementsByTagNameNS(nsURI: atom1Namespace(), QStringLiteral("category"));
74 QList<Category> list;
75 list.reserve(asize: a.count());
76
77 std::transform(first: a.cbegin(), last: a.cend(), result: std::back_inserter(x&: list), unary_op: [](const QDomElement &element) {
78 return Category(element);
79 });
80
81 return list;
82}
83
84Generator FeedDocument::generator() const
85{
86 return Generator(firstElementByTagNameNS(nsURI: atom1Namespace(), QStringLiteral("generator")));
87}
88
89QString FeedDocument::icon() const
90{
91 const QString iconPath = extractElementTextNS(namespaceURI: atom1Namespace(), QStringLiteral("icon"));
92 if (iconPath.isEmpty()) {
93 return {};
94 }
95 return completeURI(uri: iconPath);
96}
97
98QString FeedDocument::logo() const
99{
100 return completeURI(uri: extractElementTextNS(namespaceURI: atom1Namespace(), QStringLiteral("logo")));
101}
102
103QString FeedDocument::id() const
104{
105 return extractElementTextNS(namespaceURI: atom1Namespace(), QStringLiteral("id"));
106}
107
108QString FeedDocument::rights() const
109{
110 return extractAtomText(parent: *this, QStringLiteral("rights"));
111}
112
113QString FeedDocument::title() const
114{
115 return extractAtomText(parent: *this, QStringLiteral("title"));
116}
117
118QString FeedDocument::subtitle() const
119{
120 return extractAtomText(parent: *this, QStringLiteral("subtitle"));
121}
122
123time_t FeedDocument::updated() const
124{
125 QString upd = extractElementTextNS(namespaceURI: atom1Namespace(), QStringLiteral("updated"));
126 return parseDate(str: upd, hint: ISODate);
127}
128
129QList<Link> FeedDocument::links() const
130{
131 const QList<QDomElement> a = elementsByTagNameNS(nsURI: atom1Namespace(), QStringLiteral("link"));
132 QList<Link> list;
133 list.reserve(asize: a.count());
134
135 std::transform(first: a.cbegin(), last: a.cend(), result: std::back_inserter(x&: list), unary_op: [](const QDomElement &element) {
136 return Link(element);
137 });
138
139 return list;
140}
141
142QList<Entry> FeedDocument::entries() const
143{
144 const QList<QDomElement> a = elementsByTagNameNS(nsURI: atom1Namespace(), QStringLiteral("entry"));
145 QList<Entry> list;
146 list.reserve(asize: a.count());
147
148 const QList<Person> feedAuthors = authors();
149
150 std::transform(first: a.cbegin(), last: a.cend(), result: std::back_inserter(x&: list), unary_op: [&feedAuthors](const QDomElement &element) {
151 Entry entry(element);
152 entry.setFeedAuthors(feedAuthors);
153 return entry;
154 });
155
156 return list;
157}
158
159QList<QDomElement> FeedDocument::unhandledElements() const
160{
161 // TODO: do not hardcode this list here
162 static std::vector<ElementType> handled; // QVector would require a default ctor, and ElementType is too big for QList
163 if (handled.empty()) {
164 handled.reserve(n: 13);
165 handled.push_back(x: ElementType(QStringLiteral("author"), atom1Namespace()));
166 handled.push_back(x: ElementType(QStringLiteral("contributor"), atom1Namespace()));
167 handled.push_back(x: ElementType(QStringLiteral("category"), atom1Namespace()));
168 handled.push_back(x: ElementType(QStringLiteral("generator"), atom1Namespace()));
169 handled.push_back(x: ElementType(QStringLiteral("icon"), atom1Namespace()));
170 handled.push_back(x: ElementType(QStringLiteral("logo"), atom1Namespace()));
171 handled.push_back(x: ElementType(QStringLiteral("id"), atom1Namespace()));
172 handled.push_back(x: ElementType(QStringLiteral("rights"), atom1Namespace()));
173 handled.push_back(x: ElementType(QStringLiteral("title"), atom1Namespace()));
174 handled.push_back(x: ElementType(QStringLiteral("subtitle"), atom1Namespace()));
175 handled.push_back(x: ElementType(QStringLiteral("updated"), atom1Namespace()));
176 handled.push_back(x: ElementType(QStringLiteral("link"), atom1Namespace()));
177 handled.push_back(x: ElementType(QStringLiteral("entry"), atom1Namespace()));
178 }
179
180 QList<QDomElement> notHandled;
181
182 QDomNodeList children = element().childNodes();
183 const int numChildren = children.size();
184 for (int i = 0; i < numChildren; ++i) {
185 QDomElement el = children.at(index: i).toElement();
186 if (!el.isNull() //
187 && std::find(first: handled.cbegin(), last: handled.cend(), val: ElementType(el.localName(), el.namespaceURI())) == handled.cend()) {
188 notHandled.append(t: el);
189 }
190 }
191
192 return notHandled;
193}
194
195bool FeedDocument::isValid() const
196{
197 return !isNull();
198}
199
200QString FeedDocument::debugInfo() const
201{
202 QString info = QLatin1String("### FeedDocument: ###################\n");
203 if (!title().isEmpty()) {
204 info += QLatin1String("title: #") + title() + QLatin1String("#\n");
205 }
206 if (!subtitle().isEmpty()) {
207 info += QLatin1String("subtitle: #") + subtitle() + QLatin1String("#\n");
208 }
209 if (!id().isEmpty()) {
210 info += QLatin1String("id: #") + id() + QLatin1String("#\n");
211 }
212
213 if (!rights().isEmpty()) {
214 info += QLatin1String("rights: #") + rights() + QLatin1String("#\n");
215 }
216 if (!icon().isEmpty()) {
217 info += QLatin1String("icon: #") + icon() + QLatin1String("#\n");
218 }
219 if (!logo().isEmpty()) {
220 info += QLatin1String("logo: #") + logo() + QLatin1String("#\n");
221 }
222 if (!generator().isNull()) {
223 info += generator().debugInfo();
224 }
225
226 QString dupdated = dateTimeToString(date: updated());
227 if (!dupdated.isNull()) {
228 info += QLatin1String("updated: #") + dupdated + QLatin1String("#\n");
229 }
230
231 const QList<Link> dlinks = links();
232 for (const auto &link : dlinks) {
233 info += link.debugInfo();
234 }
235
236 const QList<Category> dcats = categories();
237 for (const auto &cat : dcats) {
238 info += cat.debugInfo();
239 }
240
241 info += QLatin1String("### Authors: ###################\n");
242
243 const QList<Person> dauthors = authors();
244 for (const auto &author : dauthors) {
245 info += author.debugInfo();
246 }
247
248 info += QLatin1String("### Contributors: ###################\n");
249
250 const QList<Person> dcontri = contributors();
251 for (const auto &person : dcontri) {
252 info += person.debugInfo();
253 }
254
255 const QList<Entry> dentries = entries();
256 for (const auto &entry : dentries) {
257 info += entry.debugInfo();
258 }
259
260 info += QLatin1String("### FeedDocument end ################\n");
261
262 return info;
263}
264
265EntryDocument::EntryDocument()
266 : ElementWrapper()
267{
268}
269
270EntryDocument::EntryDocument(const QDomElement &element)
271 : ElementWrapper(element)
272{
273}
274
275bool EntryDocument::accept(DocumentVisitor *visitor)
276{
277 return visitor->visitAtomEntryDocument(document: this);
278}
279
280Entry EntryDocument::entry() const
281{
282 return Entry(element());
283}
284
285bool EntryDocument::isValid() const
286{
287 return !isNull();
288}
289
290QString EntryDocument::debugInfo() const
291{
292 QString info;
293 info += QLatin1String("### EntryDocument: ##################\n");
294
295 Entry dentry = entry();
296 if (!dentry.isNull()) {
297 info += dentry.debugInfo();
298 }
299
300 info += QLatin1String("### EntryDocument end ###############\n");
301 return info;
302}
303
304} // namespace Atom
305} // namespace Syndication
306

source code of syndication/src/atom/document.cpp