Always use QStringBuilder.
[grantlee:grantlee.git] / examples / htmlapps / rssfeed.cpp
1 /*
2   This file is part of the Grantlee template system.
3
4   Copyright (c) 2011 Stephen Kelly <steveire@gmail.com>
5
6   This library is free software; you can redistribute it and/or
7   modify it under the terms of the GNU Lesser General Public
8   License as published by the Free Software Foundation; either version
9   2.1 of the Licence, or (at your option) any later version.
10
11   This library is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with this library.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "rssfeed.h"
22
23 #include <grantlee_templates.h>
24
25
26 #include <QtCore/QBuffer>
27 #include <QtCore/QFile>
28 #include <QtCore/QDebug>
29 #include <QtCore/QEventLoop>
30 #include <QtNetwork/QNetworkAccessManager>
31 #include <QtNetwork/QNetworkRequest>
32 #include <QtNetwork/QNetworkReply>
33 #include <QXmlQuery>
34 #include <QXmlResultItems>
35 #include <QAbstractXmlNodeModel>
36 #include <QXmlNodeModelIndex>
37
38 Q_DECLARE_METATYPE(QXmlQuery)
39
40 RssFeedNodeFactory::RssFeedNodeFactory(QObject* parent)
41   : Grantlee::AbstractNodeFactory(parent)
42 {
43
44 }
45
46 Grantlee::Node* RssFeedNodeFactory::getNode(const QString& tagContent, Grantlee::Parser* p) const
47 {
48   QStringList expr = smartSplit(tagContent);
49   Grantlee::FilterExpression url(expr.at(1), p);
50   Grantlee::FilterExpression query(expr.at(2), p);
51
52   RssFeedNode *n = new RssFeedNode(url, query);
53
54   QList<Grantlee::Node*> nodes = p->parse(n, "endrssfeed");
55   p->takeNextToken();
56
57   n->setChildNodes(nodes);
58
59   return n;
60 }
61
62 RssFeedNode::RssFeedNode(const Grantlee::FilterExpression& url, const Grantlee::FilterExpression& query, QObject* parent)
63   : Grantlee::Node(parent), m_url(url), m_query(query)
64 {
65
66 }
67
68 void RssFeedNode::setChildNodes(QList< Grantlee::Node* > childNodes)
69 {
70   m_childNodes = childNodes;
71 }
72
73 void RssFeedNode::render(Grantlee::OutputStream* stream, Grantlee::Context* c) const
74 {
75   QNetworkAccessManager *mgr = new QNetworkAccessManager(this);
76   QUrl url(Grantlee::getSafeString(m_url.resolve(c)));
77   QNetworkReply *reply = mgr->get(QNetworkRequest(url));
78   QEventLoop eLoop;
79   connect( mgr, SIGNAL( finished( QNetworkReply * ) ), &eLoop, SLOT( quit() ) );
80   eLoop.exec( QEventLoop::ExcludeUserInputEvents );
81
82   c->push();
83   foreach(Grantlee::Node *n, m_childNodes) {
84     if (!n->inherits(XmlNamespaceNode::staticMetaObject.className()))
85       continue;
86     Grantlee::OutputStream _dummy;
87     n->render(&_dummy, c);
88   }
89
90   QXmlQuery query;
91   QByteArray ba = reply->readAll();
92
93   QBuffer buffer;
94   buffer.setData(ba);
95   buffer.open(QIODevice::ReadOnly);
96   query.bindVariable("inputDocument", &buffer);
97   QString ns;
98   QHash<QString, QVariant> h = c->lookup("_ns").toHash();
99   QHash<QString, QVariant>::const_iterator it = h.constBegin();
100   const QHash<QString, QVariant>::const_iterator end = h.constEnd();
101   for ( ; it != end; ++it ) {
102     if (it.key().isEmpty()) {
103       ns += QLatin1Literal( "declare default element namespace " ) + QLatin1Literal( " \"" ) + it.value().toString() + QLatin1Literal( "\";\n" );
104     } else {
105       ns += QLatin1Literal( "declare namespace " ) + it.key() + QLatin1Literal( " = \"" ) + it.value().toString() + QLatin1Literal( "\";\n" );
106     }
107   }
108   query.setQuery(ns + "doc($inputDocument)" + Grantlee::getSafeString(m_query.resolve(c)).get());
109
110   QXmlResultItems result;
111   query.evaluateTo(&result);
112
113   QXmlItem item(result.next());
114   int count = 0;
115   while (!item.isNull()) {
116       if (count++ > 20)
117         break;
118       query.setFocus(item);
119       c->push();
120       foreach(Grantlee::Node *n, m_childNodes) {
121         if (n->inherits(XmlNamespaceNode::staticMetaObject.className()))
122           continue;
123         c->insert("_q", QVariant::fromValue(query));
124         n->render(stream, c);
125       }
126       c->pop();
127       item = result.next();
128   }
129   c->pop();
130 }
131
132 XmlRoleNodeFactory::XmlRoleNodeFactory(QObject* parent)
133 {
134
135 }
136
137 Grantlee::Node* XmlRoleNodeFactory::getNode(const QString &tagContent, Grantlee::Parser *p) const
138 {
139   QStringList expr = smartSplit(tagContent);
140   Grantlee::FilterExpression query(expr.at(1), p);
141   return new XmlRoleNode(query);
142 }
143
144 XmlRoleNode::XmlRoleNode(const Grantlee::FilterExpression &query, QObject* parent)
145   : m_query(query), m_count(0)
146 {
147
148 }
149
150 static QString unescape(const QString &_input)
151 {
152   QString input = _input;
153   input.replace("&lt;", "<");
154   input.replace("&gt;", ">");
155   input.replace("&quot;", "\"");
156   input.replace("&amp;", "&");
157   return input;
158 }
159
160 void XmlRoleNode::render(Grantlee::OutputStream *stream, Grantlee::Context *c) const
161 {
162   QXmlQuery q = c->lookup("_q").value<QXmlQuery>();
163   QHash<QString, QVariant> h = c->lookup("_ns").toHash();
164   QString ns;
165   QHash<QString, QVariant>::const_iterator it = h.constBegin();
166   const QHash<QString, QVariant>::const_iterator end = h.constEnd();
167   for ( ; it != end; ++it ) {
168     if (it.key().isEmpty()) {
169       ns += QLatin1Literal( "declare default element namespace " ) + QLatin1Literal( " \"" ) + it.value().toString() + QLatin1Literal( "\";\n" );
170     } else {
171       ns += QLatin1Literal( "declare namespace " ) + it.key() + QLatin1Literal( " = \"" ) + it.value().toString() + QLatin1Literal( "\";\n" );
172     }
173   }
174   q.setQuery(ns + Grantlee::getSafeString(m_query.resolve(c)));
175   QString s;
176   q.evaluateTo(&s);
177   ( *stream ) << unescape(s);
178 }
179
180 XmlNamespaceNodeFactory::XmlNamespaceNodeFactory(QObject* parent)
181 {
182
183 }
184
185 Grantlee::Node* XmlNamespaceNodeFactory::getNode(const QString &tagContent, Grantlee::Parser *p) const
186 {
187   QStringList expr = smartSplit(tagContent);
188   Grantlee::FilterExpression query(expr.at(1), p);
189   QString name;
190   if (expr.size() == 4)
191     name = expr.at(3);
192   return new XmlNamespaceNode(query, name);
193 }
194
195 XmlNamespaceNode::XmlNamespaceNode(const Grantlee::FilterExpression &query, const QString &name, QObject* parent)
196   : m_query(query), m_name(name)
197 {
198
199 }
200
201 void XmlNamespaceNode::render(Grantlee::OutputStream *stream, Grantlee::Context *c) const
202 {
203   QString q = Grantlee::getSafeString(m_query.resolve(c));
204   QHash<QString, QVariant> h = c->lookup("_ns").toHash();
205   h.insert(m_name, q);
206   c->insert("_ns", h);
207 }
208
209 QVariant ResizeFilter::doFilter(const QVariant& input, const QVariant& argument, bool autoescape) const
210 {
211   QString url = Grantlee::getSafeString(input);
212   url.replace("_s", "_z");
213   return url;
214 }
215