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 "qdocumentprojector_p.h"
41
42QT_BEGIN_NAMESPACE
43
44using namespace QPatternist;
45
46DocumentProjector::DocumentProjector(const ProjectedExpression::Vector &paths,
47 QAbstractXmlReceiver *const receiver) : m_paths(paths)
48 , m_pathCount(paths.count())
49 , m_action(ProjectedExpression::Move)
50 , m_nodesInProcess(0)
51 , m_receiver(receiver)
52{
53 Q_ASSERT_X(paths.count() > 0, Q_FUNC_INFO,
54 "Using DocumentProjector with no paths is an "
55 "overhead and has also undefined behavior.");
56 Q_ASSERT(m_receiver);
57}
58
59void DocumentProjector::startElement(const QXmlName &name)
60{
61 Q_UNUSED(name);
62
63 switch(m_action)
64 {
65 case ProjectedExpression::KeepSubtree:
66 {
67 m_receiver->startElement(name);
68 Q_FALLTHROUGH();
69 }
70 case ProjectedExpression::Skip:
71 {
72 ++m_nodesInProcess;
73 return;
74 }
75 default:
76 {
77 Q_ASSERT_X(m_action == ProjectedExpression::Move, Q_FUNC_INFO,
78 "We're not supposed to receive Keep here, because "
79 "endElement() should always end that state.");
80
81 for(int i = 0; i < m_pathCount; ++i)
82 {
83 m_action = m_paths.at(i)->actionForElement(name, next&: m_paths[i]);
84
85 switch(m_action)
86 {
87 case ProjectedExpression::Keep:
88 {
89 m_action = ProjectedExpression::Keep;
90 continue;
91 }
92 case ProjectedExpression::KeepSubtree:
93 {
94 /* Ok, at least one path wanted this node. Pass it on,
95 * and exit. */
96 m_receiver->startElement(name);
97 ++m_nodesInProcess;
98 return;
99 }
100 case ProjectedExpression::Skip:
101 {
102 /* This particular path doesn't need it, but
103 * some other path might, so continue looping. */
104 continue;
105 }
106 case ProjectedExpression::Move:
107 Q_ASSERT_X(false, Q_FUNC_INFO, "The action functions can never return Move.");
108 }
109 }
110
111 ++m_nodesInProcess;
112
113 if(m_action == ProjectedExpression::Keep)
114 m_receiver->startElement(name);
115 else
116 {
117 Q_ASSERT(m_action == ProjectedExpression::Skip);
118 }
119 }
120 }
121}
122
123void DocumentProjector::endElement()
124{
125 if(m_action == ProjectedExpression::Keep)
126 {
127 Q_ASSERT(m_nodesInProcess == 1);
128
129 m_receiver->endElement();
130
131 /* We have now kept the single node, and now wants to skip
132 * all its children. */
133 m_action = ProjectedExpression::Skip;
134 m_nodesInProcess = 0;
135 }
136 else if(m_action == ProjectedExpression::KeepSubtree)
137 {
138 m_receiver->endElement();
139 --m_nodesInProcess;
140
141 if(m_nodesInProcess == 0)
142 {
143 /* We have now skipped all the children, let's do
144 * a new path analysis. */
145 m_action = ProjectedExpression::Move;
146 }
147 }
148 else
149 {
150 Q_ASSERT_X(m_action == ProjectedExpression::Skip, Q_FUNC_INFO,
151 "We're not supposed to be in a Move action here.");
152 /* We skip calling m_receiver's endElement() here since we're
153 * skipping. */
154 Q_ASSERT(m_nodesInProcess > 0);
155 --m_nodesInProcess;
156
157 if(m_nodesInProcess == 0)
158 {
159 /* Ok, we've skipped them all, let's do something
160 * new -- let's Move on to the next path! */
161 m_action = ProjectedExpression::Move;
162 }
163 }
164}
165
166void DocumentProjector::attribute(const QXmlName &name,
167 const QStringRef &value)
168{
169 Q_UNUSED(name);
170 Q_UNUSED(value);
171}
172
173void DocumentProjector::namespaceBinding(const QXmlName &nb)
174{
175 Q_UNUSED(nb);
176}
177
178void DocumentProjector::comment(const QString &value)
179{
180 Q_ASSERT_X(!value.contains(QLatin1String("--")), Q_FUNC_INFO,
181 "Invalid input; it's the caller's responsibility to ensure the input is correct.");
182 Q_UNUSED(value);
183}
184
185void DocumentProjector::characters(const QStringRef &value)
186{
187 Q_UNUSED(value);
188}
189
190void DocumentProjector::processingInstruction(const QXmlName &name,
191 const QString &value)
192{
193 Q_ASSERT_X(!value.contains(QLatin1String("?>")), Q_FUNC_INFO,
194 "Invalid input; it's the caller's responsibility to ensure the input is correct.");
195 Q_UNUSED(name);
196 Q_UNUSED(value);
197}
198
199void DocumentProjector::item(const Item &outputItem)
200{
201 Q_UNUSED(outputItem);
202}
203
204void DocumentProjector::startDocument()
205{
206}
207
208void DocumentProjector::endDocument()
209{
210}
211
212QT_END_NAMESPACE
213

source code of qtxmlpatterns/src/xmlpatterns/projection/qdocumentprojector.cpp