8 #include <rss2/category.h>
9 #include <rss2/cloud.h>
10 #include <rss2/document.h>
11 #include <rss2/image.h>
12 #include <rss2/item.h>
13 #include <rss2/textinput.h>
15 #include <constants.h>
16 #include <documentvisitor.h>
19 #include <QDomDocument>
30 class SYNDICATION_NO_EXPORT
Document::DocumentPrivate
34 : itemDescriptionIsCDATA(false)
35 , itemDescriptionContainsMarkup(false)
36 , itemDescGuessed(false)
37 , itemTitleIsCDATA(false)
38 , itemTitleContainsMarkup(false)
39 , itemTitlesGuessed(false)
42 mutable bool itemDescriptionIsCDATA;
43 mutable bool itemDescriptionContainsMarkup;
44 mutable bool itemDescGuessed;
45 mutable bool itemTitleIsCDATA;
46 mutable bool itemTitleContainsMarkup;
47 mutable bool itemTitlesGuessed;
52 , ElementWrapper(element)
53 , d(new DocumentPrivate)
67 , d(new DocumentPrivate)
71 Document::Document(
const Document &other)
72 : SpecificDocument(other)
73 , ElementWrapper(other)
84 ElementWrapper::operator=(other);
88 bool Document::isValid()
const
95 return extractElementTextNS(
QString(), QStringLiteral(
"title"));
100 return extractElementTextNS(
QString(), QStringLiteral(
"link"));
103 QString Document::description()
const
105 const QString desc = extractElementTextNS(
QString(), QStringLiteral(
"description"));
109 QString Document::language()
const
111 const QString lang = extractElementTextNS(
QString(), QStringLiteral(
"language"));
116 return extractElementTextNS(dublinCoreNamespace(), QStringLiteral(
"language"));
120 QString Document::copyright()
const
122 const QString rights = extractElementTextNS(
QString(), QStringLiteral(
"copyright"));
127 return extractElementTextNS(dublinCoreNamespace(), QStringLiteral(
"rights"));
131 QString Document::managingEditor()
const
133 return extractElementTextNS(
QString(), QStringLiteral(
"managingEditor"));
136 QString Document::webMaster()
const
138 return extractElementTextNS(
QString(), QStringLiteral(
"webMaster"));
141 time_t Document::pubDate()
const
143 QString str = extractElementTextNS(
QString(), QStringLiteral(
"pubDate"));
146 return parseDate(str, RFCDate);
149 str = extractElementTextNS(dublinCoreNamespace(), QStringLiteral(
"date"));
150 return parseDate(str, ISODate);
154 time_t Document::lastBuildDate()
const
156 const QString str = extractElementTextNS(
QString(), QStringLiteral(
"lastBuildDate"));
158 return parseDate(str, RFCDate);
168 std::transform(catNodes.
cbegin(), catNodes.
cend(), std::back_inserter(categories), [](
const QDomElement &element) {
169 return Category(element);
175 QString Document::generator()
const
177 return extractElementTextNS(
QString(), QStringLiteral(
"generator"));
182 return extractElementTextNS(
QString(), QStringLiteral(
"docs"));
185 Cloud Document::cloud()
const
187 return Cloud(firstElementByTagNameNS(
QString(), QStringLiteral(
"cloud")));
190 int Document::ttl()
const
195 QString text = extractElementTextNS(
QString(), QStringLiteral(
"ttl"));
200 Image Document::image()
const
202 return Image(firstElementByTagNameNS(
QString(), QStringLiteral(
"image")));
205 TextInput Document::textInput()
const
207 TextInput ti = TextInput(firstElementByTagNameNS(
QString(), QStringLiteral(
"textInput")));
214 return TextInput(firstElementByTagNameNS(
QString(), QStringLiteral(
"textinput")));
220 QDomElement skipHoursNode = firstElementByTagNameNS(
QString(), QStringLiteral(
"skipHours"));
221 if (!skipHoursNode.
isNull()) {
222 ElementWrapper skipHoursWrapper(skipHoursNode);
225 for (
const auto &element : hours) {
226 const int h = element.text().toInt(&ok);
239 QDomElement skipDaysNode = firstElementByTagNameNS(
QString(), QStringLiteral(
"skipDays"));
240 if (!skipDaysNode.
isNull()) {
241 ElementWrapper skipDaysWrapper(skipDaysNode);
246 static const std::vector<DayInfo> weekDays = {
257 for (
const auto &element : days) {
258 const QString day = element.text();
259 auto it = std::find_if(weekDays.cbegin(), weekDays.cend(), [&day](
const DayInfo &info) {
260 return info.name == day;
262 if (it != weekDays.cend()) {
263 skipDays.
insert(it->enumValue);
278 DocumentPtr doccpy(
new Document(*
this));
280 std::transform(itemNodes.
cbegin(), itemNodes.
cend(), std::back_inserter(items), [&doccpy](
const QDomElement &element) {
281 return Item(element, doccpy);
289 static std::vector<ElementType> handled;
290 if (handled.empty()) {
292 handled.push_back(ElementType(QStringLiteral(
"title")));
293 handled.push_back(ElementType(QStringLiteral(
"link")));
294 handled.push_back(ElementType(QStringLiteral(
"description")));
295 handled.push_back(ElementType(QStringLiteral(
"language")));
296 handled.push_back(ElementType(QStringLiteral(
"copyright")));
297 handled.push_back(ElementType(QStringLiteral(
"managingEditor")));
298 handled.push_back(ElementType(QStringLiteral(
"webMaster")));
299 handled.push_back(ElementType(QStringLiteral(
"pubDate")));
300 handled.push_back(ElementType(QStringLiteral(
"lastBuildDate")));
301 handled.push_back(ElementType(QStringLiteral(
"skipDays")));
302 handled.push_back(ElementType(QStringLiteral(
"skipHours")));
303 handled.push_back(ElementType(QStringLiteral(
"item")));
304 handled.push_back(ElementType(QStringLiteral(
"textinput")));
305 handled.push_back(ElementType(QStringLiteral(
"textInput")));
306 handled.push_back(ElementType(QStringLiteral(
"image")));
307 handled.push_back(ElementType(QStringLiteral(
"ttl")));
308 handled.push_back(ElementType(QStringLiteral(
"generator")));
309 handled.push_back(ElementType(QStringLiteral(
"docs")));
310 handled.push_back(ElementType(QStringLiteral(
"cloud")));
311 handled.push_back(ElementType(QStringLiteral(
"language"), dublinCoreNamespace()));
312 handled.push_back(ElementType(QStringLiteral(
"rights"), dublinCoreNamespace()));
313 handled.push_back(ElementType(QStringLiteral(
"date"), dublinCoreNamespace()));
319 const int numChildren = children.
size();
320 for (
int i = 0; i < numChildren; ++i) {
323 && std::find(handled.cbegin(), handled.cend(), ElementType(el.
localName(), el.
namespaceURI())) == handled.cend()) {
331 QString Document::debugInfo()
const
334 info +=
QLatin1String(
"### Document: ###################\n");
335 if (!title().isNull()) {
338 if (!description().isNull()) {
341 if (!
link().isNull()) {
344 if (!language().isNull()) {
347 if (!copyright().isNull()) {
350 if (!managingEditor().isNull()) {
353 if (!webMaster().isNull()) {
363 if (!dlastbuilddate.
isNull()) {
367 if (!textInput().isNull()) {
368 info += textInput().debugInfo();
370 if (!cloud().isNull()) {
371 info += cloud().debugInfo();
373 if (!image().isNull()) {
374 info += image().debugInfo();
379 for (
const auto &c : cats) {
380 info += c.debugInfo();
384 for (
const auto &item : litems) {
385 info += item.debugInfo();
387 info +=
QLatin1String(
"### Document end ################\n");
391 void Document::getItemTitleFormatInfo(
bool *isCDATA,
bool *containsMarkup)
const
393 if (!d->itemTitlesGuessed) {
398 d->itemTitlesGuessed =
true;
405 const int nmax = std::min<int>(litems.
size(), 10);
408 for (
const auto &item : litems) {
412 titles += item.originalTitle();
415 d->itemTitleContainsMarkup = stringContainsMarkup(titles);
416 d->itemTitlesGuessed =
true;
419 if (isCDATA !=
nullptr) {
420 *isCDATA = d->itemTitleIsCDATA;
422 if (containsMarkup !=
nullptr) {
423 *containsMarkup = d->itemTitleContainsMarkup;
427 void Document::getItemDescriptionFormatInfo(
bool *isCDATA,
bool *containsMarkup)
const
429 if (!d->itemDescGuessed) {
434 d->itemDescGuessed =
true;
441 const int nmax = std::min<int>(litems.
size(), 10);
444 for (
const auto &item : litems) {
448 desc += item.originalDescription();
451 d->itemDescriptionContainsMarkup = stringContainsMarkup(desc);
452 d->itemDescGuessed =
true;
455 if (isCDATA !=
nullptr) {
456 *isCDATA = d->itemDescriptionIsCDATA;
458 if (containsMarkup !=
nullptr) {
459 *containsMarkup = d->itemDescriptionContainsMarkup;
463 bool Document::accept(DocumentVisitor *visitor)
465 return visitor->visitRSS2Document(
this);