File indexing completed on 2024-12-22 03:46:51

0001 /*
0002   This file is part of the KTextTemplate library
0003 
0004   SPDX-FileCopyrightText: 2011 Stephen Kelly <steveire@gmail.com>
0005 
0006   SPDX-License-Identifier: LGPL-2.1-or-later
0007 
0008 */
0009 
0010 #include "rssfeed.h"
0011 
0012 #include <KTextTemplate/Util>
0013 
0014 #include <QAbstractXmlNodeModel>
0015 #include <QBuffer>
0016 #include <QDebug>
0017 #include <QEventLoop>
0018 #include <QFile>
0019 #include <QNetworkAccessManager>
0020 #include <QNetworkReply>
0021 #include <QNetworkRequest>
0022 #include <QXmlNodeModelIndex>
0023 #include <QXmlQuery>
0024 #include <QXmlResultItems>
0025 
0026 Q_DECLARE_METATYPE(QXmlQuery)
0027 
0028 RssFeedNodeFactory::RssFeedNodeFactory(QObject *parent)
0029     : KTextTemplate::AbstractNodeFactory(parent)
0030 {
0031 }
0032 
0033 KTextTemplate::Node *RssFeedNodeFactory::getNode(const QString &tagContent, KTextTemplate::Parser *p) const
0034 {
0035     QStringList expr = smartSplit(tagContent);
0036     KTextTemplate::FilterExpression url(expr.at(1), p);
0037     KTextTemplate::FilterExpression query(expr.at(2), p);
0038 
0039     RssFeedNode *n = new RssFeedNode(url, query);
0040 
0041     QList<KTextTemplate::Node *> nodes = p->parse(n, "endrssfeed");
0042     p->takeNextToken();
0043 
0044     n->setChildNodes(nodes);
0045 
0046     return n;
0047 }
0048 
0049 RssFeedNode::RssFeedNode(const KTextTemplate::FilterExpression &url, const KTextTemplate::FilterExpression &query, QObject *parent)
0050     : KTextTemplate::Node(parent)
0051     , m_url(url)
0052     , m_query(query)
0053 {
0054 }
0055 
0056 void RssFeedNode::setChildNodes(QList<KTextTemplate::Node *> childNodes)
0057 {
0058     m_childNodes = childNodes;
0059 }
0060 
0061 void RssFeedNode::render(KTextTemplate::OutputStream *stream, KTextTemplate::Context *c) const
0062 {
0063     QNetworkAccessManager *mgr = new QNetworkAccessManager(const_cast<RssFeedNode *>(this));
0064     QUrl url(KTextTemplate::getSafeString(m_url.resolve(c)));
0065     QNetworkReply *reply = mgr->get(QNetworkRequest(url));
0066     QEventLoop eLoop;
0067     connect(mgr, SIGNAL(finished(QNetworkReply *)), &eLoop, SLOT(quit()));
0068     eLoop.exec(QEventLoop::ExcludeUserInputEvents);
0069 
0070     c->push();
0071     foreach (KTextTemplate::Node *n, m_childNodes) {
0072         if (!n->inherits(XmlNamespaceNode::staticMetaObject.className()))
0073             continue;
0074         KTextTemplate::OutputStream _dummy;
0075         n->render(&_dummy, c);
0076     }
0077 
0078     QXmlQuery query;
0079     QByteArray ba = reply->readAll();
0080 
0081     QBuffer buffer;
0082     buffer.setData(ba);
0083     buffer.open(QIODevice::ReadOnly);
0084     query.bindVariable("inputDocument", &buffer);
0085     QString ns;
0086     QHash<QString, QVariant> h = c->lookup("_ns").toHash();
0087     QHash<QString, QVariant>::const_iterator it = h.constBegin();
0088     const QHash<QString, QVariant>::const_iterator end = h.constEnd();
0089     for (; it != end; ++it) {
0090         if (it.key().isEmpty()) {
0091             ns += QStringLiteral("declare default element namespace ") + QLatin1String(" \"") + it.value().toString() + QLatin1String("\";\n");
0092         } else {
0093             ns += QStringLiteral("declare namespace ") + it.key() + QLatin1String(" = \"") + it.value().toString() + QLatin1String("\";\n");
0094         }
0095     }
0096     query.setQuery(ns + "doc($inputDocument)" + KTextTemplate::getSafeString(m_query.resolve(c)).get());
0097 
0098     QXmlResultItems result;
0099     query.evaluateTo(&result);
0100 
0101     QXmlItem item(result.next());
0102     int count = 0;
0103     while (!item.isNull()) {
0104         if (count++ > 20)
0105             break;
0106         query.setFocus(item);
0107         c->push();
0108         foreach (KTextTemplate::Node *n, m_childNodes) {
0109             if (n->inherits(XmlNamespaceNode::staticMetaObject.className()))
0110                 continue;
0111             c->insert("_q", QVariant::fromValue(query));
0112             n->render(stream, c);
0113         }
0114         c->pop();
0115         item = result.next();
0116     }
0117     c->pop();
0118 }
0119 
0120 XmlRoleNodeFactory::XmlRoleNodeFactory(QObject *parent)
0121 {
0122 }
0123 
0124 KTextTemplate::Node *XmlRoleNodeFactory::getNode(const QString &tagContent, KTextTemplate::Parser *p) const
0125 {
0126     QStringList expr = smartSplit(tagContent);
0127     KTextTemplate::FilterExpression query(expr.at(1), p);
0128     return new XmlRoleNode(query);
0129 }
0130 
0131 XmlRoleNode::XmlRoleNode(const KTextTemplate::FilterExpression &query, QObject *parent)
0132     : m_query(query)
0133     , m_count(0)
0134 {
0135 }
0136 
0137 static QString unescape(const QString &_input)
0138 {
0139     QString input = _input;
0140     input.replace("&lt;", "<");
0141     input.replace("&gt;", ">");
0142     input.replace("&quot;", "\"");
0143     input.replace("&amp;", "&");
0144     return input;
0145 }
0146 
0147 void XmlRoleNode::render(KTextTemplate::OutputStream *stream, KTextTemplate::Context *c) const
0148 {
0149     QXmlQuery q = c->lookup("_q").value<QXmlQuery>();
0150     QHash<QString, QVariant> h = c->lookup("_ns").toHash();
0151     QString ns;
0152     QHash<QString, QVariant>::const_iterator it = h.constBegin();
0153     const QHash<QString, QVariant>::const_iterator end = h.constEnd();
0154     for (; it != end; ++it) {
0155         if (it.key().isEmpty()) {
0156             ns += QStringLiteral("declare default element namespace ") + QLatin1String(" \"") + it.value().toString() + QLatin1String("\";\n");
0157         } else {
0158             ns += QStringLiteral("declare namespace ") + it.key() + QLatin1String(" = \"") + it.value().toString() + QLatin1String("\";\n");
0159         }
0160     }
0161     q.setQuery(ns + KTextTemplate::getSafeString(m_query.resolve(c)));
0162     QString s;
0163     q.evaluateTo(&s);
0164     (*stream) << unescape(s);
0165 }
0166 
0167 XmlNamespaceNodeFactory::XmlNamespaceNodeFactory(QObject *parent)
0168 {
0169 }
0170 
0171 KTextTemplate::Node *XmlNamespaceNodeFactory::getNode(const QString &tagContent, KTextTemplate::Parser *p) const
0172 {
0173     QStringList expr = smartSplit(tagContent);
0174     KTextTemplate::FilterExpression query(expr.at(1), p);
0175     QString name;
0176     if (expr.size() == 4)
0177         name = expr.at(3);
0178     return new XmlNamespaceNode(query, name);
0179 }
0180 
0181 XmlNamespaceNode::XmlNamespaceNode(const KTextTemplate::FilterExpression &query, const QString &name, QObject *parent)
0182     : m_query(query)
0183     , m_name(name)
0184 {
0185 }
0186 
0187 void XmlNamespaceNode::render(KTextTemplate::OutputStream *stream, KTextTemplate::Context *c) const
0188 {
0189     QString q = KTextTemplate::getSafeString(m_query.resolve(c));
0190     QHash<QString, QVariant> h = c->lookup("_ns").toHash();
0191     h.insert(m_name, q);
0192     c->insert("_ns", h);
0193 }
0194 
0195 QVariant ResizeFilter::doFilter(const QVariant &input, const QVariant &argument, bool autoescape) const
0196 {
0197     QString url = KTextTemplate::getSafeString(input);
0198     url.replace("_s", "_z");
0199     return url;
0200 }
0201 
0202 #include "moc_rssfeed.cpp"