Syndication

rdf/parser.cpp
1 /*
2  This file is part of the syndication library
3  SPDX-FileCopyrightText: 2006 Frank Osterfeld <[email protected]>
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 
28 namespace Syndication
29 {
30 namespace RDF
31 {
32 class SYNDICATION_NO_EXPORT Parser::ParserPrivate
33 {
34 public:
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 
43 bool 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 
59 SpecificDocumentPtr 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 
88 QDomDocument 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 
106 void 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 
143 void 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 
186 Parser::Parser()
187  : d(new ParserPrivate)
188 {
189  d->strInternalNs = QStringLiteral("http://akregator.sf.net/libsyndication/internal#");
190  d->strItemIndex = QStringLiteral("itemIndex");
191 }
192 
193 Parser::~Parser()
194 {
195  delete d;
196 }
197 
198 Parser::Parser(const Parser &other)
199  : AbstractParser(other)
200  , d(nullptr)
201 {
202 }
203 Parser &Parser::operator=(const Parser & /*other*/)
204 {
205  return *this;
206 }
207 
208 QString Parser::format() const
209 {
210  return QStringLiteral("rdf");
211 }
212 
213 } // namespace RDF
214 } // namespace Syndication
T & first()
QString number(int n, int base)
QDomElement createElementNS(const QString &nsURI, const QString &qName)
Type type(const QSqlDatabase &db)
bool isNull() const const
bool contains(const QString &str, Qt::CaseSensitivity cs) const const
QDomText createTextNode(const QString &value)
KIOFILEWIDGETS_EXPORT QStringList list(const QString &fileClass)
Model
Definition: resource.h:38
QString namespaceURI() const const
QHash::iterator insert(const Key &key, const T &value)
KIOCORE_EXPORT CopyJob * link(const QList< QUrl > &src, const QUrl &destDir, JobFlags flags=DefaultFlags)
int size() const const
QDomNodeList elementsByTagNameNS(const QString &nsURI, const QString &localName)
bool isEmpty() const const
QDomElement documentElement() const const
uint toUInt(bool *ok, int base) const const
QDomNode appendChild(const QDomNode &newChild)
QString name(StandardShortcut id)
QList::iterator begin()
bool isElement() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 03:57:11 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.