Syndication

rdf/parser.cpp
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 "parser.h"
9#include "document.h"
10#include "model.h"
11#include "modelmaker.h"
12#include "property.h"
13#include "rdfvocab.h"
14#include "resource.h"
15#include "rssvocab.h"
16#include "statement.h"
17
18#include <documentsource.h>
19
20#include <QDomDocument>
21#include <QDomNodeList>
22#include <QHash>
23#include <QList>
24#include <QMap>
25#include <QString>
26#include <QStringList>
27
28namespace Syndication
29{
30namespace RDF
31{
32class SYNDICATION_NO_EXPORT Parser::ParserPrivate
33{
34public:
35 QDomDocument addEnumeration(const QDomDocument &doc);
36 void map09to10(Model model);
37 void addSequenceFor09(Model model);
38
39 QString strInternalNs;
40 QString strItemIndex;
41};
42
43bool Parser::accept(const DocumentSource &source) const
44{
45 QDomDocument doc = source.asDomDocument();
46
47 if (doc.isNull()) {
48 return false;
49 }
50 QDomElement root = doc.documentElement();
51
52 if (!root.isElement()) {
53 return false;
54 }
55
56 return root.namespaceURI() == RDFVocab::self()->namespaceURI();
57}
58
59SpecificDocumentPtr Parser::parse(const DocumentSource &source) const
60{
61 QDomDocument doc = source.asDomDocument();
62
63 if (doc.isNull()) {
64 return Syndication::SpecificDocumentPtr(new Document());
65 }
66
67 doc = d->addEnumeration(doc);
68
69 ModelMaker maker;
70 Model model = maker.createFromXML(doc);
71
72 bool is09 = !model.resourcesWithType(RSS09Vocab::self()->channel()).isEmpty();
73
74 if (is09) {
75 d->map09to10(model);
76 d->addSequenceFor09(model);
77 }
78
79 QList<ResourcePtr> channels = model.resourcesWithType(RSSVocab::self()->channel());
80
81 if (channels.isEmpty()) {
82 return Syndication::SpecificDocumentPtr(new Document());
83 }
84
85 return DocumentPtr(new Document(*(channels.begin())));
86}
87
88QDomDocument Parser::ParserPrivate::addEnumeration(const QDomDocument &docp)
89{
90 QDomDocument doc(docp);
91
92 const QDomNodeList list = doc.elementsByTagNameNS(RSS09Vocab::self()->namespaceURI(), QStringLiteral("item"));
93
94 for (int i = 0; i < list.size(); ++i) {
95 QDomElement item = list.item(i).toElement();
96 if (!item.isNull()) {
97 QDomElement ie = doc.createElementNS(strInternalNs, strItemIndex);
98 item.appendChild(ie);
99 ie.appendChild(doc.createTextNode(QString::number(i)));
100 }
101 }
102
103 return doc;
104}
105
106void Parser::ParserPrivate::map09to10(Model model)
107{
109
110 hash.insert(RSS09Vocab::self()->title()->uri(), RSSVocab::self()->title());
111 hash.insert(RSS09Vocab::self()->description()->uri(), RSSVocab::self()->description());
112 hash.insert(RSS09Vocab::self()->link()->uri(), RSSVocab::self()->link());
113 hash.insert(RSS09Vocab::self()->name()->uri(), RSSVocab::self()->name());
114 hash.insert(RSS09Vocab::self()->url()->uri(), RSSVocab::self()->url());
115 hash.insert(RSS09Vocab::self()->image()->uri(), RSSVocab::self()->image());
116 hash.insert(RSS09Vocab::self()->textinput()->uri(), RSSVocab::self()->textinput());
117
119
120 // map statement predicates to RSS 1.0
121
122 const QList<StatementPtr> &statements = model.statements();
123
124 for (const auto &stmt : statements) {
125 const QString predUri = stmt->predicate()->uri();
126 if (uris09.contains(predUri)) {
127 model.addStatement(stmt->subject(), hash[predUri], stmt->object());
128 }
129 }
130 // map channel type
131 QList<ResourcePtr> channels = model.resourcesWithType(RSS09Vocab::self()->channel());
132
133 ResourcePtr channel;
134
135 if (!channels.isEmpty()) {
136 channel = *(channels.begin());
137
138 model.removeStatement(channel, RDFVocab::self()->type(), RSS09Vocab::self()->channel());
139 model.addStatement(channel, RDFVocab::self()->type(), RSSVocab::self()->channel());
140 }
141}
142
143void Parser::ParserPrivate::addSequenceFor09(Model model)
144{
145 // RDF 0.9 doesn't contain an item sequence, and the items don't have rdf:about, so add both
146
147 const QList<ResourcePtr> items = model.resourcesWithType(RSS09Vocab::self()->item());
148
149 if (items.isEmpty()) {
150 return;
151 }
152
153 const QList<ResourcePtr> channels = model.resourcesWithType(RSSVocab::self()->channel());
154
155 if (channels.isEmpty()) {
156 return;
157 }
158
159 PropertyPtr itemIndex = model.createProperty(strInternalNs + strItemIndex);
160
161 // use QMap here, not QHash. as we need the sorting functionality
163
164 for (const ResourcePtr &i : items) {
165 QString numstr = i->property(itemIndex)->asString();
166 bool ok = false;
167 uint num = numstr.toUInt(&ok);
168 if (ok) {
169 sorted[num] = i;
170 }
171 }
172
173 SequencePtr seq = model.createSequence();
174 model.addStatement(channels.first(), RSSVocab::self()->items(), seq);
175
176 for (const ResourcePtr &i : std::as_const(sorted)) {
177 seq->append(i);
178 // add rdf:about (type)
179 model.addStatement(i, RDFVocab::self()->type(), RSSVocab::self()->item());
180
181 // add to items sequence
182 model.addStatement(seq, RDFVocab::self()->li(), i);
183 }
184}
185
187 : d(new ParserPrivate)
188{
189 d->strInternalNs = QStringLiteral("http://akregator.sf.net/libsyndication/internal#");
190 d->strItemIndex = QStringLiteral("itemIndex");
191}
192
193Parser::~Parser() = default;
194
195Parser::Parser(const Parser &other)
196 : AbstractParser(other)
197 , d(nullptr)
198{
199}
200Parser &Parser::operator=(const Parser & /*other*/)
201{
202 return *this;
203}
204
206{
207 return QStringLiteral("rdf");
208}
209
210} // namespace RDF
211} // namespace Syndication
Interface for all parsers.
Represents the source of a syndication document, as read from the downloaded file.
QDomDocument asDomDocument() const
Returns the feed source as DOM document.
Document implementation for RDF, representing an RSS 1.0 feed.
An RDF parser, used to parse an RDF model from RDF/XML.
Definition modelmaker.h:35
Model createFromXML(const QDomDocument &doc)
parses an RDF model from RDF/XML
An RDF model, a set of RDF statements.
Definition model.h:37
virtual QList< ResourcePtr > resourcesWithType(ResourcePtr type) const
returns all resources of a given type.
Definition model.cpp:247
Parser implementation for RDF-based RSS 0.9 and RSS 1.0 feeds.
Definition rdf/parser.h:28
QString format() const override
format string of this parser, which is "rdf".
bool accept(const DocumentSource &source) const override
returns whether the passed document looks like an RSS 0.9 or RSS 1.0 document.
SpecificDocumentPtr parse(const DocumentSource &source) const override
Parses an RSS 0.9/1.0 document from a feed source.
~Parser() override
destructor
Parser()
default constructor
static RDFVocab * self()
returns the singleton instance
Definition rdfvocab.cpp:36
QString namespaceURI()
the RDF namespace, which is http://www.w3.org/1999/02/22-rdf-syntax-ns#
Definition rdfvocab.cpp:75
QStringList properties() const
returns a list containing all URIs representing properties in this vocabulary
Definition rssvocab.cpp:246
static RSS09Vocab * self()
returns the singleton instance
Definition rssvocab.cpp:182
PropertyPtr items() const
RSS 1.0 items property, see Document::items() for more details.
Definition rssvocab.cpp:113
static RSSVocab * self()
returns the singleton instance
Definition rssvocab.cpp:63
Type type(const QSqlDatabase &db)
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
QString name(StandardAction id)
QDomElement documentElement() const const
QDomNode appendChild(const QDomNode &newChild)
bool isElement() const const
bool isNull() const const
QString namespaceURI() const const
iterator insert(const Key &key, const T &value)
iterator begin()
T & first()
bool isEmpty() const const
qsizetype size() const const
QString number(double n, char format, int precision)
uint toUInt(bool *ok, int base) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 18 2024 12:09:18 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.