src/xmlpatterns/api/qxmlformatter.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 <QtDebug>
       
    43 
       
    44 #include "qxmlformatter.h"
       
    45 #include "qxpathhelper_p.h"
       
    46 #include "qxmlserializer_p.h"
       
    47 
       
    48 QT_BEGIN_NAMESPACE
       
    49 
       
    50 using namespace QPatternist;
       
    51 
       
    52 class QXmlFormatterPrivate : public QXmlSerializerPrivate
       
    53 {
       
    54 public:
       
    55     inline QXmlFormatterPrivate(const QXmlQuery &q,
       
    56                                 QIODevice *const outputDevice);
       
    57 
       
    58     int             indentationDepth;
       
    59     int             currentDepth;
       
    60     QString         characterBuffer;
       
    61     QString         indentString;
       
    62 
       
    63     /**
       
    64      * Whether we /have/ sent nodes like processing instructions and comments
       
    65      * to QXmlSerializer.
       
    66      */
       
    67     QStack<bool>    canIndent;
       
    68 };
       
    69 
       
    70 QXmlFormatterPrivate::QXmlFormatterPrivate(const QXmlQuery &query,
       
    71                                            QIODevice *const outputDevice) : QXmlSerializerPrivate(query, outputDevice)
       
    72                                                                           , indentationDepth(4)
       
    73                                                                           , currentDepth(0)
       
    74 {
       
    75     indentString.reserve(30);
       
    76     indentString.resize(1);
       
    77     indentString[0] = QLatin1Char('\n');
       
    78     canIndent.push(false);
       
    79 }
       
    80 
       
    81 /*!
       
    82    \class QXmlFormatter
       
    83    \brief The QXmlFormatter class is an implementation of QXmlSerializer for transforming XQuery output into formatted XML.
       
    84    \reentrant
       
    85    \since 4.4
       
    86    \ingroup xml-tools
       
    87 
       
    88    QXmlFormatter is a subclass of QXmlSerializer that formats the XML
       
    89    output to make it easier for humans to read.
       
    90 
       
    91    QXmlSerializer outputs XML without adding unnecessary whitespace.
       
    92    In particular, it does not add \e {newlines} and indentation.
       
    93    To make the XML output easier to read, QXmlFormatter adds \e{newlines}
       
    94    and indentation by adding, removing, and modifying
       
    95    \l{XQuery Sequence}{sequence nodes} that only consist of whitespace.
       
    96    It also modifies whitespace in other places where it is not
       
    97    significant; e.g., between attributes and in the document prologue.
       
    98 
       
    99    For example, where the base class QXmlSerializer would
       
   100    output this:
       
   101 
       
   102    \quotefile doc/src/snippets/patternist/notIndented.xml
       
   103 
       
   104    QXmlFormatter outputs this:
       
   105 
       
   106    \quotefile doc/src/snippets/patternist/indented.xml
       
   107 
       
   108    If you just want to serialize your XML in a human-readable
       
   109    format, use QXmlFormatter as it is. The default indentation
       
   110    level is 4 spaces, but you can set your own indentation value
       
   111    setIndentationDepth().
       
   112 
       
   113    The \e{newlines} and indentation added by QXmlFormatter are
       
   114    suitable for common formats, such as XHTML, SVG, or Docbook,
       
   115    where whitespace is not significant. However, if your XML will
       
   116    be used as input where whitespace is significant, then you must
       
   117    write your own subclass of QXmlSerializer or QAbstractXmlReceiver.
       
   118 
       
   119    Note that using QXmlFormatter instead of QXmlSerializer will
       
   120    increase computational overhead and document storage size due
       
   121    to the insertion of whitespace.
       
   122 
       
   123    Note also that the indentation style used by QXmlFormatter
       
   124    remains loosely defined and may change in future versions of
       
   125    Qt. If a specific indentation style is required then either
       
   126    use the base class QXmlSerializer directly, or write your own
       
   127    subclass of QXmlSerializer or QAbstractXmlReceiver.
       
   128    Alternatively, you can subclass QXmlFormatter and reimplement
       
   129    the callbacks there.
       
   130 
       
   131    \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlformatter.cpp 0
       
   132 */
       
   133 
       
   134 /*!
       
   135   Constructs a formatter that uses the name pool and message
       
   136   handler in \a query, and writes the result to \a outputDevice
       
   137   as formatted XML.
       
   138 
       
   139   \a outputDevice is passed directly to QXmlSerializer's constructor.
       
   140 
       
   141   \sa QXmlSerializer
       
   142  */
       
   143 QXmlFormatter::QXmlFormatter(const QXmlQuery &query,
       
   144                              QIODevice *outputDevice) : QXmlSerializer(new QXmlFormatterPrivate(query, outputDevice))
       
   145 {
       
   146 }
       
   147 
       
   148 /*!
       
   149   \internal
       
   150  */
       
   151 void QXmlFormatter::startFormattingContent()
       
   152 {
       
   153     Q_D(QXmlFormatter);
       
   154 
       
   155     if(QPatternist::XPathHelper::isWhitespaceOnly(d->characterBuffer))
       
   156     {
       
   157         if(d->canIndent.top())
       
   158             QXmlSerializer::characters(QStringRef(&d->indentString));
       
   159     }
       
   160     else
       
   161     {
       
   162         if(!d->characterBuffer.isEmpty()) /* Significant data, we don't touch it. */
       
   163             QXmlSerializer::characters(QStringRef(&d->characterBuffer));
       
   164     }
       
   165 
       
   166     d->characterBuffer.clear();
       
   167 }
       
   168 
       
   169 /*!
       
   170   \reimp
       
   171  */
       
   172 void QXmlFormatter::startElement(const QXmlName &name)
       
   173 {
       
   174     Q_D(QXmlFormatter);
       
   175     startFormattingContent();
       
   176     ++d->currentDepth;
       
   177     d->indentString.append(QString(d->indentationDepth, QLatin1Char(' ')));
       
   178     d->canIndent.push(true);
       
   179 
       
   180     QXmlSerializer::startElement(name);
       
   181 }
       
   182 
       
   183 /*!
       
   184   \reimp
       
   185  */
       
   186 void QXmlFormatter::endElement()
       
   187 {
       
   188     Q_D(QXmlFormatter);
       
   189     --d->currentDepth;
       
   190     d->indentString.chop(d->indentationDepth);
       
   191 
       
   192     if(!d->hasClosedElement.top().second)
       
   193         d->canIndent.top() = false;
       
   194 
       
   195     startFormattingContent();
       
   196 
       
   197     d->canIndent.pop();
       
   198     d->canIndent.top() = true;
       
   199     QXmlSerializer::endElement();
       
   200 }
       
   201 
       
   202 /*!
       
   203   \reimp
       
   204  */
       
   205 void QXmlFormatter::attribute(const QXmlName &name,
       
   206                               const QStringRef &value)
       
   207 {
       
   208     QXmlSerializer::attribute(name, value);
       
   209 }
       
   210 
       
   211 /*!
       
   212  \reimp
       
   213  */
       
   214 void QXmlFormatter::comment(const QString &value)
       
   215 {
       
   216     Q_D(QXmlFormatter);
       
   217     startFormattingContent();
       
   218     QXmlSerializer::comment(value);
       
   219     d->canIndent.top() = true;
       
   220 }
       
   221 
       
   222 /*!
       
   223  \reimp
       
   224  */
       
   225 void QXmlFormatter::characters(const QStringRef &value)
       
   226 {
       
   227     Q_D(QXmlFormatter);
       
   228     d->isPreviousAtomic = false;
       
   229     d->characterBuffer += value.toString();
       
   230 }
       
   231 
       
   232 /*!
       
   233  \reimp
       
   234  */
       
   235 void QXmlFormatter::processingInstruction(const QXmlName &name,
       
   236                                           const QString &value)
       
   237 {
       
   238     Q_D(QXmlFormatter);
       
   239     startFormattingContent();
       
   240     QXmlSerializer::processingInstruction(name, value);
       
   241     d->canIndent.top() = true;
       
   242 }
       
   243 
       
   244 /*!
       
   245  \reimp
       
   246  */
       
   247 void QXmlFormatter::atomicValue(const QVariant &value)
       
   248 {
       
   249     Q_D(QXmlFormatter);
       
   250     d->canIndent.top() = false;
       
   251     QXmlSerializer::atomicValue(value);
       
   252 }
       
   253 
       
   254 /*!
       
   255  \reimp
       
   256  */
       
   257 void QXmlFormatter::startDocument()
       
   258 {
       
   259     QXmlSerializer::startDocument();
       
   260 }
       
   261 
       
   262 /*!
       
   263  \reimp
       
   264  */
       
   265 void QXmlFormatter::endDocument()
       
   266 {
       
   267     QXmlSerializer::endDocument();
       
   268 }
       
   269 
       
   270 /*!
       
   271  \reimp
       
   272  */
       
   273 void QXmlFormatter::startOfSequence()
       
   274 {
       
   275     QXmlSerializer::startOfSequence();
       
   276 }
       
   277 
       
   278 /*!
       
   279  \reimp
       
   280  */
       
   281 void QXmlFormatter::endOfSequence()
       
   282 {
       
   283     Q_D(QXmlFormatter);
       
   284 
       
   285     /* Flush any buffered content. */
       
   286     if(!d->characterBuffer.isEmpty())
       
   287         QXmlSerializer::characters(QStringRef(&d->characterBuffer));
       
   288 
       
   289     d->write('\n');
       
   290     QXmlSerializer::endOfSequence();
       
   291 }
       
   292 
       
   293 /*!
       
   294  \internal
       
   295  */
       
   296 void QXmlFormatter::item(const QPatternist::Item &item)
       
   297 {
       
   298     Q_D(QXmlFormatter);
       
   299 
       
   300     if(item.isAtomicValue())
       
   301     {
       
   302         if(QPatternist::XPathHelper::isWhitespaceOnly(item.stringValue()))
       
   303            return;
       
   304         else
       
   305         {
       
   306             d->canIndent.top() = false;
       
   307             startFormattingContent();
       
   308         }
       
   309     }
       
   310 
       
   311     QXmlSerializer::item(item);
       
   312 }
       
   313 
       
   314 /*!
       
   315   Returns the number of spaces QXmlFormatter will output for each
       
   316   indentation level. The default is four.
       
   317 
       
   318  \sa setIndentationDepth()
       
   319  */
       
   320 int QXmlFormatter::indentationDepth() const
       
   321 {
       
   322     Q_D(const QXmlFormatter);
       
   323     return d->indentationDepth;
       
   324 }
       
   325 
       
   326 /*!
       
   327   Sets \a depth to be the number of spaces QXmlFormatter will
       
   328   output for level of indentation. The default is four.
       
   329 
       
   330  \sa indentationDepth()
       
   331  */
       
   332 void QXmlFormatter::setIndentationDepth(int depth)
       
   333 {
       
   334     Q_D(QXmlFormatter);
       
   335     d->indentationDepth = depth;
       
   336 }
       
   337 
       
   338 QT_END_NAMESPACE