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);
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
118 QStringList uris09 = RSS09Vocab::self()->properties();
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
186Parser::Parser()
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
205QString Parser::format() const
206{
207 return QStringLiteral("rdf");
208}
209
210} // namespace RDF
211} // namespace Syndication
Type type(const QSqlDatabase &db)
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardShortcut id)
QDomElement createElementNS(const QString &nsURI, const QString &qName)
QDomText createTextNode(const QString &value)
QDomElement documentElement() const const
QDomNodeList elementsByTagNameNS(const QString &nsURI, const QString &localName)
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 Tue Mar 26 2024 11:14:15 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.