1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include <QStringList>
45 #include "qanyuri_p.h"
46 #include "qboolean_p.h"
47 #include "qcommonsequencetypes_p.h"
48 #include "qcommonvalues_p.h"
49 #include "qemptysequence_p.h"
50 #include "qitemmappingiterator_p.h"
51 #include "qnodesort_p.h"
52 #include "qpatternistlocale_p.h"
53 #include "private/qxmlutils_p.h"
55 #include "qsequencegeneratingfns_p.h"
59 using namespace QPatternist;
61 IdFN::IdFN() : m_hasCreatedSorter(false)
65 Item IdFN::mapToItem(const QString &id,
66 const IDContext &context) const
68 return context.second->elementById(context.first->namePool()->allocateQName(QString(), id));
72 * @short Helper class for IdFN.
74 * StringSplitter takes an Iterator which delivers strings of this kind:
76 * "a", "b c", "%invalidNCName", " ", "d"
78 * and we deliver instead:
83 * - Remove invalid @c NCName
84 * - Split IDREFs into individual NCNames
86 * @author Frans Englich <frans.englich@nokia.com>
88 class StringSplitter : public QAbstractXmlForwardIterator<QString>
91 StringSplitter(const Item::Iterator::Ptr &source);
92 virtual QString next();
93 virtual QString current() const;
94 virtual qint64 position() const;
97 const Item::Iterator::Ptr m_source;
98 QStack<QString> m_buffer;
104 StringSplitter::StringSplitter(const Item::Iterator::Ptr &source) : m_source(source)
106 , m_sourceAtEnd(false)
109 m_buffer.push(loadNext());
112 QString StringSplitter::next()
114 /* We also check m_position, we want to load on our first run. */
115 if(!m_buffer.isEmpty())
118 m_current = m_buffer.pop();
121 else if(m_sourceAtEnd)
131 QString StringSplitter::loadNext()
133 const Item sourceNext(m_source->next());
135 if(sourceNext.isNull())
137 m_sourceAtEnd = true;
138 /* We might have strings in m_buffer, let's empty it. */
142 const QStringList candidates(sourceNext.stringValue().simplified().split(QLatin1Char(' ')));
143 const int count = candidates.length();
145 for(int i = 0; i < count; ++i)
147 const QString &at = candidates.at(i);
149 if(QXmlUtils::isNCName(at))
153 /* So, now we have populated m_buffer, let's start from the beginning. */
157 QString StringSplitter::current() const
162 qint64 StringSplitter::position() const
167 Item::Iterator::Ptr IdFN::evaluateSequence(const DynamicContext::Ptr &context) const
169 const Item::Iterator::Ptr idrefs(m_operands.first()->evaluateSequence(context));
170 const Item node(m_operands.last()->evaluateSingleton(context));
172 checkTargetNode(node.asNode(), context, ReportContext::FODC0001);
174 return makeItemMappingIterator<Item,
177 IDContext>(ConstPtr(this),
178 StringSplitter::Ptr(new StringSplitter(idrefs)),
179 qMakePair(context, node.asNode().model()));
182 Expression::Ptr IdFN::typeCheck(const StaticContext::Ptr &context,
183 const SequenceType::Ptr &reqType)
185 if(m_hasCreatedSorter)
186 return FunctionCall::typeCheck(context, reqType);
189 const Expression::Ptr newMe(new NodeSortExpression(Expression::Ptr(this)));
190 context->wrapExpressionWith(this, newMe);
191 m_hasCreatedSorter = true;
192 return newMe->typeCheck(context, reqType);
196 Item::Iterator::Ptr IdrefFN::evaluateSequence(const DynamicContext::Ptr &context) const
198 const Item::Iterator::Ptr ids(m_operands.first()->evaluateSequence(context));
200 Item mId(ids->next());
202 return CommonValues::emptyIterator;
204 const Item node(m_operands.last()->evaluateSingleton(context));
205 checkTargetNode(node.asNode(), context, ReportContext::FODC0001);
207 return CommonValues::emptyIterator; /* TODO Haven't implemented further. */
210 Item DocFN::evaluateSingleton(const DynamicContext::Ptr &context) const
212 const Item itemURI(m_operands.first()->evaluateSingleton(context));
217 /* These two lines were previously in a separate function but are now duplicated
218 * in DocAvailableFN::evaluateEBV() and DocFN::typeCheck(),
219 * as part of a workaround for solaris-cc-64. DocFN::typeCheck() is in qsequencefns.cpp
220 * as part of that workaround. */
221 const QUrl mayRela(AnyURI::toQUrl<ReportContext::FODC0005>(itemURI.stringValue(), context, this));
222 const QUrl uri(context->resolveURI(mayRela, staticBaseURI()));
224 Q_ASSERT(uri.isValid());
225 Q_ASSERT(!uri.isRelative());
227 const Item doc(context->resourceLoader()->openDocument(uri, context));
232 SequenceType::Ptr DocFN::staticType() const
237 return CommonSequenceTypes::ZeroOrOneDocumentNode;
240 bool DocAvailableFN::evaluateEBV(const DynamicContext::Ptr &context) const
242 const Item itemURI(m_operands.first()->evaluateSingleton(context));
244 /* 15.5.4 fn:doc reads: "If $uri is the empty sequence, the result is an empty sequence."
245 * Hence, we return false for the empty sequence, because this doesn't hold true:
246 * "If this function returns true, then calling fn:doc($uri) within
247 * the same execution scope must return a document node."(15.5.5 fn:doc-available) */
251 /* These two lines are duplicated in DocFN::evaluateSingleton(), as part
252 * of a workaround for solaris-cc-64. */
253 const QUrl mayRela(AnyURI::toQUrl<ReportContext::FODC0005>(itemURI.stringValue(), context, this));
254 const QUrl uri(context->resolveURI(mayRela, staticBaseURI()));
256 Q_ASSERT(!uri.isRelative());
257 return context->resourceLoader()->isDocumentAvailable(uri);
260 Item::Iterator::Ptr CollectionFN::evaluateSequence(const DynamicContext::Ptr &context) const
262 // TODO resolve with URI resolve
263 if(m_operands.isEmpty())
265 // TODO check default collection
266 context->error(QtXmlPatterns::tr("The default collection is undefined"),
267 ReportContext::FODC0002, this);
268 return CommonValues::emptyIterator;
272 const Item itemURI(m_operands.first()->evaluateSingleton(context));
276 const QUrl uri(AnyURI::toQUrl<ReportContext::FODC0004>(itemURI.stringValue(), context, this));
278 // TODO 2. Resolve against static context base URI(store base URI at compile time)
279 context->error(QtXmlPatterns::tr("%1 cannot be retrieved").arg(formatResourcePath(uri)),
280 ReportContext::FODC0004, this);
281 return CommonValues::emptyIterator;
285 /* This is out default collection currently, */
286 return CommonValues::emptyIterator;