Syndication

rss2/item.cpp
1 /*
2  This file is part of the syndication library
3  SPDX-FileCopyrightText: 2005 Frank Osterfeld <[email protected]>
4 
5  SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7 
8 #include <constants.h>
9 #include <rss2/category.h>
10 #include <rss2/enclosure.h>
11 #include <rss2/item.h>
12 #include <rss2/source.h>
13 #include <rss2/tools_p.h>
14 #include <specificitem.h>
15 #include <specificitemvisitor.h>
16 #include <tools.h>
17 
18 #include <QDomElement>
19 #include <QList>
20 #include <QString>
21 
22 #include <vector>
23 
24 namespace Syndication
25 {
26 namespace RSS2
27 {
28 class SYNDICATION_NO_EXPORT Item::ItemPrivate
29 {
30 public:
32 };
33 
34 Item::Item(QSharedPointer<Document> doc)
35  : ElementWrapper()
36  , d(new ItemPrivate)
37 {
38  d->doc = doc;
39 }
40 
41 Item::Item(const QDomElement &element, QSharedPointer<Document> doc)
42  : ElementWrapper(element)
43  , d(new ItemPrivate)
44 {
45  d->doc = doc;
46 }
47 
49 {
50 }
51 
52 Item::Item(const Item &other)
53  : ElementWrapper(other)
54  , SpecificItem(other)
55 {
56  d = other.d;
57 }
58 
59 Item &Item::operator=(const Item &other)
60 {
61  ElementWrapper::operator=(other);
62  SpecificItem::operator=(other);
63  d = other.d;
64  return *this;
65 }
66 
67 QString Item::title() const
68 {
69  if (!d->doc) {
70  return originalTitle();
71  }
72 
73  bool isCDATA = false;
74  bool containsMarkup = false;
75  d->doc->getItemTitleFormatInfo(&isCDATA, &containsMarkup);
76 
77  return normalize(originalTitle(), isCDATA, containsMarkup);
78 }
79 
80 QString Item::originalDescription() const
81 {
82  return extractElementTextNS(QString(), QStringLiteral("description"));
83 }
84 
85 QString Item::originalTitle() const
86 {
87  return extractElementTextNS(QString(), QStringLiteral("title"));
88 }
89 
90 QString Item::link() const
91 {
92  QString url = extractElementTextNS(QString(), QStringLiteral("link"));
93  if (url.startsWith(QLatin1String("http://")) || url.startsWith(QLatin1String("https://"))) {
94  return url;
95  }
96  if (url.isEmpty()) {
97  return QString();
98  }
99  if (d->doc->link().isEmpty()) {
100  return url;
101  }
102  // link does not look like a complete url, assume the feed author expects
103  // the doc link to provide the base of the url.
104  QString baseUrl = d->doc->link();
105  if (url.startsWith(QLatin1Char('/')) || baseUrl.endsWith(QLatin1Char('/'))) {
106  return baseUrl + url;
107  } else {
108  return baseUrl + QLatin1Char('/') + url;
109  }
110 }
111 
113 {
114  if (!d->doc) {
115  return originalDescription();
116  }
117 
118  bool isCDATA = false;
119  bool containsMarkup = false;
120  d->doc->getItemDescriptionFormatInfo(&isCDATA, &containsMarkup);
121 
122  return normalize(originalDescription(), isCDATA, containsMarkup);
123 }
124 
126 {
127  // parse encoded stuff from content:encoded, xhtml:body and friends into content
128  return extractContent(*this);
129 }
130 
132 {
133  const QList<QDomElement> cats = elementsByTagNameNS(QString(), QStringLiteral("category"));
134 
136  categories.reserve(cats.count());
137 
138  std::transform(cats.cbegin(), cats.cend(), std::back_inserter(categories), [](const QDomElement &element) {
139  return Category(element);
140  });
141 
142  return categories;
143 }
144 
145 QString Item::comments() const
146 {
147  return extractElementTextNS(QString(), QStringLiteral("comments"));
148 }
149 
150 QString Item::author() const
151 {
152  QString a = extractElementTextNS(QString(), QStringLiteral("author"));
153  if (!a.isNull()) {
154  return a;
155  } else {
156  // if author is not available, fall back to dc:creator
157  return extractElementTextNS(dublinCoreNamespace(), QStringLiteral("creator"));
158  }
159 }
160 
162 {
163  const QList<QDomElement> encs = elementsByTagNameNS(QString(), QStringLiteral("enclosure"));
164 
166  enclosures.reserve(encs.count());
167 
168  std::transform(encs.cbegin(), encs.cend(), std::back_inserter(enclosures), [](const QDomElement &element) {
169  return Enclosure(element);
170  });
171 
172  return enclosures;
173 }
174 
175 QString Item::guid() const
176 {
177  return extractElementTextNS(QString(), QStringLiteral("guid"));
178 }
179 
180 bool Item::guidIsPermaLink() const
181 {
182  bool guidIsPermaLink = true; // true is default
183 
184  QDomElement guidNode = firstElementByTagNameNS(QString(), QStringLiteral("guid"));
185  if (!guidNode.isNull()) {
186  if (guidNode.attribute(QStringLiteral("isPermaLink")) == QLatin1String("false")) {
187  guidIsPermaLink = false;
188  }
189  }
190 
191  return guidIsPermaLink;
192 }
193 
194 time_t Item::pubDate() const
195 {
196  QString str = extractElementTextNS(QString(), QStringLiteral("pubDate"));
197 
198  if (!str.isNull()) {
199  return parseDate(str, RFCDate);
200  }
201 
202  // if there is no pubDate, check for dc:date
203  str = extractElementTextNS(dublinCoreNamespace(), QStringLiteral("date"));
204  return parseDate(str, ISODate);
205 }
206 
207 time_t Item::expirationDate() const
208 {
209  QString str = extractElementTextNS(QString(), QStringLiteral("expirationDate"));
210  return parseDate(str, RFCDate);
211 }
212 
213 Source Item::source() const
214 {
215  return Source(firstElementByTagNameNS(QString(), QStringLiteral("source")));
216 }
217 
218 QString Item::rating() const
219 {
220  return extractElementTextNS(QString(), QStringLiteral("rating"));
221 }
222 
223 QString Item::debugInfo() const
224 {
225  QString info = QLatin1String("### Item: ###################\n");
226  if (!title().isNull()) {
227  info += QLatin1String("title: #") + title() + QLatin1String("#\n");
228  }
229  if (!link().isNull()) {
230  info += QLatin1String("link: #") + link() + QLatin1String("#\n");
231  }
232  if (!description().isNull()) {
233  info += QLatin1String("description: #") + description() + QLatin1String("#\n");
234  }
235  if (!content().isNull()) {
236  info += QLatin1String("content: #") + content() + QLatin1String("#\n");
237  }
238  if (!author().isNull()) {
239  info += QLatin1String("author: #") + author() + QLatin1String("#\n");
240  }
241  if (!comments().isNull()) {
242  info += QLatin1String("comments: #") + comments() + QLatin1String("#\n");
243  }
244  QString dpubdate = dateTimeToString(pubDate());
245  if (!dpubdate.isNull()) {
246  info += QLatin1String("pubDate: #") + dpubdate + QLatin1String("#\n");
247  }
248  if (!guid().isNull()) {
249  info += QLatin1String("guid: #") + guid() + QLatin1String("#\n");
250  }
251  if (guidIsPermaLink()) {
252  info += QLatin1String("guid is PL: #true#\n");
253  }
254  if (!source().isNull()) {
255  info += source().debugInfo();
256  }
257 
258  const QList<Category> cats = categories();
259  for (const auto &c : cats) {
260  info += c.debugInfo();
261  }
262 
263  const QList<Enclosure> encs = enclosures();
264  for (const auto &e : encs) {
265  info += e.debugInfo();
266  }
267 
268  info += QLatin1String("### Item end ################\n");
269  return info;
270 }
271 
272 QList<QDomElement> Item::unhandledElements() const
273 {
274  // TODO: do not hardcode this list here
275  static std::vector<ElementType> handled; // QVector would require a default ctor, and ElementType is too big for QList
276  if (handled.empty()) {
277  handled.reserve(11);
278  handled.push_back(ElementType(QStringLiteral("title")));
279  handled.push_back(ElementType(QStringLiteral("link")));
280  handled.push_back(ElementType(QStringLiteral("description")));
281  handled.push_back(ElementType(QStringLiteral("pubDate")));
282  handled.push_back(ElementType(QStringLiteral("expirationDate")));
283  handled.push_back(ElementType(QStringLiteral("rating")));
284  handled.push_back(ElementType(QStringLiteral("source")));
285  handled.push_back(ElementType(QStringLiteral("guid")));
286  handled.push_back(ElementType(QStringLiteral("comments")));
287  handled.push_back(ElementType(QStringLiteral("author")));
288  handled.push_back(ElementType(QStringLiteral("date"), dublinCoreNamespace()));
289  }
290 
291  QList<QDomElement> notHandled;
292 
293  QDomNodeList children = element().childNodes();
294  const int numChildren = children.size();
295  for (int i = 0; i < numChildren; ++i) {
296  QDomElement el = children.at(i).toElement();
297  if (!el.isNull() //
298  && std::find(handled.cbegin(), handled.cend(), ElementType(el.localName(), el.namespaceURI())) == handled.cend()) {
299  notHandled.append(el);
300  }
301  }
302 
303  return notHandled;
304 }
305 
306 bool Item::accept(SpecificItemVisitor *visitor)
307 {
308  return visitor->visitRSS2Item(this);
309 }
310 
311 } // namespace RSS2
312 } // namespace Syndication
void append(const T &value)
virtual ~Item()
destructor
Definition: item.cpp:18
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool isNull() const const
QDomElement toElement() const const
virtual QString content() const =0
returns the content of the item.
Definition: rss2/item.cpp:125
int count(const T &value) const const
bool isNull() const const
virtual QList< EnclosurePtr > enclosures() const =0
returns a list of enclosures describing files available on the net.
Definition: rss2/item.cpp:161
QString normalize(QStringView str)
QDomNode at(int index) const const
int size() const const
QString namespaceURI() const const
void reserve(int alloc)
virtual QString title() const =0
The title of the item.
virtual QString debugInfo() const
returns a description of the item for debugging purposes
Definition: item.cpp:22
QString localName() const const
virtual QList< CategoryPtr > categories() const =0
returns a list of categories this item is filed in.
Definition: rss2/item.cpp:131
bool isEmpty() const const
virtual QString description() const =0
returns the description of the item.
QList::const_iterator cend() const const
KCALUTILS_EXPORT QString dateTimeToString(const QDateTime &date, bool dateOnly=false, bool shortfmt=true)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
QList::const_iterator cbegin() const const
virtual QString link() const =0
returns a link to the (web) resource described by this item.
QString attribute(const QString &name, const QString &defValue) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Dec 5 2023 03:58:07 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.