kde-playground/kdepimlibs/syndication/rdf/parser.cpp
2015-04-14 21:49:29 +00:00

230 lines
6.6 KiB
C++

/*
* This file is part of the syndication library
*
* Copyright (C) 2006 Frank Osterfeld <osterfeld@kde.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "parser.h"
#include "document.h"
#include "model.h"
#include "modelmaker.h"
#include "property.h"
#include "rdfvocab.h"
#include "resource.h"
#include "rssvocab.h"
#include "statement.h"
#include <documentsource.h>
#include <QtXml/QDomDocument>
#include <QtXml/QDomNodeList>
#include <QtCore/QHash>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
namespace Syndication {
namespace RDF {
class Parser::ParserPrivate
{
public:
QDomDocument addEnumeration(const QDomDocument& doc);
void map09to10(Model model);
void addSequenceFor09(Model model);
QString strInternalNs;
QString strItemIndex;
};
bool Parser::accept(const DocumentSource& source) const
{
QDomDocument doc = source.asDomDocument();
if (doc.isNull())
return false;
QDomElement root = doc.documentElement();
if (!root.isElement())
return false;
return root.namespaceURI() == RDFVocab::self()->namespaceURI();
}
SpecificDocumentPtr Parser::parse(const DocumentSource& source) const
{
QDomDocument doc = source.asDomDocument();
if (doc.isNull())
return Syndication::SpecificDocumentPtr(new Document());
doc = d->addEnumeration(doc);
ModelMaker maker;
Model model = maker.createFromXML(doc);
bool is09 = !model.resourcesWithType(RSS09Vocab::self()->channel()).isEmpty();
if (is09)
{
d->map09to10(model);
d->addSequenceFor09(model);
}
QList<ResourcePtr> channels = model.resourcesWithType(RSSVocab::self()->channel());
if (channels.isEmpty())
return Syndication::SpecificDocumentPtr(new Document());
return DocumentPtr(new Document(*(channels.begin())));
}
QDomDocument Parser::ParserPrivate::addEnumeration(const QDomDocument& docp)
{
QDomDocument doc(docp);
QDomNodeList list = doc.elementsByTagNameNS(RSS09Vocab::self()->namespaceURI(),
QLatin1String("item"));
for (int i = 0; i < list.size(); ++i)
{
QDomElement item = list.item(i).toElement();
if (!item.isNull())
{
QDomElement ie = doc.createElementNS(strInternalNs, strItemIndex);
item.appendChild(ie);
ie.appendChild(doc.createTextNode(QString::number(i)));
}
}
return doc;
}
void Parser::ParserPrivate::map09to10(Model model)
{
QHash<QString, PropertyPtr> hash;
hash.insert(RSS09Vocab::self()->title()->uri(), RSSVocab::self()->title());
hash.insert(RSS09Vocab::self()->description()->uri(), RSSVocab::self()->description());
hash.insert(RSS09Vocab::self()->link()->uri(), RSSVocab::self()->link());
hash.insert(RSS09Vocab::self()->name()->uri(), RSSVocab::self()->name());
hash.insert(RSS09Vocab::self()->url()->uri(), RSSVocab::self()->url());
hash.insert(RSS09Vocab::self()->image()->uri(), RSSVocab::self()->image());
hash.insert(RSS09Vocab::self()->textinput()->uri(), RSSVocab::self()->textinput());
QStringList uris09 = RSS09Vocab::self()->properties();
// map statement predicates to RSS 1.0
QList<StatementPtr> statements = model.statements();
QList<StatementPtr>::ConstIterator it = statements.constBegin();
QList<StatementPtr>::ConstIterator end = statements.constEnd();
for ( ; it != end; ++it)
{
StatementPtr stmt = *it;
QString predUri = stmt->predicate()->uri();
if (uris09.contains(predUri))
{
model.addStatement(stmt->subject(), hash[predUri], stmt->object());
}
}
// map channel type
QList<ResourcePtr> channels = model.resourcesWithType(RSS09Vocab::self()->channel());
ResourcePtr channel;
if (!channels.isEmpty())
{
channel = *(channels.begin());
model.removeStatement(channel, RDFVocab::self()->type(), RSS09Vocab::self()->channel());
model.addStatement(channel, RDFVocab::self()->type(), RSSVocab::self()->channel());
}
}
void Parser::ParserPrivate::addSequenceFor09(Model model)
{
//RDF 0.9 doesn't contain an item sequence, and the items don't have rdf:about, so add both
const QList<ResourcePtr> items = model.resourcesWithType(RSS09Vocab::self()->item());
if (items.isEmpty())
return;
const QList<ResourcePtr> channels = model.resourcesWithType(RSSVocab::self()->channel());
if (channels.isEmpty())
return;
PropertyPtr itemIndex = model.createProperty(strInternalNs + strItemIndex);
// use QMap here, not QHash. as we need the sorting functionality
QMap<uint, ResourcePtr> sorted;
foreach (const ResourcePtr &i, items)
{
QString numstr = i->property(itemIndex)->asString();
bool ok = false;
uint num = numstr.toUInt(&ok);
if (ok)
{
sorted[num] = i;
}
}
SequencePtr seq = model.createSequence();
model.addStatement(channels.first(), RSSVocab::self()->items(), seq);
foreach (const ResourcePtr &i, sorted)
{
seq->append(i);
// add rdf:about (type)
model.addStatement(i, RDFVocab::self()->type(), RSSVocab::self()->item());
//add to items sequence
model.addStatement(seq, RDFVocab::self()->li(), i);
}
}
Parser::Parser() : d(new ParserPrivate)
{
d->strInternalNs = QLatin1String("http://akregator.sf.net/libsyndication/internal#");
d->strItemIndex = QLatin1String("itemIndex");
}
Parser::~Parser()
{
delete d;
}
Parser::Parser(const Parser& other) : AbstractParser(other), d(0) {}
Parser& Parser::operator=(const Parser& /*other*/) { return *this; }
QString Parser::format() const
{
return QLatin1String("rdf");
}
} // namespace RDF
} // namespace Syndication