1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation ([email protected])
|
---|
6 | **
|
---|
7 | ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at [email protected].
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include <QStringList>
|
---|
43 |
|
---|
44 | #include "qbuiltintypes_p.h"
|
---|
45 | #include "qcommonnamespaces_p.h"
|
---|
46 | #include "qquerytransformparser_p.h"
|
---|
47 | #include "qxquerytokenizer_p.h"
|
---|
48 | #include "qpatternistlocale_p.h"
|
---|
49 |
|
---|
50 | #include "qxslttokenizer_p.h"
|
---|
51 |
|
---|
52 | QT_BEGIN_NAMESPACE
|
---|
53 |
|
---|
54 | using namespace QPatternist;
|
---|
55 |
|
---|
56 | Tokenizer::Token SingleTokenContainer::nextToken(YYLTYPE *const location)
|
---|
57 | {
|
---|
58 | if(m_hasDelivered)
|
---|
59 | return Tokenizer::Token(END_OF_FILE);
|
---|
60 | else
|
---|
61 | {
|
---|
62 | *location = m_location;
|
---|
63 | m_hasDelivered = true;
|
---|
64 | return m_token;
|
---|
65 | }
|
---|
66 | }
|
---|
67 |
|
---|
68 | XSLTTokenizer::XSLTTokenizer(QIODevice *const queryDevice,
|
---|
69 | const QUrl &location,
|
---|
70 | const ReportContext::Ptr &context,
|
---|
71 | const NamePool::Ptr &np) : Tokenizer(location)
|
---|
72 | , MaintainingReader<XSLTTokenLookup>(createElementDescriptions(), createStandardAttributes(), context, queryDevice)
|
---|
73 | , m_location(location)
|
---|
74 | , m_namePool(np)
|
---|
75 | /* We initialize after all name constants. */
|
---|
76 | , m_validationAlternatives(createValidationAlternatives())
|
---|
77 | , m_parseInfo(0)
|
---|
78 | {
|
---|
79 | Q_ASSERT(m_namePool);
|
---|
80 |
|
---|
81 | pushState(OutsideDocumentElement);
|
---|
82 | }
|
---|
83 |
|
---|
84 | bool XSLTTokenizer::isAnyAttributeAllowed() const
|
---|
85 | {
|
---|
86 | return m_processingMode.top() == ForwardCompatible;
|
---|
87 | }
|
---|
88 |
|
---|
89 | void XSLTTokenizer::setParserContext(const ParserContext::Ptr &parseInfo)
|
---|
90 | {
|
---|
91 | m_parseInfo = parseInfo;
|
---|
92 | }
|
---|
93 |
|
---|
94 | void XSLTTokenizer::validateElement() const
|
---|
95 | {
|
---|
96 | MaintainingReader<XSLTTokenLookup>::validateElement(currentElementName());
|
---|
97 | }
|
---|
98 |
|
---|
99 | QSet<XSLTTokenizer::NodeName> XSLTTokenizer::createStandardAttributes()
|
---|
100 | {
|
---|
101 | QSet<NodeName> retval;
|
---|
102 | enum
|
---|
103 | {
|
---|
104 | ReservedForAttributes = 6
|
---|
105 | };
|
---|
106 |
|
---|
107 | retval.reserve(6);
|
---|
108 |
|
---|
109 | retval.insert(DefaultCollation);
|
---|
110 | retval.insert(ExcludeResultPrefixes);
|
---|
111 | retval.insert(ExtensionElementPrefixes);
|
---|
112 | retval.insert(UseWhen);
|
---|
113 | retval.insert(Version);
|
---|
114 | retval.insert(XpathDefaultNamespace);
|
---|
115 |
|
---|
116 | Q_ASSERT(retval.count() == ReservedForAttributes);
|
---|
117 |
|
---|
118 | return retval;
|
---|
119 | }
|
---|
120 |
|
---|
121 | ElementDescription<XSLTTokenLookup>::Hash XSLTTokenizer::createElementDescriptions()
|
---|
122 | {
|
---|
123 | ElementDescription<XSLTTokenLookup>::Hash result;
|
---|
124 | enum
|
---|
125 | {
|
---|
126 | ReservedForElements = 40
|
---|
127 | };
|
---|
128 | result.reserve(ReservedForElements);
|
---|
129 |
|
---|
130 | /* xsl:apply-templates */
|
---|
131 | {
|
---|
132 | ElementDescription<XSLTTokenLookup> &e = result[ApplyTemplates];
|
---|
133 | e.optionalAttributes.insert(Select);
|
---|
134 | e.optionalAttributes.insert(Mode);
|
---|
135 | }
|
---|
136 |
|
---|
137 | /* xsl:template */
|
---|
138 | {
|
---|
139 | ElementDescription<XSLTTokenLookup> &e = result[Template];
|
---|
140 | e.optionalAttributes.insert(Match);
|
---|
141 | e.optionalAttributes.insert(Name);
|
---|
142 | e.optionalAttributes.insert(Mode);
|
---|
143 | e.optionalAttributes.insert(Priority);
|
---|
144 | e.optionalAttributes.insert(As);
|
---|
145 | }
|
---|
146 |
|
---|
147 | /* xsl:text, xsl:choose and xsl:otherwise */
|
---|
148 | {
|
---|
149 | ElementDescription<XSLTTokenLookup> &e = result[Text];
|
---|
150 | result.insert(Choose, e);
|
---|
151 | result.insert(Otherwise, e);
|
---|
152 | }
|
---|
153 |
|
---|
154 | /* xsl:stylesheet */
|
---|
155 | {
|
---|
156 | ElementDescription<XSLTTokenLookup> &e = result[Stylesheet];
|
---|
157 |
|
---|
158 | e.requiredAttributes.insert(Version);
|
---|
159 |
|
---|
160 | e.optionalAttributes.insert(Id);
|
---|
161 | e.optionalAttributes.insert(ExtensionElementPrefixes);
|
---|
162 | e.optionalAttributes.insert(ExcludeResultPrefixes);
|
---|
163 | e.optionalAttributes.insert(XpathDefaultNamespace);
|
---|
164 | e.optionalAttributes.insert(DefaultValidation);
|
---|
165 | e.optionalAttributes.insert(DefaultCollation);
|
---|
166 | e.optionalAttributes.insert(InputTypeAnnotations);
|
---|
167 | }
|
---|
168 |
|
---|
169 | /* xsl:transform */
|
---|
170 | {
|
---|
171 | result[Transform] = result[Stylesheet];
|
---|
172 | }
|
---|
173 |
|
---|
174 | /* xsl:value-of */
|
---|
175 | {
|
---|
176 | ElementDescription<XSLTTokenLookup> &e = result[ValueOf];
|
---|
177 | e.optionalAttributes.insert(Separator);
|
---|
178 | e.optionalAttributes.insert(Select);
|
---|
179 | }
|
---|
180 |
|
---|
181 | /* xsl:variable */
|
---|
182 | {
|
---|
183 | ElementDescription<XSLTTokenLookup> &e = result[Variable];
|
---|
184 |
|
---|
185 | e.requiredAttributes.insert(Name);
|
---|
186 |
|
---|
187 | e.optionalAttributes.insert(Select);
|
---|
188 | e.optionalAttributes.insert(As);
|
---|
189 | }
|
---|
190 |
|
---|
191 | /* xsl:when & xsl:if */
|
---|
192 | {
|
---|
193 | ElementDescription<XSLTTokenLookup> &e = result[When];
|
---|
194 |
|
---|
195 | e.requiredAttributes.insert(Test);
|
---|
196 |
|
---|
197 | result.insert(If, e);
|
---|
198 | }
|
---|
199 |
|
---|
200 | /* xsl:sequence, xsl:for-each */
|
---|
201 | {
|
---|
202 | ElementDescription<XSLTTokenLookup> &e = result[Sequence];
|
---|
203 |
|
---|
204 | e.requiredAttributes.insert(Select);
|
---|
205 |
|
---|
206 | result.insert(ForEach, e);
|
---|
207 | }
|
---|
208 |
|
---|
209 | /* xsl:comment */
|
---|
210 | {
|
---|
211 | ElementDescription<XSLTTokenLookup> &e = result[XSLTTokenLookup::Comment];
|
---|
212 |
|
---|
213 | e.optionalAttributes.insert(Select);
|
---|
214 | }
|
---|
215 |
|
---|
216 | /* xsl:processing-instruction */
|
---|
217 | {
|
---|
218 | ElementDescription<XSLTTokenLookup> &e = result[XSLTTokenLookup::ProcessingInstruction];
|
---|
219 |
|
---|
220 | e.requiredAttributes.insert(Name);
|
---|
221 | e.optionalAttributes.insert(Select);
|
---|
222 | }
|
---|
223 |
|
---|
224 | /* xsl:document */
|
---|
225 | {
|
---|
226 | ElementDescription<XSLTTokenLookup> &e = result[Document];
|
---|
227 |
|
---|
228 | e.optionalAttributes.insert(Validation);
|
---|
229 | e.optionalAttributes.insert(Type);
|
---|
230 | }
|
---|
231 |
|
---|
232 | /* xsl:element */
|
---|
233 | {
|
---|
234 | ElementDescription<XSLTTokenLookup> &e = result[Element];
|
---|
235 |
|
---|
236 | e.requiredAttributes.insert(Name);
|
---|
237 |
|
---|
238 | e.optionalAttributes.insert(Namespace);
|
---|
239 | e.optionalAttributes.insert(InheritNamespaces);
|
---|
240 | e.optionalAttributes.insert(UseAttributeSets);
|
---|
241 | e.optionalAttributes.insert(Validation);
|
---|
242 | e.optionalAttributes.insert(Type);
|
---|
243 | }
|
---|
244 |
|
---|
245 | /* xsl:attribute */
|
---|
246 | {
|
---|
247 | ElementDescription<XSLTTokenLookup> &e = result[Attribute];
|
---|
248 |
|
---|
249 | e.requiredAttributes.insert(Name);
|
---|
250 |
|
---|
251 | e.optionalAttributes.insert(Namespace);
|
---|
252 | e.optionalAttributes.insert(Select);
|
---|
253 | e.optionalAttributes.insert(Separator);
|
---|
254 | e.optionalAttributes.insert(Validation);
|
---|
255 | e.optionalAttributes.insert(Type);
|
---|
256 | }
|
---|
257 |
|
---|
258 | /* xsl:function */
|
---|
259 | {
|
---|
260 | ElementDescription<XSLTTokenLookup> &e = result[Function];
|
---|
261 |
|
---|
262 | e.requiredAttributes.insert(Name);
|
---|
263 |
|
---|
264 | e.optionalAttributes.insert(As);
|
---|
265 | e.optionalAttributes.insert(Override);
|
---|
266 | }
|
---|
267 |
|
---|
268 | /* xsl:param */
|
---|
269 | {
|
---|
270 | ElementDescription<XSLTTokenLookup> &e = result[Param];
|
---|
271 |
|
---|
272 | e.requiredAttributes.insert(Name);
|
---|
273 |
|
---|
274 | e.optionalAttributes.insert(Select);
|
---|
275 | e.optionalAttributes.insert(As);
|
---|
276 | e.optionalAttributes.insert(Required);
|
---|
277 | e.optionalAttributes.insert(Tunnel);
|
---|
278 | }
|
---|
279 |
|
---|
280 | /* xsl:namespace */
|
---|
281 | {
|
---|
282 | ElementDescription<XSLTTokenLookup> &e = result[Namespace];
|
---|
283 |
|
---|
284 | e.requiredAttributes.insert(Name);
|
---|
285 | e.optionalAttributes.insert(Select);
|
---|
286 | }
|
---|
287 |
|
---|
288 | /* xsl:call-template */
|
---|
289 | {
|
---|
290 | ElementDescription<XSLTTokenLookup> &e = result[CallTemplate];
|
---|
291 | e.requiredAttributes.insert(Name);
|
---|
292 | }
|
---|
293 |
|
---|
294 | /* xsl:perform-sort */
|
---|
295 | {
|
---|
296 | ElementDescription<XSLTTokenLookup> &e = result[PerformSort];
|
---|
297 | e.requiredAttributes.insert(Select);
|
---|
298 | }
|
---|
299 |
|
---|
300 | /* xsl:sort */
|
---|
301 | {
|
---|
302 | ElementDescription<XSLTTokenLookup> &e = result[Sort];
|
---|
303 |
|
---|
304 | e.optionalAttributes.reserve(7);
|
---|
305 | e.optionalAttributes.insert(Select);
|
---|
306 | e.optionalAttributes.insert(Lang);
|
---|
307 | e.optionalAttributes.insert(Order);
|
---|
308 | e.optionalAttributes.insert(Collation);
|
---|
309 | e.optionalAttributes.insert(Stable);
|
---|
310 | e.optionalAttributes.insert(CaseOrder);
|
---|
311 | e.optionalAttributes.insert(DataType);
|
---|
312 | }
|
---|
313 |
|
---|
314 | /* xsl:import-schema */
|
---|
315 | {
|
---|
316 | ElementDescription<XSLTTokenLookup> &e = result[ImportSchema];
|
---|
317 |
|
---|
318 | e.optionalAttributes.reserve(2);
|
---|
319 | e.optionalAttributes.insert(Namespace);
|
---|
320 | e.optionalAttributes.insert(SchemaLocation);
|
---|
321 | }
|
---|
322 |
|
---|
323 | /* xsl:message */
|
---|
324 | {
|
---|
325 | ElementDescription<XSLTTokenLookup> &e = result[Message];
|
---|
326 |
|
---|
327 | e.optionalAttributes.reserve(2);
|
---|
328 | e.optionalAttributes.insert(Select);
|
---|
329 | e.optionalAttributes.insert(Terminate);
|
---|
330 | }
|
---|
331 |
|
---|
332 | /* xsl:copy-of */
|
---|
333 | {
|
---|
334 | ElementDescription<XSLTTokenLookup> &e = result[CopyOf];
|
---|
335 |
|
---|
336 | e.requiredAttributes.insert(Select);
|
---|
337 |
|
---|
338 | e.optionalAttributes.reserve(2);
|
---|
339 | e.optionalAttributes.insert(CopyNamespaces);
|
---|
340 | e.optionalAttributes.insert(Type);
|
---|
341 | e.optionalAttributes.insert(Validation);
|
---|
342 | }
|
---|
343 |
|
---|
344 | /* xsl:copy */
|
---|
345 | {
|
---|
346 | ElementDescription<XSLTTokenLookup> &e = result[Copy];
|
---|
347 |
|
---|
348 | e.optionalAttributes.reserve(5);
|
---|
349 | e.optionalAttributes.insert(CopyNamespaces);
|
---|
350 | e.optionalAttributes.insert(InheritNamespaces);
|
---|
351 | e.optionalAttributes.insert(UseAttributeSets);
|
---|
352 | e.optionalAttributes.insert(Type);
|
---|
353 | e.optionalAttributes.insert(Validation);
|
---|
354 | }
|
---|
355 |
|
---|
356 | /* xsl:output */
|
---|
357 | {
|
---|
358 | ElementDescription<XSLTTokenLookup> &e = result[Output];
|
---|
359 |
|
---|
360 | e.optionalAttributes.reserve(17);
|
---|
361 | e.optionalAttributes.insert(Name);
|
---|
362 | e.optionalAttributes.insert(Method);
|
---|
363 | e.optionalAttributes.insert(ByteOrderMark);
|
---|
364 | e.optionalAttributes.insert(CdataSectionElements);
|
---|
365 | e.optionalAttributes.insert(DoctypePublic);
|
---|
366 | e.optionalAttributes.insert(DoctypeSystem);
|
---|
367 | e.optionalAttributes.insert(Encoding);
|
---|
368 | e.optionalAttributes.insert(EscapeUriAttributes);
|
---|
369 | e.optionalAttributes.insert(IncludeContentType);
|
---|
370 | e.optionalAttributes.insert(Indent);
|
---|
371 | e.optionalAttributes.insert(MediaType);
|
---|
372 | e.optionalAttributes.insert(NormalizationForm);
|
---|
373 | e.optionalAttributes.insert(OmitXmlDeclaration);
|
---|
374 | e.optionalAttributes.insert(Standalone);
|
---|
375 | e.optionalAttributes.insert(UndeclarePrefixes);
|
---|
376 | e.optionalAttributes.insert(UseCharacterMaps);
|
---|
377 | e.optionalAttributes.insert(Version);
|
---|
378 | }
|
---|
379 |
|
---|
380 | /* xsl:attribute-set */
|
---|
381 | {
|
---|
382 | ElementDescription<XSLTTokenLookup> &e = result[AttributeSet];
|
---|
383 |
|
---|
384 | e.requiredAttributes.insert(Name);
|
---|
385 | e.optionalAttributes.insert(UseAttributeSets);
|
---|
386 | }
|
---|
387 |
|
---|
388 | /* xsl:include and xsl:import. */
|
---|
389 | {
|
---|
390 | ElementDescription<XSLTTokenLookup> &e = result[Include];
|
---|
391 | e.requiredAttributes.insert(Href);
|
---|
392 | result[Import] = e;
|
---|
393 | }
|
---|
394 |
|
---|
395 | /* xsl:with-param */
|
---|
396 | {
|
---|
397 | ElementDescription<XSLTTokenLookup> &e = result[WithParam];
|
---|
398 | e.requiredAttributes.insert(Name);
|
---|
399 |
|
---|
400 | e.optionalAttributes.insert(Select);
|
---|
401 | e.optionalAttributes.insert(As);
|
---|
402 | e.optionalAttributes.insert(Tunnel);
|
---|
403 | }
|
---|
404 |
|
---|
405 | /* xsl:strip-space */
|
---|
406 | {
|
---|
407 | ElementDescription<XSLTTokenLookup> &e = result[StripSpace];
|
---|
408 | e.requiredAttributes.insert(Elements);
|
---|
409 |
|
---|
410 | result.insert(PreserveSpace, e);
|
---|
411 | }
|
---|
412 |
|
---|
413 | /* xsl:result-document */
|
---|
414 | {
|
---|
415 | ElementDescription<XSLTTokenLookup> &e = result[ResultDocument];
|
---|
416 |
|
---|
417 | e.optionalAttributes.insert(ByteOrderMark);
|
---|
418 | e.optionalAttributes.insert(CdataSectionElements);
|
---|
419 | e.optionalAttributes.insert(DoctypePublic);
|
---|
420 | e.optionalAttributes.insert(DoctypeSystem);
|
---|
421 | e.optionalAttributes.insert(Encoding);
|
---|
422 | e.optionalAttributes.insert(EscapeUriAttributes);
|
---|
423 | e.optionalAttributes.insert(Format);
|
---|
424 | e.optionalAttributes.insert(Href);
|
---|
425 | e.optionalAttributes.insert(IncludeContentType);
|
---|
426 | e.optionalAttributes.insert(Indent);
|
---|
427 | e.optionalAttributes.insert(MediaType);
|
---|
428 | e.optionalAttributes.insert(Method);
|
---|
429 | e.optionalAttributes.insert(NormalizationForm);
|
---|
430 | e.optionalAttributes.insert(OmitXmlDeclaration);
|
---|
431 | e.optionalAttributes.insert(OutputVersion);
|
---|
432 | e.optionalAttributes.insert(Standalone);
|
---|
433 | e.optionalAttributes.insert(Type);
|
---|
434 | e.optionalAttributes.insert(UndeclarePrefixes);
|
---|
435 | e.optionalAttributes.insert(UseCharacterMaps);
|
---|
436 | e.optionalAttributes.insert(Validation);
|
---|
437 | }
|
---|
438 |
|
---|
439 | /* xsl:key */
|
---|
440 | {
|
---|
441 | ElementDescription<XSLTTokenLookup> &e = result[Key];
|
---|
442 |
|
---|
443 | e.requiredAttributes.insert(Name);
|
---|
444 | e.requiredAttributes.insert(Match);
|
---|
445 |
|
---|
446 | e.optionalAttributes.insert(Use);
|
---|
447 | e.optionalAttributes.insert(Collation);
|
---|
448 | }
|
---|
449 |
|
---|
450 | /* xsl:analyze-string */
|
---|
451 | {
|
---|
452 | ElementDescription<XSLTTokenLookup> &e = result[AnalyzeString];
|
---|
453 |
|
---|
454 | e.requiredAttributes.insert(Select);
|
---|
455 | e.requiredAttributes.insert(Regex);
|
---|
456 |
|
---|
457 | e.optionalAttributes.insert(Flags);
|
---|
458 | }
|
---|
459 |
|
---|
460 | /* xsl:matching-substring */
|
---|
461 | {
|
---|
462 | /* We insert a default constructed value. */
|
---|
463 | result[MatchingSubstring];
|
---|
464 | }
|
---|
465 |
|
---|
466 | /* xsl:non-matching-substring */
|
---|
467 | {
|
---|
468 | /* We insert a default constructed value. */
|
---|
469 | result[NonMatchingSubstring];
|
---|
470 | }
|
---|
471 |
|
---|
472 | Q_ASSERT(result.count() == ReservedForElements);
|
---|
473 |
|
---|
474 | return result;
|
---|
475 | }
|
---|
476 |
|
---|
477 | QHash<QString, int> XSLTTokenizer::createValidationAlternatives()
|
---|
478 | {
|
---|
479 | QHash<QString, int> retval;
|
---|
480 |
|
---|
481 | retval.insert(QLatin1String("preserve"), 0);
|
---|
482 | retval.insert(QLatin1String("strip"), 1);
|
---|
483 | retval.insert(QLatin1String("strict"), 2);
|
---|
484 | retval.insert(QLatin1String("lax"), 3);
|
---|
485 |
|
---|
486 | return retval;
|
---|
487 | }
|
---|
488 |
|
---|
489 | bool XSLTTokenizer::whitespaceToSkip() const
|
---|
490 | {
|
---|
491 | return m_stripWhitespace.top() && isWhitespace();
|
---|
492 | }
|
---|
493 |
|
---|
494 | void XSLTTokenizer::unexpectedContent(const ReportContext::ErrorCode code) const
|
---|
495 | {
|
---|
496 | QString message;
|
---|
497 |
|
---|
498 | ReportContext::ErrorCode effectiveCode = code;
|
---|
499 |
|
---|
500 | switch(tokenType())
|
---|
501 | {
|
---|
502 | case QXmlStreamReader::StartElement:
|
---|
503 | {
|
---|
504 | if(isXSLT())
|
---|
505 | {
|
---|
506 | switch(currentElementName())
|
---|
507 | {
|
---|
508 | case Include:
|
---|
509 | effectiveCode = ReportContext::XTSE0170;
|
---|
510 | break;
|
---|
511 | case Import:
|
---|
512 | effectiveCode = ReportContext::XTSE0190;
|
---|
513 | break;
|
---|
514 | default:
|
---|
515 | ;
|
---|
516 | }
|
---|
517 | }
|
---|
518 |
|
---|
519 | message = QtXmlPatterns::tr("Element %1 is not allowed at this location.")
|
---|
520 | .arg(formatKeyword(name()));
|
---|
521 | break;
|
---|
522 | }
|
---|
523 | case QXmlStreamReader::Characters:
|
---|
524 | {
|
---|
525 | if(whitespaceToSkip())
|
---|
526 | return;
|
---|
527 |
|
---|
528 | message = QtXmlPatterns::tr("Text nodes are not allowed at this location.");
|
---|
529 | break;
|
---|
530 | }
|
---|
531 | case QXmlStreamReader::Invalid:
|
---|
532 | {
|
---|
533 | /* It's an issue with well-formedness. */
|
---|
534 | message = escape(errorString());
|
---|
535 | break;
|
---|
536 | }
|
---|
537 | default:
|
---|
538 | Q_ASSERT(false);
|
---|
539 | }
|
---|
540 |
|
---|
541 | error(message, effectiveCode);
|
---|
542 | }
|
---|
543 |
|
---|
544 | void XSLTTokenizer::checkForParseError() const
|
---|
545 | {
|
---|
546 | if(hasError())
|
---|
547 | {
|
---|
548 | error(QtXmlPatterns::tr("Parse error: %1").arg(escape(errorString())), ReportContext::XTSE0010);
|
---|
549 | }
|
---|
550 | }
|
---|
551 |
|
---|
552 | QString XSLTTokenizer::readElementText()
|
---|
553 | {
|
---|
554 | QString result;
|
---|
555 |
|
---|
556 | while(!atEnd())
|
---|
557 | {
|
---|
558 | switch(readNext())
|
---|
559 | {
|
---|
560 | case QXmlStreamReader::Characters:
|
---|
561 | {
|
---|
562 | result += text().toString();
|
---|
563 | continue;
|
---|
564 | }
|
---|
565 | case QXmlStreamReader::Comment:
|
---|
566 | /* Fallthrough. */
|
---|
567 | case QXmlStreamReader::ProcessingInstruction:
|
---|
568 | continue;
|
---|
569 | case QXmlStreamReader::EndElement:
|
---|
570 | return result;
|
---|
571 | default:
|
---|
572 | unexpectedContent();
|
---|
573 | }
|
---|
574 | }
|
---|
575 |
|
---|
576 | checkForParseError();
|
---|
577 | return result;
|
---|
578 | }
|
---|
579 |
|
---|
580 | int XSLTTokenizer::commenceScanOnly()
|
---|
581 | {
|
---|
582 | /* Do nothing, return a dummy value. */
|
---|
583 | return 0;
|
---|
584 | }
|
---|
585 |
|
---|
586 | void XSLTTokenizer::resumeTokenizationFrom(const int position)
|
---|
587 | {
|
---|
588 | /* Do nothing. */
|
---|
589 | Q_UNUSED(position);
|
---|
590 | }
|
---|
591 |
|
---|
592 | void XSLTTokenizer::handleXSLTVersion(TokenSource::Queue *const to,
|
---|
593 | QStack<Token> *const queueOnExit,
|
---|
594 | const bool isXSLTElement,
|
---|
595 | const QXmlStreamAttributes *atts,
|
---|
596 | const bool generateCode,
|
---|
597 | const bool setGlobalVersion)
|
---|
598 | {
|
---|
599 | const QString ns(isXSLTElement ? QString() : CommonNamespaces::XSLT);
|
---|
600 | const QXmlStreamAttributes effectiveAtts(atts ? *atts : attributes());
|
---|
601 |
|
---|
602 | if(!effectiveAtts.hasAttribute(ns, QLatin1String("version")))
|
---|
603 | return;
|
---|
604 |
|
---|
605 | const QString attribute(effectiveAtts.value(ns, QLatin1String("version")).toString());
|
---|
606 | const AtomicValue::Ptr number(Decimal::fromLexical(attribute));
|
---|
607 |
|
---|
608 | if(number->hasError())
|
---|
609 | {
|
---|
610 | error(QtXmlPatterns::tr("The value of the XSL-T version attribute "
|
---|
611 | "must be a value of type %1, which %2 isn't.").arg(formatType(m_namePool, BuiltinTypes::xsDecimal),
|
---|
612 | formatData(attribute)),
|
---|
613 | ReportContext::XTSE0110);
|
---|
614 | }
|
---|
615 | else
|
---|
616 | {
|
---|
617 |
|
---|
618 | if(generateCode)
|
---|
619 | {
|
---|
620 | queueToken(Token(XSLT_VERSION, attribute), to);
|
---|
621 | queueToken(CURLY_LBRACE, to);
|
---|
622 | }
|
---|
623 |
|
---|
624 | const xsDecimal version = number->as<Numeric>()->toDecimal();
|
---|
625 | if(version == 2.0)
|
---|
626 | m_processingMode.push(NormalProcessing);
|
---|
627 | else if(version == 1.0)
|
---|
628 | {
|
---|
629 | /* See section 3.6 Stylesheet Element discussing this. */
|
---|
630 | warning(QtXmlPatterns::tr("Running an XSL-T 1.0 stylesheet with a 2.0 processor."));
|
---|
631 | m_processingMode.push(BackwardsCompatible);
|
---|
632 |
|
---|
633 | if(setGlobalVersion)
|
---|
634 | {
|
---|
635 | m_parseInfo->staticContext->setCompatModeEnabled(true);
|
---|
636 | m_parseInfo->isBackwardsCompat.push(true);
|
---|
637 | }
|
---|
638 | }
|
---|
639 | else if(version > 2.0)
|
---|
640 | m_processingMode.push(ForwardCompatible);
|
---|
641 | else if(version < 2.0)
|
---|
642 | m_processingMode.push(BackwardsCompatible);
|
---|
643 | }
|
---|
644 |
|
---|
645 | if(generateCode)
|
---|
646 | queueOnExit->push(CURLY_RBRACE);
|
---|
647 | }
|
---|
648 |
|
---|
649 | void XSLTTokenizer::handleXMLBase(TokenSource::Queue *const to,
|
---|
650 | QStack<Token> *const queueOnExit,
|
---|
651 | const bool isInstruction,
|
---|
652 | const QXmlStreamAttributes *atts)
|
---|
653 | {
|
---|
654 | const QXmlStreamAttributes effectiveAtts(atts ? *atts : m_currentAttributes);
|
---|
655 |
|
---|
656 | if(effectiveAtts.hasAttribute(QLatin1String("xml:base")))
|
---|
657 | {
|
---|
658 | const QStringRef val(effectiveAtts.value(QLatin1String("xml:base")));
|
---|
659 |
|
---|
660 | if(!val.isEmpty())
|
---|
661 | {
|
---|
662 | if(isInstruction)
|
---|
663 | {
|
---|
664 | queueToken(BASEURI, to);
|
---|
665 | queueToken(Token(STRING_LITERAL, val.toString()), to);
|
---|
666 | queueToken(CURLY_LBRACE, to);
|
---|
667 | queueOnExit->push(CURLY_RBRACE);
|
---|
668 | }
|
---|
669 | else
|
---|
670 | {
|
---|
671 | queueToken(DECLARE, to);
|
---|
672 | queueToken(BASEURI, to);
|
---|
673 | queueToken(INTERNAL, to);
|
---|
674 | queueToken(Token(STRING_LITERAL, val.toString()), to);
|
---|
675 | queueToken(SEMI_COLON, to);
|
---|
676 | }
|
---|
677 | }
|
---|
678 | }
|
---|
679 | }
|
---|
680 |
|
---|
681 | void XSLTTokenizer::handleStandardAttributes(const bool isXSLTElement)
|
---|
682 | {
|
---|
683 | /* We're not necessarily StartElement, that's why we have atts passed in. */
|
---|
684 | Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
|
---|
685 |
|
---|
686 | if(m_hasHandledStandardAttributes)
|
---|
687 | return;
|
---|
688 |
|
---|
689 | m_hasHandledStandardAttributes = true;
|
---|
690 |
|
---|
691 | const QString ns(isXSLTElement ? QString() : CommonNamespaces::XSLT);
|
---|
692 | const int len = m_currentAttributes.count();
|
---|
693 |
|
---|
694 | for(int i = 0; i < len; ++i)
|
---|
695 | {
|
---|
696 | const QXmlStreamAttribute &att = m_currentAttributes.at(i);
|
---|
697 |
|
---|
698 | if(att.qualifiedName() == QLatin1String("xml:space"))
|
---|
699 | {
|
---|
700 | const QStringRef val(m_currentAttributes.value(CommonNamespaces::XML, QLatin1String("space")));
|
---|
701 |
|
---|
702 | /* We raise an error if the value is not recognized.
|
---|
703 | *
|
---|
704 | * Extensible Markup Language (XML) 1.0 (Fourth Edition), 2.10
|
---|
705 | * White Space Handling:
|
---|
706 | *
|
---|
707 | * 'This specification does not give meaning to any value of
|
---|
708 | * xml:space other than "default" and "preserve". It is an error
|
---|
709 | * for other values to be specified; the XML processor may report
|
---|
710 | * the error or may recover by ignoring the attribute specification
|
---|
711 | * or by reporting the (erroneous) value to the application.' */
|
---|
712 | m_stripWhitespace.push(readToggleAttribute(QLatin1String("xml:space"),
|
---|
713 | QLatin1String("default"),
|
---|
714 | QLatin1String("preserve"),
|
---|
715 | &m_currentAttributes));
|
---|
716 | }
|
---|
717 |
|
---|
718 | if(att.namespaceUri() != ns)
|
---|
719 | continue;
|
---|
720 |
|
---|
721 | switch(toToken(att.name()))
|
---|
722 | {
|
---|
723 | case Type:
|
---|
724 | /* Fallthrough. */
|
---|
725 | case Validation:
|
---|
726 | /* Fallthrough. */
|
---|
727 | case UseAttributeSets:
|
---|
728 | /* Fallthrough. */
|
---|
729 | case Version:
|
---|
730 | /* These are handled by other function such as
|
---|
731 | * handleValidationAttributes() and handleXSLTVersion(). */
|
---|
732 | continue;
|
---|
733 | default:
|
---|
734 | {
|
---|
735 | if(!isXSLTElement) /* validateElement() will take care of it, and we
|
---|
736 | * don't want to flag non-standard XSL-T attributes. */
|
---|
737 | {
|
---|
738 | error(QtXmlPatterns::tr("Unknown XSL-T attribute %1.")
|
---|
739 | .arg(formatKeyword(att.name())),
|
---|
740 | ReportContext::XTSE0805);
|
---|
741 | }
|
---|
742 | }
|
---|
743 | }
|
---|
744 | }
|
---|
745 | }
|
---|
746 |
|
---|
747 | void XSLTTokenizer::handleValidationAttributes(const bool isLRE) const
|
---|
748 | {
|
---|
749 | Q_ASSERT(tokenType() == QXmlStreamReader::StartElement);
|
---|
750 |
|
---|
751 | const QString ns(isLRE ? QString() : CommonNamespaces::XSLT);
|
---|
752 |
|
---|
753 | const bool hasValidation = hasAttribute(ns, QLatin1String("validation"));
|
---|
754 | const bool hasType = hasAttribute(ns, QLatin1String("type"));
|
---|
755 |
|
---|
756 | if(!hasType && !hasValidation)
|
---|
757 | return;
|
---|
758 |
|
---|
759 | if(hasType && hasValidation)
|
---|
760 | {
|
---|
761 | error(QtXmlPatterns::tr("Attribute %1 and %2 are mutually exclusive.")
|
---|
762 | .arg(formatKeyword(QLatin1String("validation")),
|
---|
763 | formatKeyword(QLatin1String("type"))),
|
---|
764 | ReportContext::XTSE1505);
|
---|
765 | }
|
---|
766 |
|
---|
767 | /* QXmlStreamReader surely doesn't make this easy. */
|
---|
768 | QXmlStreamAttribute validationAttribute;
|
---|
769 | int len = m_currentAttributes.count();
|
---|
770 |
|
---|
771 | for(int i = 0; i < len; ++i)
|
---|
772 | {
|
---|
773 | const QXmlStreamAttribute &at = m_currentAttributes.at(i);
|
---|
774 | if(at.name() == QLatin1String("validation") && at.namespaceUri() == ns)
|
---|
775 | validationAttribute = at;
|
---|
776 | }
|
---|
777 |
|
---|
778 | Q_ASSERT_X(!validationAttribute.name().isNull(), Q_FUNC_INFO,
|
---|
779 | "We should always find the attribute.");
|
---|
780 |
|
---|
781 | /* We don't care about the return value, we just want to check it's a valid
|
---|
782 | * one. */
|
---|
783 | readAlternativeAttribute(m_validationAlternatives,
|
---|
784 | validationAttribute);
|
---|
785 | }
|
---|
786 |
|
---|
787 | Tokenizer::Token XSLTTokenizer::nextToken(YYLTYPE *const sourceLocator)
|
---|
788 | {
|
---|
789 | Q_UNUSED(sourceLocator);
|
---|
790 |
|
---|
791 | if(m_tokenSource.isEmpty())
|
---|
792 | {
|
---|
793 | switch(m_state.top())
|
---|
794 | {
|
---|
795 | case OutsideDocumentElement:
|
---|
796 | outsideDocumentElement();
|
---|
797 | break;
|
---|
798 | case InsideStylesheetModule:
|
---|
799 | insideStylesheetModule();
|
---|
800 | break;
|
---|
801 | case InsideSequenceConstructor:
|
---|
802 | insideSequenceConstructor(&m_tokenSource);
|
---|
803 | break;
|
---|
804 | }
|
---|
805 |
|
---|
806 | if(m_tokenSource.isEmpty())
|
---|
807 | {
|
---|
808 | *sourceLocator = currentSourceLocator();
|
---|
809 | return Token(END_OF_FILE);
|
---|
810 | }
|
---|
811 | else
|
---|
812 | return m_tokenSource.head()->nextToken(sourceLocator);
|
---|
813 | }
|
---|
814 | else
|
---|
815 | {
|
---|
816 | do
|
---|
817 | {
|
---|
818 | const Token candidate(m_tokenSource.head()->nextToken(sourceLocator));
|
---|
819 | if(candidate.type == END_OF_FILE)
|
---|
820 | m_tokenSource.dequeue();
|
---|
821 | else
|
---|
822 | return candidate;
|
---|
823 | }
|
---|
824 | while(!m_tokenSource.isEmpty());
|
---|
825 |
|
---|
826 | /* Now we will resume parsing inside the regular XSL-T(XML) file. */
|
---|
827 | return nextToken(sourceLocator);
|
---|
828 | }
|
---|
829 | }
|
---|
830 |
|
---|
831 | bool XSLTTokenizer::isElement(const XSLTTokenLookup::NodeName &name) const
|
---|
832 | {
|
---|
833 | Q_ASSERT(isXSLT());
|
---|
834 | Q_ASSERT(tokenType() == QXmlStreamReader::StartElement ||
|
---|
835 | tokenType() == QXmlStreamReader::EndElement);
|
---|
836 |
|
---|
837 | return currentElementName() == name;
|
---|
838 | }
|
---|
839 |
|
---|
840 | inline bool XSLTTokenizer::isXSLT() const
|
---|
841 | {
|
---|
842 | Q_ASSERT_X(tokenType() == QXmlStreamReader::StartElement ||
|
---|
843 | tokenType() == QXmlStreamReader::EndElement,
|
---|
844 | Q_FUNC_INFO, "The current token state must be StartElement or EndElement.");
|
---|
845 | /* Possible optimization: let MaintainingReader set an m_isXSLT which we
|
---|
846 | * read. */
|
---|
847 | return namespaceUri() == CommonNamespaces::XSLT;
|
---|
848 | }
|
---|
849 |
|
---|
850 | void XSLTTokenizer::queueOnExit(QStack<Token> &source,
|
---|
851 | TokenSource::Queue *const destination)
|
---|
852 | {
|
---|
853 | while(!source.isEmpty())
|
---|
854 | queueToken(source.pop(), destination);
|
---|
855 | }
|
---|
856 |
|
---|
857 | void XSLTTokenizer::outsideDocumentElement()
|
---|
858 | {
|
---|
859 | while(!atEnd())
|
---|
860 | {
|
---|
861 | switch(readNext())
|
---|
862 | {
|
---|
863 | case QXmlStreamReader::StartElement:
|
---|
864 | {
|
---|
865 | /* First, we synthesize one of the built-in templates,
|
---|
866 | * see section 6.6 Built-in Template Rules.
|
---|
867 | *
|
---|
868 | * Note that insideStylesheetModule() can be called multiple
|
---|
869 | * times so we can't do it there. */
|
---|
870 | {
|
---|
871 | /* Start with the one for text nodes and attributes.
|
---|
872 | * declare template matches (text() | @*) mode #all
|
---|
873 | * {
|
---|
874 | * text{.}
|
---|
875 | * };
|
---|
876 | */
|
---|
877 |
|
---|
878 | /* declare template matches (text() | @*) */
|
---|
879 | queueToken(DECLARE, &m_tokenSource);
|
---|
880 | queueToken(TEMPLATE, &m_tokenSource);
|
---|
881 | queueToken(MATCHES, &m_tokenSource);
|
---|
882 | queueToken(LPAREN, &m_tokenSource);
|
---|
883 | queueToken(TEXT, &m_tokenSource);
|
---|
884 | queueToken(LPAREN, &m_tokenSource);
|
---|
885 | queueToken(RPAREN, &m_tokenSource);
|
---|
886 | queueToken(BAR, &m_tokenSource);
|
---|
887 | queueToken(AT_SIGN, &m_tokenSource);
|
---|
888 | queueToken(STAR, &m_tokenSource);
|
---|
889 | queueToken(RPAREN, &m_tokenSource);
|
---|
890 |
|
---|
891 | /* mode #all */
|
---|
892 | queueToken(MODE, &m_tokenSource);
|
---|
893 | queueToken(Token(NCNAME, QLatin1String("#all")), &m_tokenSource);
|
---|
894 | queueToken(CURLY_LBRACE, &m_tokenSource);
|
---|
895 |
|
---|
896 | /* text{.} { */
|
---|
897 | queueToken(TEXT, &m_tokenSource);
|
---|
898 | queueToken(CURLY_LBRACE, &m_tokenSource);
|
---|
899 | queueToken(DOT, &m_tokenSource);
|
---|
900 | queueToken(CURLY_RBRACE, &m_tokenSource);
|
---|
901 |
|
---|
902 | /* }; */
|
---|
903 | queueToken(CURLY_RBRACE, &m_tokenSource);
|
---|
904 | queueToken(SEMI_COLON, &m_tokenSource);
|
---|
905 | }
|
---|
906 |
|
---|
907 | if(isXSLT() && isStylesheetElement())
|
---|
908 | {
|
---|
909 | handleStandardAttributes(true);
|
---|
910 | QStack<Token> onExitTokens;
|
---|
911 | handleXMLBase(&m_tokenSource, &onExitTokens, false);
|
---|
912 | handleXSLTVersion(&m_tokenSource, &onExitTokens, true, 0, false, true);
|
---|
913 | validateElement();
|
---|
914 | queueNamespaceDeclarations(&m_tokenSource, 0, true);
|
---|
915 |
|
---|
916 | /* We're a regular stylesheet. */
|
---|
917 |
|
---|
918 | pushState(InsideStylesheetModule);
|
---|
919 | insideStylesheetModule();
|
---|
920 | }
|
---|
921 | else
|
---|
922 | {
|
---|
923 | /* We're a simplified stylesheet. */
|
---|
924 |
|
---|
925 | if(!hasAttribute(CommonNamespaces::XSLT, QLatin1String("version")))
|
---|
926 | {
|
---|
927 | error(QtXmlPatterns::tr("In a simplified stylesheet module, attribute %1 must be present.")
|
---|
928 | .arg(formatKeyword(QLatin1String("version"))),
|
---|
929 | ReportContext::XTSE0010);
|
---|
930 | }
|
---|
931 |
|
---|
932 | QStack<Token> onExitTokens;
|
---|
933 |
|
---|
934 | /* We synthesize this as exemplified in
|
---|
935 | * 3.7 Simplified Stylesheet Modules. */
|
---|
936 | queueToken(DECLARE, &m_tokenSource);
|
---|
937 | queueToken(TEMPLATE, &m_tokenSource);
|
---|
938 | queueToken(MATCHES, &m_tokenSource);
|
---|
939 | queueToken(LPAREN, &m_tokenSource);
|
---|
940 | queueToken(SLASH, &m_tokenSource);
|
---|
941 | queueToken(RPAREN, &m_tokenSource);
|
---|
942 | queueToken(CURLY_LBRACE, &m_tokenSource);
|
---|
943 | pushState(InsideSequenceConstructor);
|
---|
944 |
|
---|
945 | handleXSLTVersion(&m_tokenSource, &onExitTokens, false, 0, true);
|
---|
946 | handleStandardAttributes(false);
|
---|
947 |
|
---|
948 | insideSequenceConstructor(&m_tokenSource, false);
|
---|
949 |
|
---|
950 | queueOnExit(onExitTokens, &m_tokenSource);
|
---|
951 | queueToken(CURLY_RBRACE, &m_tokenSource);
|
---|
952 | queueToken(CURLY_RBRACE, &m_tokenSource);
|
---|
953 | queueToken(SEMI_COLON, &m_tokenSource);
|
---|
954 | }
|
---|
955 |
|
---|
956 | queueToken(APPLY_TEMPLATE, &m_tokenSource);
|
---|
957 | queueToken(LPAREN, &m_tokenSource);
|
---|
958 | queueToken(RPAREN, &m_tokenSource);
|
---|
959 |
|
---|
960 | break;
|
---|
961 | }
|
---|
962 | default:
|
---|
963 | /* Do nothing. */;
|
---|
964 | }
|
---|
965 | }
|
---|
966 | checkForParseError();
|
---|
967 | }
|
---|
968 |
|
---|
969 | void XSLTTokenizer::queueToken(const Token &token,
|
---|
970 | TokenSource::Queue *const to)
|
---|
971 | {
|
---|
972 | TokenSource::Queue *const effective = to ? to : &m_tokenSource;
|
---|
973 |
|
---|
974 | effective->enqueue(TokenSource::Ptr(new SingleTokenContainer(token, currentSourceLocator())));
|
---|
975 | }
|
---|
976 |
|
---|
977 | void XSLTTokenizer::pushState(const State nextState)
|
---|
978 | {
|
---|
979 | m_state.push(nextState);
|
---|
980 | }
|
---|
981 |
|
---|
982 | void XSLTTokenizer::leaveState()
|
---|
983 | {
|
---|
984 | m_state.pop();
|
---|
985 | }
|
---|
986 |
|
---|
987 | void XSLTTokenizer::insideTemplate()
|
---|
988 | {
|
---|
989 | const bool hasPriority = hasAttribute(QLatin1String("priority"));
|
---|
990 | const bool hasMatch = hasAttribute(QLatin1String("match"));
|
---|
991 | const bool hasName = hasAttribute(QLatin1String("name"));
|
---|
992 | const bool hasMode = hasAttribute(QLatin1String("mode"));
|
---|
993 | const bool hasAs = hasAttribute(QLatin1String("as"));
|
---|
994 |
|
---|
995 | if(!hasMatch &&
|
---|
996 | (hasMode ||
|
---|
997 | hasPriority))
|
---|
998 | {
|
---|
999 | error(QtXmlPatterns::tr("If element %1 has no attribute %2, it cannot have attribute %3 or %4.")
|
---|
1000 | .arg(formatKeyword(QLatin1String("template")),
|
---|
1001 | formatKeyword(QLatin1String("match")),
|
---|
1002 | formatKeyword(QLatin1String("mode")),
|
---|
1003 | formatKeyword(QLatin1String("priority"))),
|
---|
1004 | ReportContext::XTSE0500);
|
---|
1005 | }
|
---|
1006 | else if(!hasMatch && !hasName)
|
---|
1007 | {
|
---|
1008 | error(QtXmlPatterns::tr("Element %1 must have at least one of the attributes %2 or %3.")
|
---|
1009 | .arg(formatKeyword(QLatin1String("template")),
|
---|
1010 | formatKeyword(QLatin1String("name")),
|
---|
1011 | formatKeyword(QLatin1String("match"))),
|
---|
1012 | ReportContext::XTSE0500);
|
---|
1013 | }
|
---|
1014 |
|
---|
1015 | queueToken(DECLARE, &m_tokenSource);
|
---|
|
---|