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 | |
26 | namespace Syndication |
27 | { |
28 | namespace Atom |
29 | { |
30 | FeedDocument::FeedDocument() |
31 | : ElementWrapper() |
32 | { |
33 | } |
34 | |
35 | FeedDocument::FeedDocument(const QDomElement &element) |
36 | : ElementWrapper(element) |
37 | { |
38 | } |
39 | |
40 | bool FeedDocument::accept(DocumentVisitor *visitor) |
41 | { |
42 | return visitor->visitAtomFeedDocument(document: this); |
43 | } |
44 | |
45 | QList<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 | |
58 | QList<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 | |
71 | QList<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 | |
84 | Generator FeedDocument::generator() const |
85 | { |
86 | return Generator(firstElementByTagNameNS(nsURI: atom1Namespace(), QStringLiteral("generator" ))); |
87 | } |
88 | |
89 | QString 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 | |
98 | QString FeedDocument::logo() const |
99 | { |
100 | return completeURI(uri: extractElementTextNS(namespaceURI: atom1Namespace(), QStringLiteral("logo" ))); |
101 | } |
102 | |
103 | QString FeedDocument::id() const |
104 | { |
105 | return extractElementTextNS(namespaceURI: atom1Namespace(), QStringLiteral("id" )); |
106 | } |
107 | |
108 | QString FeedDocument::rights() const |
109 | { |
110 | return extractAtomText(parent: *this, QStringLiteral("rights" )); |
111 | } |
112 | |
113 | QString FeedDocument::title() const |
114 | { |
115 | return extractAtomText(parent: *this, QStringLiteral("title" )); |
116 | } |
117 | |
118 | QString FeedDocument::subtitle() const |
119 | { |
120 | return extractAtomText(parent: *this, QStringLiteral("subtitle" )); |
121 | } |
122 | |
123 | time_t FeedDocument::updated() const |
124 | { |
125 | QString upd = extractElementTextNS(namespaceURI: atom1Namespace(), QStringLiteral("updated" )); |
126 | return parseDate(str: upd, hint: ISODate); |
127 | } |
128 | |
129 | QList<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 | |
142 | QList<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 | |
159 | QList<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 | |
195 | bool FeedDocument::isValid() const |
196 | { |
197 | return !isNull(); |
198 | } |
199 | |
200 | QString 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 | |
265 | EntryDocument::EntryDocument() |
266 | : ElementWrapper() |
267 | { |
268 | } |
269 | |
270 | EntryDocument::EntryDocument(const QDomElement &element) |
271 | : ElementWrapper(element) |
272 | { |
273 | } |
274 | |
275 | bool EntryDocument::accept(DocumentVisitor *visitor) |
276 | { |
277 | return visitor->visitAtomEntryDocument(document: this); |
278 | } |
279 | |
280 | Entry EntryDocument::entry() const |
281 | { |
282 | return Entry(element()); |
283 | } |
284 | |
285 | bool EntryDocument::isValid() const |
286 | { |
287 | return !isNull(); |
288 | } |
289 | |
290 | QString 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 | |