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 <QtDebug>
41
42#include "qaxisstep_p.h"
43#include "qcommonsequencetypes_p.h"
44#include "qcommonvalues_p.h"
45#include "qitemmappingiterator_p.h"
46#include "qsequencemappingiterator_p.h"
47#include "qpatternistlocale_p.h"
48
49#include "qapplytemplate_p.h"
50
51QT_BEGIN_NAMESPACE
52
53using namespace QPatternist;
54
55ApplyTemplate::ApplyTemplate(const TemplateMode::Ptr &mode,
56 const WithParam::Hash &withParams,
57 const TemplateMode::Ptr &defaultMode) : TemplateInvoker(withParams)
58 , m_mode(mode)
59 , m_defaultMode(defaultMode)
60{
61 Q_ASSERT_X(m_mode || m_defaultMode, Q_FUNC_INFO,
62 "Either a mode, or the default mode must be supplied.");
63}
64
65Item ApplyTemplate::mapToItem(const QXmlNodeModelIndex &node,
66 const DynamicContext::Ptr &) const
67{
68 return Item(node);
69}
70
71Item::Iterator::Ptr ApplyTemplate::mapToSequence(const Item &item,
72 const DynamicContext::Ptr &context) const
73{
74 Q_UNUSED(item);
75 return evaluateSequence(context);
76}
77
78TemplateMode::Ptr ApplyTemplate::effectiveMode(const DynamicContext::Ptr &context) const
79{
80 if(m_mode)
81 return m_mode;
82 else
83 {
84 const TemplateMode::Ptr currentMode(context->currentTemplateMode());
85
86 if(currentMode)
87 return currentMode;
88 else
89 return m_defaultMode;
90 }
91}
92
93Template::Ptr ApplyTemplate::findTemplate(const DynamicContext::Ptr &context,
94 const TemplateMode::Ptr &templateMode) const
95{
96 const int count = templateMode->templatePatterns.count();
97 Template::Ptr result;
98 /* It's redundant to initialize these values, but it suppresses false
99 * positives with GCC. */
100 PatternPriority priority = 0;
101 TemplatePattern::ID id = -1;
102
103 /* Possible optimization: detecting ambiguous rule matches could be forked off to a
104 * low prioirity thread. */
105 for(int i = 0; i < count; ++i)
106 {
107 const TemplatePattern::Ptr &candidate = templateMode->templatePatterns.at(i);
108 if(candidate->matchPattern()->evaluateEBV(context))
109 {
110 if(result)
111 {
112 if( candidate->id() != id
113 && candidate->priority() == priority
114 && candidate->templateTarget()->importPrecedence ==
115 result->importPrecedence)
116 {
117 context->error(message: QtXmlPatterns::tr(sourceText: "Ambiguous rule match."),
118 errorCode: ReportContext::XTRE0540, reflection: this);
119 }
120 else
121 break;
122 }
123 else
124 {
125 result = candidate->templateTarget();
126 priority = candidate->priority();
127 id = candidate->id();
128 }
129 }
130 }
131
132 return result;
133}
134
135Item::Iterator::Ptr ApplyTemplate::evaluateSequence(const DynamicContext::Ptr &context) const
136{
137 const TemplateMode::Ptr templateMode(effectiveMode(context));
138 const Template::Ptr &templateMatch = findTemplate(context, templateMode);
139
140 if(templateMatch)
141 return templateMatch->body->evaluateSequence(context: templateMatch->createContext(invoker: this, context, isCallTemplate: false));
142 else
143 {
144 /* None of our templates matched. Proceed with a built-in. */
145 const Item current(context->contextItem());
146 // TODO it can be an atomic value?
147 const QXmlNodeModelIndex::NodeKind kind(current.asNode().kind());
148
149 if(kind == QXmlNodeModelIndex::Element || kind == QXmlNodeModelIndex::Document)
150 {
151 pDebug() << "No template match, using builtin template for element() | document-node()";
152
153 const Item::Iterator::Ptr focusIterator(makeItemMappingIterator<Item>(mapper: ConstPtr(this),
154 source: current.asNode().iterate(axis: QXmlNodeModelIndex::AxisChild),
155 context));
156
157 const DynamicContext::Ptr focus(context->createFocus());
158 focus->setFocusIterator(focusIterator);
159 return makeSequenceMappingIterator<Item>(mapper: ConstPtr(this), source: focusIterator, context: focus);
160 }
161 return CommonValues::emptyIterator;
162 }
163}
164
165Expression::Ptr ApplyTemplate::compress(const StaticContext::Ptr &context)
166{
167 /* If we have a mode, we will never need the default mode. */
168 if(m_mode)
169 m_defaultMode.reset();
170
171 return TemplateInvoker::compress(context);
172}
173
174SequenceType::Ptr ApplyTemplate::staticType() const
175{
176 return CommonSequenceTypes::ZeroOrMoreItems;
177}
178
179ExpressionVisitorResult::Ptr ApplyTemplate::accept(const ExpressionVisitor::Ptr &visitor) const
180{
181 return visitor->visit(this);
182}
183
184Expression::Properties ApplyTemplate::properties() const
185{
186 return RequiresFocus | DisableElimination;
187}
188
189bool ApplyTemplate::configureRecursion(const CallTargetDescription::Ptr &sign)
190{
191 Q_ASSERT_X(false, Q_FUNC_INFO, "We're not expected to be called.");
192 Q_UNUSED(sign);
193 return false;
194}
195
196Expression::Ptr ApplyTemplate::body() const
197{
198 Q_ASSERT_X(false, Q_FUNC_INFO, "We're not expected to be called.");
199 return Expression::Ptr();
200}
201
202CallTargetDescription::Ptr ApplyTemplate::callTargetDescription() const
203{
204 Q_ASSERT_X(false, Q_FUNC_INFO, "We're not expected to be called.");
205 return CallTargetDescription::Ptr();
206}
207
208QT_END_NAMESPACE
209

source code of qtxmlpatterns/src/xmlpatterns/expr/qapplytemplate.cpp