1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QVariant>
41#include <QStringList>
42
43#include "qanyuri_p.h"
44#include "qatomicstring_p.h"
45#include "qbuiltintypes_p.h"
46#include "qcommonsequencetypes_p.h"
47#include "qgenericsequencetype_p.h"
48#include "qinteger_p.h"
49#include "qitem_p.h"
50#include "qsequencetype_p.h"
51#include "qvariableloader_p.h"
52#include "qxmlquery_p.h"
53
54QT_BEGIN_NAMESPACE
55
56namespace QPatternist
57{
58
59 class VariantListIterator : public ListIteratorPlatform<QVariant, Item, VariantListIterator>
60 {
61 public:
62 inline VariantListIterator(const QVariantList &list) : ListIteratorPlatform<QVariant, Item, VariantListIterator>(list)
63 {
64 }
65
66 private:
67 friend class ListIteratorPlatform<QVariant, Item, VariantListIterator>;
68
69 inline Item inputToOutputItem(const QVariant &inputType) const
70 {
71 return AtomicValue::toXDM(value: inputType);
72 }
73 };
74
75 class StringListIterator : public ListIteratorPlatform<QString, Item, StringListIterator>
76 {
77 public:
78 inline StringListIterator(const QStringList &list) : ListIteratorPlatform<QString, Item, StringListIterator>(list)
79 {
80 }
81
82 private:
83 friend class ListIteratorPlatform<QString, Item, StringListIterator>;
84
85 static inline Item inputToOutputItem(const QString &inputType)
86 {
87 return AtomicString::fromValue(value: inputType);
88 }
89 };
90
91 /**
92 * Takes two DynamicContext instances, and redirects the storage of temporary trees
93 * to one of them.
94 *
95 * @since 4.5
96 */
97 class TemporaryTreesRedirectingContext : public DelegatingDynamicContext
98 {
99 public:
100 TemporaryTreesRedirectingContext(const DynamicContext::Ptr &other,
101 const DynamicContext::Ptr &modelStorage) : DelegatingDynamicContext(other)
102 , m_modelStorage(modelStorage)
103 {
104 Q_ASSERT(m_modelStorage);
105 }
106
107 void addNodeModel(const QAbstractXmlNodeModel::Ptr &nodeModel) override
108 {
109 m_modelStorage->addNodeModel(nm: nodeModel);
110 }
111
112 private:
113 const DynamicContext::Ptr m_modelStorage;
114 };
115}
116
117using namespace QPatternist;
118
119SequenceType::Ptr VariableLoader::announceExternalVariable(const QXmlName name,
120 const SequenceType::Ptr &declaredType)
121{
122 Q_UNUSED(declaredType);
123 const QVariant &variant = m_bindingHash.value(akey: name);
124
125
126 if(variant.isNull())
127 return SequenceType::Ptr();
128 else if(variant.userType() == qMetaTypeId<QIODevice *>())
129 return CommonSequenceTypes::ExactlyOneAnyURI;
130 else if(variant.userType() == qMetaTypeId<QXmlQuery>())
131 {
132 const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(v: variant));
133 return variableQuery.d->expression()->staticType();
134 }
135 else
136 {
137 return makeGenericSequenceType(itemType: AtomicValue::qtToXDMType(item: qvariant_cast<QXmlItem>(v: variant)),
138 cardinality: Cardinality::exactlyOne());
139 }
140}
141
142Item::Iterator::Ptr VariableLoader::evaluateSequence(const QXmlName name,
143 const DynamicContext::Ptr &context)
144{
145
146 const QVariant &variant = m_bindingHash.value(akey: name);
147 Q_ASSERT_X(!variant.isNull(), Q_FUNC_INFO,
148 "We assume that we have a binding.");
149
150 /* Same code as in the default clause below. */
151 if(variant.userType() == qMetaTypeId<QIODevice *>())
152 return makeSingletonIterator(item: itemForName(name));
153 else if(variant.userType() == qMetaTypeId<QXmlQuery>())
154 {
155 const QXmlQuery variableQuery(qvariant_cast<QXmlQuery>(v: variant));
156
157 return variableQuery.d->expression()->evaluateSequence(context: DynamicContext::Ptr(new TemporaryTreesRedirectingContext(variableQuery.d->dynamicContext(), context)));
158 }
159
160 const QVariant v(qvariant_cast<QXmlItem>(v: variant).toAtomicValue());
161
162 switch(v.type())
163 {
164 case QVariant::StringList:
165 return Item::Iterator::Ptr(new StringListIterator(v.toStringList()));
166 case QVariant::List:
167 return Item::Iterator::Ptr(new VariantListIterator(v.toList()));
168 default:
169 return makeSingletonIterator(item: itemForName(name));
170 }
171}
172
173Item VariableLoader::itemForName(const QXmlName &name) const
174{
175 const QVariant &variant = m_bindingHash.value(akey: name);
176
177 if(variant.userType() == qMetaTypeId<QIODevice *>())
178 return Item(AnyURI::fromValue(value: QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(code: name.localName())));
179
180 const QXmlItem item(qvariant_cast<QXmlItem>(v: variant));
181
182 if(item.isNode())
183 return Item::fromPublic(i: item);
184 else
185 {
186 const QVariant atomicValue(item.toAtomicValue());
187 /* If the atomicValue is null it means it doesn't exist in m_bindingHash, and therefore it must
188 * be a QIODevice, since Patternist guarantees to only ask for variables that announceExternalVariable()
189 * has accepted. */
190 if(atomicValue.isNull())
191 return Item(AnyURI::fromValue(value: QLatin1String("tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:") + m_namePool->stringForLocalName(code: name.localName())));
192 else
193 return AtomicValue::toXDM(value: atomicValue);
194 }
195}
196
197Item VariableLoader::evaluateSingleton(const QXmlName name,
198 const DynamicContext::Ptr &)
199{
200 return itemForName(name);
201}
202
203bool VariableLoader::isSameType(const QVariant &v1,
204 const QVariant &v2) const
205{
206 /* Are both of type QIODevice *? */
207 if(v1.userType() == qMetaTypeId<QIODevice *>() && v1.userType() == v2.userType())
208 return true;
209
210 /* Ok, we have two QXmlItems. */
211 const QXmlItem i1(qvariant_cast<QXmlItem>(v: v1));
212 const QXmlItem i2(qvariant_cast<QXmlItem>(v: v2));
213
214 if(i1.isNode())
215 {
216 Q_ASSERT(false);
217 return false;
218 }
219 else if(i2.isAtomicValue())
220 return i1.toAtomicValue().type() == i2.toAtomicValue().type();
221 else
222 {
223 /* One is an atomic, the other is a node or they are null. */
224 return false;
225 }
226}
227
228void VariableLoader::removeBinding(const QXmlName &name)
229{
230 m_bindingHash.remove(akey: name);
231}
232
233bool VariableLoader::hasBinding(const QXmlName &name) const
234{
235 return m_bindingHash.contains(akey: name)
236 || (m_previousLoader && m_previousLoader->hasBinding(name));
237}
238
239QVariant VariableLoader::valueFor(const QXmlName &name) const
240{
241 if(m_bindingHash.contains(akey: name))
242 return m_bindingHash.value(akey: name);
243 else if(m_previousLoader)
244 return m_previousLoader->valueFor(name);
245 else
246 return QVariant();
247}
248
249void VariableLoader::addBinding(const QXmlName &name,
250 const QVariant &value)
251{
252 m_bindingHash.insert(akey: name, avalue: value);
253}
254
255bool VariableLoader::invalidationRequired(const QXmlName &name,
256 const QVariant &variant) const
257{
258 return hasBinding(name) && !isSameType(v1: valueFor(name), v2: variant);
259}
260
261QT_END_NAMESPACE
262
263

source code of qtxmlpatterns/src/xmlpatterns/api/qvariableloader.cpp