src/xmlpatterns/acceltree/qacceltree.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     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