author | Eckhart Koeppen <eckhart.koppen@nokia.com> |
Wed, 21 Apr 2010 12:15:23 +0300 | |
branch | RCL_3 |
changeset 12 | cc75c76972ee |
parent 4 | 3b1da2848fc7 |
permissions | -rw-r--r-- |
0 | 1 |
/**************************************************************************** |
2 |
** |
|
4
3b1da2848fc7
Revision: 201003
Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
parents:
0
diff
changeset
|
3 |
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). |
0 | 4 |
** All rights reserved. |
5 |
** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 |
** |
|
7 |
** This file is part of the QtXmlPatterns module of the Qt Toolkit. |
|
8 |
** |
|
9 |
** $QT_BEGIN_LICENSE:LGPL$ |
|
10 |
** No Commercial Usage |
|
11 |
** This file contains pre-release code and may not be distributed. |
|
12 |
** You may use this file in accordance with the terms and conditions |
|
13 |
** contained in the Technology Preview License Agreement accompanying |
|
14 |
** this package. |
|
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 |
** If you have questions regarding the use of this file, please contact |
|
29 |
** Nokia at qt-info@nokia.com. |
|
30 |
** |
|
31 |
** |
|
32 |
** |
|
33 |
** |
|
34 |
** |
|
35 |
** |
|
36 |
** |
|
37 |
** |
|
38 |
** $QT_END_LICENSE$ |
|
39 |
** |
|
40 |
****************************************************************************/ |
|
41 |
||
42 |
#include <QStack> |
|
43 |
||
44 |
#include "qabstractxmlreceiver.h" |
|
45 |
#include "qabstractxmlnodemodel_p.h" |
|
46 |
#include "qacceliterators_p.h" |
|
47 |
#include "qacceltree_p.h" |
|
48 |
#include "qatomicstring_p.h" |
|
49 |
#include "qcommonvalues_p.h" |
|
50 |
#include "qcompressedwhitespace_p.h" |
|
51 |
#include "qdebug_p.h" |
|
52 |
#include "quntypedatomic_p.h" |
|
53 |
#include "qxpathhelper_p.h" |
|
54 |
||
55 |
QT_BEGIN_NAMESPACE |
|
56 |
||
57 |
using namespace QPatternist; |
|
58 |
||
59 |
namespace QPatternist { |
|
60 |
||
61 |
class AccelTreePrivate : public QAbstractXmlNodeModelPrivate |
|
62 |
{ |
|
63 |
public: |
|
64 |
AccelTreePrivate(AccelTree *accelTree) |
|
65 |
: m_accelTree(accelTree) |
|
66 |
{ |
|
67 |
} |
|
68 |
||
69 |
virtual QSourceLocation sourceLocation(const QXmlNodeModelIndex &index) const |
|
70 |
{ |
|
71 |
return m_accelTree->sourceLocation(index); |
|
72 |
} |
|
73 |
||
74 |
private: |
|
75 |
AccelTree *m_accelTree; |
|
76 |
}; |
|
77 |
} |
|
78 |
||
79 |
AccelTree::AccelTree(const QUrl &docURI, const QUrl &bURI) |
|
80 |
: QAbstractXmlNodeModel(new AccelTreePrivate(this)) |
|
81 |
, m_documentURI(docURI) |
|
82 |
, m_baseURI(bURI) |
|
83 |
{ |
|
84 |
/* Pre-allocate at least a little bit. */ |
|
85 |
// TODO. Do it according to what an average 4 KB doc contains. |
|
86 |
basicData.reserve(100); |
|
87 |
data.reserve(30); |
|
88 |
} |
|
89 |
||
90 |
void AccelTree::printStats(const NamePool::Ptr &np) const |
|
91 |
{ |
|
92 |
Q_ASSERT(np); |
|
93 |
#ifdef QT_NO_DEBUG |
|
94 |
Q_UNUSED(np); /* Needed when compiling in release mode. */ |
|
95 |
#else |
|
96 |
const int len = basicData.count(); |
|
97 |
||
98 |
pDebug() << "AccelTree stats for" << (m_documentURI.isEmpty() ? QString::fromLatin1("<empty URI>") : m_documentURI.toString()); |
|
99 |
pDebug() << "Maximum pre number:" << maximumPreNumber(); |
|
100 |
pDebug() << "+---------------+-------+-------+---------------+-------+--------------+-------+"; |
|
101 |
pDebug() << "| Pre number | Depth | Size | Post Number | Kind | Name | Value |"; |
|
102 |
pDebug() << "+---------------+-------+-------+---------------+-------+--------------+-------+"; |
|
103 |
for(int i = 0; i < len; ++i) |
|
104 |
{ |
|
105 |
const BasicNodeData &v = basicData.at(i); |
|
106 |
pDebug() << '|' << i |
|
107 |
<< "\t\t|" << v.depth() |
|
108 |
<< "\t|" << v.size() |
|
109 |
<< "\t|" << postNumber(i) |
|
110 |
<< "\t|" << v.kind() |
|
111 |
<< "\t\t|" << (v.name().isNull() ? QString::fromLatin1("(none)") : np->displayName(v.name())) |
|
112 |
<< "\t\t|" << ((v.kind() == QXmlNodeModelIndex::Text && isCompressed(i)) ? CompressedWhitespace::decompress(data.value(i)) |
|
113 |
: data.value(i)) |
|
114 |
<< "\t|"; |
|
115 |
/* |
|
116 |
pDebug() << '|' << QString().arg(i, 14) |
|
117 |
<< '|' << QString().arg(v.depth(), 6) |
|
118 |
<< '|' << QString().arg(v.size(), 6) |
|
119 |
<< '|' << QString().arg(postNumber(i), 14) |
|
120 |
<< '|' << QString().arg(v.kind(), 6) |
|
121 |
<< '|'; |
|
122 |
*/ |
|
123 |
} |
|
124 |
pDebug() << "+---------------+-------+-------+---------------+-------+--------------+"; |
|
125 |
pDebug() << "Namespaces(" << namespaces.count() << "):"; |
|
126 |
||
127 |
QHashIterator<PreNumber, QVector<QXmlName> > it(namespaces); |
|
128 |
while(it.hasNext()) |
|
129 |
{ |
|
130 |
it.next(); |
|
131 |
||
132 |
pDebug() << "PreNumber: " << QString::number(it.key()); |
|
133 |
for(int i = 0; i < it.value().count(); ++i) |
|
134 |
pDebug() << "\t\t" << np->stringForPrefix(it.value().at(i).prefix()) << " = " << np->stringForNamespace(it.value().at(i).namespaceURI()); |
|
135 |
} |
|
136 |
||
137 |
#endif |
|
138 |
} |
|
139 |
||
140 |
QUrl AccelTree::baseUri(const QXmlNodeModelIndex &ni) const |
|
141 |
{ |
|
142 |
switch(kind(toPreNumber(ni))) |
|
143 |
{ |
|
144 |
case QXmlNodeModelIndex::Document: |
|
145 |
return baseUri(); |
|
146 |
case QXmlNodeModelIndex::Element: |
|
147 |
{ |
|
148 |
const QXmlNodeModelIndex::Iterator::Ptr it(iterate(ni, QXmlNodeModelIndex::AxisAttribute)); |
|
149 |
QXmlNodeModelIndex next(it->next()); |
|
150 |
||
151 |
while(!next.isNull()) |
|
152 |
{ |
|
153 |
if(next.name() == QXmlName(StandardNamespaces::xml, StandardLocalNames::base)) |
|
154 |
{ |
|
155 |
const QUrl candidate(next.stringValue()); |
|
156 |
// TODO. The xml:base spec says to do URI escaping here. |
|
157 |
||
158 |
if(!candidate.isValid()) |
|
159 |
return QUrl(); |
|
160 |
else if(candidate.isRelative()) |
|
161 |
{ |
|
162 |
const QXmlNodeModelIndex par(parent(ni)); |
|
163 |
||
164 |
if(par.isNull()) |
|
165 |
return baseUri().resolved(candidate); |
|
166 |
else |
|
167 |
return par.baseUri().resolved(candidate); |
|
168 |
} |
|
169 |
else |
|
170 |
return candidate; |
|
171 |
} |
|
172 |
||
173 |
next = it->next(); |
|
174 |
} |
|
175 |
||
176 |
/* We have no xml:base-attribute. Can any parent supply us a base URI? */ |
|
177 |
const QXmlNodeModelIndex par(parent(ni)); |
|
178 |
||
179 |
if(par.isNull()) |
|
180 |
return baseUri(); |
|
181 |
else |
|
182 |
return par.baseUri(); |
|
183 |
} |
|
184 |
case QXmlNodeModelIndex::ProcessingInstruction: |
|
185 |
/* Fallthrough. */ |
|
186 |
case QXmlNodeModelIndex::Comment: |
|
187 |
/* Fallthrough. */ |
|
188 |
case QXmlNodeModelIndex::Attribute: |
|
189 |
/* Fallthrough. */ |
|
190 |
case QXmlNodeModelIndex::Text: |
|
191 |
{ |
|
192 |
const QXmlNodeModelIndex par(ni.iterate(QXmlNodeModelIndex::AxisParent)->next()); |
|
193 |
if(par.isNull()) |
|
194 |
return QUrl(); |
|
195 |
else |
|
196 |
return par.baseUri(); |
|
197 |
} |
|
198 |
case QXmlNodeModelIndex::Namespace: |
|
199 |
return QUrl(); |
|
200 |
} |
|
201 |
||
202 |
Q_ASSERT_X(false, Q_FUNC_INFO, "This line is never supposed to be reached."); |
|
203 |
return QUrl(); |
|
204 |
} |
|
205 |
||
206 |
QUrl AccelTree::documentUri(const QXmlNodeModelIndex &ni) const |
|
207 |
{ |
|
208 |
if(kind(toPreNumber(ni)) == QXmlNodeModelIndex::Document) |
|
209 |
return documentUri(); |
|
210 |
else |
|
211 |
return QUrl(); |
|
212 |
} |
|
213 |
||
214 |
QXmlNodeModelIndex::NodeKind AccelTree::kind(const QXmlNodeModelIndex &ni) const |
|
215 |
{ |
|
216 |
return kind(toPreNumber(ni)); |
|
217 |
} |
|
218 |
||
219 |
QXmlNodeModelIndex::DocumentOrder AccelTree::compareOrder(const QXmlNodeModelIndex &ni1, |
|
220 |
const QXmlNodeModelIndex &ni2) const |
|
221 |
{ |
|
222 |
Q_ASSERT_X(ni1.model() == ni2.model(), Q_FUNC_INFO, |
|
223 |
"The API docs guarantees the two nodes are from the same model"); |
|
224 |
||
225 |
const PreNumber p1 = ni1.data(); |
|
226 |
const PreNumber p2 = ni2.data(); |
|
227 |
||
228 |
if(p1 == p2) |
|
229 |
return QXmlNodeModelIndex::Is; |
|
230 |
else if(p1 < p2) |
|
231 |
return QXmlNodeModelIndex::Precedes; |
|
232 |
else |
|
233 |
return QXmlNodeModelIndex::Follows; |
|
234 |
} |
|
235 |
||
236 |
QXmlNodeModelIndex AccelTree::root(const QXmlNodeModelIndex &) const |
|
237 |
{ |
|
238 |
return createIndex(qint64(0)); |
|
239 |
} |
|
240 |
||
241 |
QXmlNodeModelIndex AccelTree::parent(const QXmlNodeModelIndex &ni) const |
|
242 |
{ |
|
243 |
const AccelTree::PreNumber p = basicData.at(toPreNumber(ni)).parent(); |
|
244 |
||
245 |
if(p == -1) |
|
246 |
return QXmlNodeModelIndex(); |
|
247 |
else |
|
248 |
return createIndex(p); |
|
249 |
} |
|
250 |
||
251 |
QXmlNodeModelIndex::Iterator::Ptr AccelTree::iterate(const QXmlNodeModelIndex &ni, |
|
252 |
QXmlNodeModelIndex::Axis axis) const |
|
253 |
{ |
|
254 |
const PreNumber preNumber = toPreNumber(ni); |
|
255 |
||
256 |
switch(axis) |
|
257 |
{ |
|
258 |
case QXmlNodeModelIndex::AxisChildOrTop: |
|
259 |
{ |
|
260 |
if(!hasParent(preNumber)) |
|
261 |
{ |
|
262 |
switch(kind(preNumber)) |
|
263 |
{ |
|
264 |
case QXmlNodeModelIndex::Comment: |
|
265 |
/* Fallthrough. */ |
|
266 |
case QXmlNodeModelIndex::ProcessingInstruction: |
|
267 |
/* Fallthrough. */ |
|
268 |
case QXmlNodeModelIndex::Element: |
|
269 |
/* Fallthrough. */ |
|
270 |
case QXmlNodeModelIndex::Text: |
|
271 |
return makeSingletonIterator(ni); |
|
272 |
case QXmlNodeModelIndex::Attribute: |
|
273 |
/* Fallthrough. */ |
|
274 |
case QXmlNodeModelIndex::Document: |
|
275 |
/* Fallthrough. */ |
|
276 |
case QXmlNodeModelIndex::Namespace: |
|
277 |
/* Do nothing. */; |
|
278 |
} |
|
279 |
} |
|
280 |
/* Else, fallthrough to AxisChild. */ |
|
281 |
} |
|
282 |
case QXmlNodeModelIndex::AxisChild: |
|
283 |
{ |
|
284 |
if(hasChildren(preNumber)) |
|
285 |
return QXmlNodeModelIndex::Iterator::Ptr(new ChildIterator(this, preNumber)); |
|
286 |
else |
|
287 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
288 |
} |
|
289 |
case QXmlNodeModelIndex::AxisAncestor: |
|
290 |
{ |
|
291 |
if(hasParent(preNumber)) |
|
292 |
return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator<false>(this, preNumber)); |
|
293 |
else |
|
294 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
295 |
} |
|
296 |
case QXmlNodeModelIndex::AxisAncestorOrSelf: |
|
297 |
return QXmlNodeModelIndex::Iterator::Ptr(new AncestorIterator<true>(this, preNumber)); |
|
298 |
case QXmlNodeModelIndex::AxisParent: |
|
299 |
{ |
|
300 |
if(hasParent(preNumber)) |
|
301 |
return makeSingletonIterator(createIndex(parent(preNumber))); |
|
302 |
else |
|
303 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
304 |
} |
|
305 |
case QXmlNodeModelIndex::AxisDescendant: |
|
306 |
{ |
|
307 |
if(hasChildren(preNumber)) |
|
308 |
return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator<false>(this, preNumber)); |
|
309 |
else |
|
310 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
311 |
} |
|
312 |
case QXmlNodeModelIndex::AxisDescendantOrSelf: |
|
313 |
return QXmlNodeModelIndex::Iterator::Ptr(new DescendantIterator<true>(this, preNumber)); |
|
314 |
case QXmlNodeModelIndex::AxisFollowing: |
|
315 |
{ |
|
316 |
if(preNumber == maximumPreNumber()) |
|
317 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
318 |
else |
|
319 |
return QXmlNodeModelIndex::Iterator::Ptr(new FollowingIterator(this, preNumber)); |
|
320 |
} |
|
321 |
case QXmlNodeModelIndex::AxisAttributeOrTop: |
|
322 |
{ |
|
323 |
if(!hasParent(preNumber) && kind(preNumber) == QXmlNodeModelIndex::Attribute) |
|
324 |
return makeSingletonIterator(ni); |
|
325 |
/* Else, falthrough to AxisAttribute. */ |
|
326 |
} |
|
327 |
case QXmlNodeModelIndex::AxisAttribute: |
|
328 |
{ |
|
329 |
if(hasChildren(preNumber) && kind(preNumber + 1) == QXmlNodeModelIndex::Attribute) |
|
330 |
return QXmlNodeModelIndex::Iterator::Ptr(new AttributeIterator(this, preNumber)); |
|
331 |
else |
|
332 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
333 |
} |
|
334 |
case QXmlNodeModelIndex::AxisPreceding: |
|
335 |
{ |
|
336 |
if(preNumber == 0) |
|
337 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
338 |
else |
|
339 |
return QXmlNodeModelIndex::Iterator::Ptr(new PrecedingIterator(this, preNumber)); |
|
340 |
} |
|
341 |
case QXmlNodeModelIndex::AxisSelf: |
|
342 |
return makeSingletonIterator(createIndex(toPreNumber(ni))); |
|
343 |
case QXmlNodeModelIndex::AxisFollowingSibling: |
|
344 |
{ |
|
345 |
if(preNumber == maximumPreNumber()) |
|
346 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
347 |
else |
|
348 |
return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator<true>(this, preNumber)); |
|
349 |
} |
|
350 |
case QXmlNodeModelIndex::AxisPrecedingSibling: |
|
351 |
{ |
|
352 |
if(preNumber == 0) |
|
353 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
354 |
else |
|
355 |
return QXmlNodeModelIndex::Iterator::Ptr(new SiblingIterator<false>(this, preNumber)); |
|
356 |
} |
|
357 |
case QXmlNodeModelIndex::AxisNamespace: |
|
358 |
return makeEmptyIterator<QXmlNodeModelIndex>(); |
|
359 |
} |
|
360 |
||
361 |
Q_ASSERT(false); |
|
362 |
return QXmlNodeModelIndex::Iterator::Ptr(); |
|
363 |
} |
|
364 |
||
365 |
QXmlNodeModelIndex AccelTree::nextFromSimpleAxis(QAbstractXmlNodeModel::SimpleAxis, |
|
366 |
const QXmlNodeModelIndex&) const |
|
367 |
{ |
|
368 |
Q_ASSERT_X(false, Q_FUNC_INFO, "This function is not supposed to be called."); |
|
369 |
return QXmlNodeModelIndex(); |
|
370 |
} |
|
371 |
||
372 |
QVector<QXmlNodeModelIndex> AccelTree::attributes(const QXmlNodeModelIndex &element) const |
|
373 |
{ |
|
374 |
Q_ASSERT_X(false, Q_FUNC_INFO, "This function is not supposed to be called."); |
|
375 |
Q_UNUSED(element); |
|
376 |
return QVector<QXmlNodeModelIndex>(); |
|
377 |
} |
|
378 |
||
379 |
QXmlName AccelTree::name(const QXmlNodeModelIndex &ni) const |
|
380 |
{ |
|
381 |
/* If this node type does not have a name(for instance, it's a comment) |
|
382 |
* we will return the default constructed value, which is conformant with |
|
383 |
* this function's contract. */ |
|
384 |
return name(toPreNumber(ni)); |
|
385 |
} |
|
386 |
||
387 |
QVector<QXmlName> AccelTree::namespaceBindings(const QXmlNodeModelIndex &ni) const |
|
388 |
{ |
|
389 |
/* We get a hold of the ancestor, and loop them in reverse document |
|
390 |
* order(first the parent, then the parent's parent, etc). As soon |
|
391 |
* we find a binding that hasn't already been added, we add it to the |
|
392 |
* result list. In that way, declarations appearing further down override |
|
393 |
* those further up. */ |
|
394 |
||
395 |
const PreNumber preNumber = toPreNumber(ni); |
|
396 |
||
397 |
const QXmlNodeModelIndex::Iterator::Ptr it(new AncestorIterator<true>(this, preNumber)); |
|
398 |
QVector<QXmlName> result; |
|
399 |
QXmlNodeModelIndex n(it->next()); |
|
400 |
||
401 |
/* Whether xmlns="" has been encountered. */ |
|
402 |
bool hasUndeclaration = false; |
|
403 |
||
404 |
while(!n.isNull()) |
|
405 |
{ |
|
406 |
const QVector<QXmlName> &forNode = namespaces.value(toPreNumber(n)); |
|
407 |
const int len = forNode.size(); |
|
408 |
bool stopInheritance = false; |
|
409 |
||
410 |
for(int i = 0; i < len; ++i) |
|
411 |
{ |
|
412 |
const QXmlName &nsb = forNode.at(i); |
|
413 |
||
414 |
if(nsb.namespaceURI() == StandardNamespaces::StopNamespaceInheritance) |
|
415 |
{ |
|
416 |
stopInheritance = true; |
|
417 |
continue; |
|
418 |
} |
|
419 |
||
420 |
if(nsb.prefix() == StandardPrefixes::empty && |
|
421 |
nsb.namespaceURI() == StandardNamespaces::empty) |
|
422 |
{ |
|
423 |
hasUndeclaration = true; |
|
424 |
continue; |
|
425 |
} |
|
426 |
||
427 |
if(!hasPrefix(result, nsb.prefix())) |
|
428 |
{ |
|
429 |
/* We've already encountered an undeclaration, so we're supposed to skip |
|
430 |
* them. */ |
|
431 |
if(hasUndeclaration && nsb.prefix() == StandardPrefixes::empty) |
|
432 |
continue; |
|
433 |
else |
|
434 |
result.append(nsb); |
|
435 |
} |
|
436 |
} |
|
437 |
||
438 |
if(stopInheritance) |
|
439 |
break; |
|
440 |
else |
|
441 |
n = it->next(); |
|
442 |
} |
|
443 |
||
444 |
result.append(QXmlName(StandardNamespaces::xml, StandardLocalNames::empty, StandardPrefixes::xml)); |
|
445 |
||
446 |
return result; |
|
447 |
} |
|
448 |
||
449 |
void AccelTree::sendNamespaces(const QXmlNodeModelIndex &n, |
|
450 |
QAbstractXmlReceiver *const receiver) const |
|
451 |
{ |
|
452 |
Q_ASSERT(n.kind() == QXmlNodeModelIndex::Element); |
|
453 |
||
454 |
const QXmlNodeModelIndex::Iterator::Ptr it(iterate(n, QXmlNodeModelIndex::AxisAncestorOrSelf)); |
|
455 |
QXmlNodeModelIndex next(it->next()); |
|
456 |
QVector<QXmlName::PrefixCode> alreadySent; |
|
457 |
||
458 |
while(!next.isNull()) |
|
459 |
{ |
|
460 |
const PreNumber preNumber = toPreNumber(next); |
|
461 |
||
462 |
const QVector<QXmlName> &nss = namespaces.value(preNumber); |
|
463 |
||
464 |
/* This is by far the most common case. */ |
|
465 |
if(nss.isEmpty()) |
|
466 |
{ |
|
467 |
next = it->next(); |
|
468 |
continue; |
|
469 |
} |
|
470 |
||
471 |
const int len = nss.count(); |
|
472 |
bool stopInheritance = false; |
|
473 |
||
474 |
for(int i = 0; i < len; ++i) |
|
475 |
{ |
|
476 |
const QXmlName &name = nss.at(i); |
|
477 |
||
478 |
if(name.namespaceURI() == StandardNamespaces::StopNamespaceInheritance) |
|
479 |
{ |
|
480 |
stopInheritance = true; |
|
481 |
continue; |
|
482 |
} |
|
483 |
||
484 |
if(!alreadySent.contains(name.prefix())) |
|
485 |
{ |
|
486 |
alreadySent.append(name.prefix()); |
|
487 |
receiver->namespaceBinding(name); |
|
488 |
} |
|
489 |
} |
|
490 |
||
491 |
if(stopInheritance) |
|
492 |
break; |
|
493 |
else |
|
494 |
next = it->next(); |
|
495 |
} |
|
496 |
} |
|
497 |
||
498 |
QString AccelTree::stringValue(const QXmlNodeModelIndex &ni) const |
|
499 |
{ |
|
500 |
const PreNumber preNumber = toPreNumber(ni); |
|
501 |
||
502 |
switch(kind(preNumber)) |
|
503 |
{ |
|
504 |
case QXmlNodeModelIndex::Element: |
|
505 |
{ |
|
506 |
/* Concatenate all text nodes that are descendants of this node. */ |
|
507 |
if(!hasChildren(preNumber)) |
|
508 |
return QString(); |
|
509 |
||
510 |
const AccelTree::PreNumber stop = preNumber + size(preNumber); |
|
511 |
AccelTree::PreNumber pn = preNumber + 1; /* Jump over ourselves. */ |
|
512 |
QString result; |
|
513 |
||
514 |
for(; pn <= stop; ++pn) |
|
515 |
{ |
|
516 |
if(kind(pn) == QXmlNodeModelIndex::Text) |
|
517 |
{ |
|
518 |
if(isCompressed(pn)) |
|
519 |
result += CompressedWhitespace::decompress(data.value(pn)); |
|
520 |
else |
|
521 |
result += data.value(pn); |
|
522 |
} |
|
523 |
} |
|
524 |
||
525 |
return result; |
|
526 |
} |
|
527 |
case QXmlNodeModelIndex::Text: |
|
528 |
{ |
|
529 |
if(isCompressed(preNumber)) |
|
530 |
return CompressedWhitespace::decompress(data.value(preNumber)); |
|
531 |
/* Else, fallthrough. It's not compressed so use it as it is. */ |
|
532 |
} |
|
533 |
case QXmlNodeModelIndex::Attribute: |
|
534 |
/* Fallthrough */ |
|
535 |
case QXmlNodeModelIndex::ProcessingInstruction: |
|
536 |
/* Fallthrough */ |
|
537 |
case QXmlNodeModelIndex::Comment: |
|
538 |
return data.value(preNumber); |
|
539 |
case QXmlNodeModelIndex::Document: |
|
540 |
{ |
|
541 |
/* Concatenate all text nodes in the whole document. */ |
|
542 |
||
543 |
QString result; |
|
544 |
// Perhaps we can QString::reserve() the result based on the size? |
|
545 |
const AccelTree::PreNumber max = maximumPreNumber(); |
|
546 |
||
547 |
for(AccelTree::PreNumber i = 0; i <= max; ++i) |
|
548 |
{ |
|
549 |
if(kind(i) == QXmlNodeModelIndex::Text) |
|
550 |
{ |
|
551 |
if(isCompressed(i)) |
|
552 |
result += CompressedWhitespace::decompress(data.value(i)); |
|
553 |
else |
|
554 |
result += data.value(i); |
|
555 |
} |
|
556 |
} |
|
557 |
||
558 |
return result; |
|
559 |
} |
|
560 |
default: |
|
561 |
{ |
|
562 |
Q_ASSERT_X(false, Q_FUNC_INFO, |
|
563 |
"A node type that doesn't exist in the XPath Data Model was encountered."); |
|
564 |
return QString(); /* Dummy, silence compiler warning. */ |
|
565 |
} |
|
566 |
} |
|
567 |
} |
|
568 |
||
569 |
QVariant AccelTree::typedValue(const QXmlNodeModelIndex &n) const |
|
570 |
{ |
|
571 |
return stringValue(n); |
|
572 |
} |
|
573 |
||
574 |
bool AccelTree::hasPrefix(const QVector<QXmlName> &nbs, const QXmlName::PrefixCode prefix) |
|
575 |
{ |
|
576 |
const int size = nbs.size(); |
|
577 |
||
578 |
for(int i = 0; i < size; ++i) |
|
579 |
{ |
|
580 |
if(nbs.at(i).prefix() == prefix) |
|
581 |
return true; |
|
582 |
} |
|
583 |
||
584 |
return false; |
|
585 |
} |
|
586 |
||
587 |
ItemType::Ptr AccelTree::type(const QXmlNodeModelIndex &ni) const |
|
588 |
{ |
|
589 |
/* kind() is manually inlined here to avoid a virtual call. */ |
|
590 |
return XPathHelper::typeFromKind(basicData.at(toPreNumber(ni)).kind()); |
|
591 |
} |
|
592 |
||
593 |
Item::Iterator::Ptr AccelTree::sequencedTypedValue(const QXmlNodeModelIndex &n) const |
|
594 |
{ |
|
595 |
const PreNumber preNumber = toPreNumber(n); |
|
596 |
||
597 |
switch(kind(preNumber)) |
|
598 |
{ |
|
599 |
case QXmlNodeModelIndex::Element: |
|
600 |
/* Fallthrough. */ |
|
601 |
case QXmlNodeModelIndex::Document: |
|
602 |
/* Fallthrough. */ |
|
603 |
case QXmlNodeModelIndex::Attribute: |
|
604 |
return makeSingletonIterator(Item(UntypedAtomic::fromValue(stringValue(n)))); |
|
605 |
||
606 |
case QXmlNodeModelIndex::Text: |
|
607 |
/* Fallthrough. */ |
|
608 |
case QXmlNodeModelIndex::ProcessingInstruction: |
|
609 |
/* Fallthrough. */ |
|
610 |
case QXmlNodeModelIndex::Comment: |
|
611 |
return makeSingletonIterator(Item(AtomicString::fromValue(stringValue(n)))); |
|
612 |
default: |
|
613 |
{ |
|
614 |
Q_ASSERT_X(false, Q_FUNC_INFO, |
|
615 |
qPrintable(QString::fromLatin1("A node type that doesn't exist " |
|
616 |
"in the XPath Data Model was encountered.").arg(kind(preNumber)))); |
|
617 |
return Item::Iterator::Ptr(); /* Dummy, silence compiler warning. */ |
|
618 |
} |
|
619 |
} |
|
620 |
} |
|
621 |
||
622 |
void AccelTree::copyNodeTo(const QXmlNodeModelIndex &node, |
|
623 |
QAbstractXmlReceiver *const receiver, |
|
624 |
const NodeCopySettings &settings) const |
|
625 |
{ |
|
626 |
/* This code piece can be seen as a customized version of |
|
627 |
* QAbstractXmlReceiver::item/sendAsNode(). */ |
|
628 |
Q_ASSERT(receiver); |
|
629 |
Q_ASSERT(!node.isNull()); |
|
630 |
||
631 |
typedef QHash<QXmlName::PrefixCode, QXmlName::NamespaceCode> Binding; |
|
632 |
QStack<Binding> outputted; |
|
633 |
||
634 |
switch(node.kind()) |
|
635 |
{ |
|
636 |
case QXmlNodeModelIndex::Element: |
|
637 |
{ |
|
638 |
outputted.push(Binding()); |
|
639 |
||
640 |
/* Add the namespace for our element name. */ |
|
641 |
const QXmlName elementName(node.name()); |
|
642 |
||
643 |
receiver->startElement(elementName); |
|
644 |
||
645 |
if(!settings.testFlag(InheritNamespaces)) |
|
646 |
receiver->namespaceBinding(QXmlName(StandardNamespaces::StopNamespaceInheritance, 0, |
|
647 |
StandardPrefixes::StopNamespaceInheritance)); |
|
648 |
||
649 |
if(settings.testFlag(PreserveNamespaces)) |
|
650 |
node.sendNamespaces(receiver); |
|
651 |
else |
|
652 |
{ |
|
653 |
/* Find the namespaces that we actually use and add them to outputted. These are drawn |
|
654 |
* from the element name, and the node's attributes. */ |
|
655 |
outputted.top().insert(elementName.prefix(), elementName.namespaceURI()); |
|
656 |
||
657 |
const QXmlNodeModelIndex::Iterator::Ptr attributes(iterate(node, QXmlNodeModelIndex::AxisAttribute)); |
|
658 |
QXmlNodeModelIndex attr(attributes->next()); |
|
659 |
||
660 |
while(!attr.isNull()) |
|
661 |
{ |
|
662 |
const QXmlName &attrName = attr.name(); |
|
663 |
outputted.top().insert(attrName.prefix(), attrName.namespaceURI()); |
|
664 |
attr = attributes->next(); |
|
665 |
} |
|
666 |
||
667 |
Binding::const_iterator it(outputted.top().constBegin()); |
|
668 |
const Binding::const_iterator end(outputted.top().constEnd()); |
|
669 |
||
670 |
for(; it != end; ++it) |
|
671 |
receiver->namespaceBinding(QXmlName(it.value(), 0, it.key())); |
|
672 |
} |
|
673 |
||
674 |
/* Send the attributes of the element. */ |
|
675 |
{ |
|
676 |
QXmlNodeModelIndex::Iterator::Ptr attributes(node.iterate(QXmlNodeModelIndex::AxisAttribute)); |
|
677 |
QXmlNodeModelIndex attribute(attributes->next()); |
|
678 |
||
679 |
while(!attribute.isNull()) |
|
680 |
{ |
|
681 |
const QString &v = attribute.stringValue(); |
|
682 |
receiver->attribute(attribute.name(), QStringRef(&v)); |
|
683 |
attribute = attributes->next(); |
|
684 |
} |
|
685 |
} |
|
686 |
||
687 |
/* Send the children of the element. */ |
|
688 |
copyChildren(node, receiver, settings); |
|
689 |
||
690 |
receiver->endElement(); |
|
691 |
outputted.pop(); |
|
692 |
break; |
|
693 |
} |
|
694 |
case QXmlNodeModelIndex::Document: |
|
695 |
{ |
|
696 |
/* We need to intercept and grab the elements of the document node, such |
|
697 |
* that we preserve/inherit preference applies to them. */ |
|
698 |
receiver->startDocument(); |
|
699 |
copyChildren(node, receiver, settings); |
|
700 |
receiver->endDocument(); |
|
701 |
break; |
|
702 |
} |
|
703 |
default: |
|
704 |
receiver->item(node); |
|
705 |
} |
|
706 |
||
707 |
} |
|
708 |
||
709 |
QSourceLocation AccelTree::sourceLocation(const QXmlNodeModelIndex &index) const |
|
710 |
{ |
|
711 |
const PreNumber key = toPreNumber(index); |
|
712 |
if (sourcePositions.contains(key)) { |
|
713 |
const QPair<qint64, qint64> position = sourcePositions.value(key); |
|
714 |
return QSourceLocation(m_documentURI, position.first, position.second); |
|
715 |
} else { |
|
716 |
return QSourceLocation(); |
|
717 |
} |
|
718 |
} |
|
719 |
||
720 |
void AccelTree::copyChildren(const QXmlNodeModelIndex &node, |
|
721 |
QAbstractXmlReceiver *const receiver, |
|
722 |
const NodeCopySettings &settings) const |
|
723 |
{ |
|
724 |
QXmlNodeModelIndex::Iterator::Ptr children(node.iterate(QXmlNodeModelIndex::AxisChild)); |
|
725 |
QXmlNodeModelIndex child(children->next()); |
|
726 |
||
727 |
while(!child.isNull()) |
|
728 |
{ |
|
729 |
copyNodeTo(child, receiver, settings); |
|
730 |
child = children->next(); |
|
731 |
} |
|
732 |
} |
|
733 |
||
734 |
QXmlNodeModelIndex AccelTree::elementById(const QXmlName &id) const |
|
735 |
{ |
|
736 |
const PreNumber pre = m_IDs.value(id.localName(), -1); |
|
737 |
if(pre == -1) |
|
738 |
return QXmlNodeModelIndex(); |
|
739 |
else |
|
740 |
return createIndex(pre); |
|
741 |
} |
|
742 |
||
743 |
QVector<QXmlNodeModelIndex> AccelTree::nodesByIdref(const QXmlName &) const |
|
744 |
{ |
|
745 |
return QVector<QXmlNodeModelIndex>(); |
|
746 |
} |
|
747 |
||
748 |
QT_END_NAMESPACE |
|
749 |