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("<", "<"); 0141 input.replace(">", ">"); 0142 input.replace(""", "\""); 0143 input.replace("&", "&"); 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"