1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
44 #include "qxmlformatter.h"
45 #include "qxpathhelper_p.h"
46 #include "qxmlserializer_p.h"
50 using namespace QPatternist;
52 class QXmlFormatterPrivate : public QXmlSerializerPrivate
55 inline QXmlFormatterPrivate(const QXmlQuery &q,
56 QIODevice *const outputDevice);
60 QString characterBuffer;
64 * Whether we /have/ sent nodes like processing instructions and comments
67 QStack<bool> canIndent;
70 QXmlFormatterPrivate::QXmlFormatterPrivate(const QXmlQuery &query,
71 QIODevice *const outputDevice) : QXmlSerializerPrivate(query, outputDevice)
75 indentString.reserve(30);
76 indentString.resize(1);
77 indentString[0] = QLatin1Char('\n');
78 canIndent.push(false);
83 \brief The QXmlFormatter class is an implementation of QXmlSerializer for transforming XQuery output into formatted XML.
87 \inmodule QtXmlPatterns
89 QXmlFormatter is a subclass of QXmlSerializer that formats the XML
90 output to make it easier for humans to read.
92 QXmlSerializer outputs XML without adding unnecessary whitespace.
93 In particular, it does not add \e {newlines} and indentation.
94 To make the XML output easier to read, QXmlFormatter adds \e{newlines}
95 and indentation by adding, removing, and modifying
96 \l{XQuery Sequence}{sequence nodes} that only consist of whitespace.
97 It also modifies whitespace in other places where it is not
98 significant; e.g., between attributes and in the document prologue.
100 For example, where the base class QXmlSerializer would
103 \quotefile doc/src/snippets/patternist/notIndented.xml
105 QXmlFormatter outputs this:
107 \quotefile doc/src/snippets/patternist/indented.xml
109 If you just want to serialize your XML in a human-readable
110 format, use QXmlFormatter as it is. The default indentation
111 level is 4 spaces, but you can set your own indentation value
112 setIndentationDepth().
114 The \e{newlines} and indentation added by QXmlFormatter are
115 suitable for common formats, such as XHTML, SVG, or Docbook,
116 where whitespace is not significant. However, if your XML will
117 be used as input where whitespace is significant, then you must
118 write your own subclass of QXmlSerializer or QAbstractXmlReceiver.
120 Note that using QXmlFormatter instead of QXmlSerializer will
121 increase computational overhead and document storage size due
122 to the insertion of whitespace.
124 Note also that the indentation style used by QXmlFormatter
125 remains loosely defined and may change in future versions of
126 Qt. If a specific indentation style is required then either
127 use the base class QXmlSerializer directly, or write your own
128 subclass of QXmlSerializer or QAbstractXmlReceiver.
129 Alternatively, you can subclass QXmlFormatter and reimplement
132 \snippet doc/src/snippets/code/src_xmlpatterns_api_qxmlformatter.cpp 0
136 Constructs a formatter that uses the name pool and message
137 handler in \a query, and writes the result to \a outputDevice
140 \a outputDevice is passed directly to QXmlSerializer's constructor.
144 QXmlFormatter::QXmlFormatter(const QXmlQuery &query,
145 QIODevice *outputDevice) : QXmlSerializer(new QXmlFormatterPrivate(query, outputDevice))
152 void QXmlFormatter::startFormattingContent()
156 if(QPatternist::XPathHelper::isWhitespaceOnly(d->characterBuffer))
158 if(d->canIndent.top())
159 QXmlSerializer::characters(QStringRef(&d->indentString));
163 if(!d->characterBuffer.isEmpty()) /* Significant data, we don't touch it. */
164 QXmlSerializer::characters(QStringRef(&d->characterBuffer));
167 d->characterBuffer.clear();
173 void QXmlFormatter::startElement(const QXmlName &name)
176 startFormattingContent();
178 d->indentString.append(QString(d->indentationDepth, QLatin1Char(' ')));
179 d->canIndent.push(true);
181 QXmlSerializer::startElement(name);
187 void QXmlFormatter::endElement()
191 d->indentString.chop(d->indentationDepth);
193 if(!d->hasClosedElement.top().second)
194 d->canIndent.top() = false;
196 startFormattingContent();
199 d->canIndent.top() = true;
200 QXmlSerializer::endElement();
206 void QXmlFormatter::attribute(const QXmlName &name,
207 const QStringRef &value)
209 QXmlSerializer::attribute(name, value);
215 void QXmlFormatter::comment(const QString &value)
218 startFormattingContent();
219 QXmlSerializer::comment(value);
220 d->canIndent.top() = true;
226 void QXmlFormatter::characters(const QStringRef &value)
229 d->isPreviousAtomic = false;
230 d->characterBuffer += value.toString();
236 void QXmlFormatter::processingInstruction(const QXmlName &name,
237 const QString &value)
240 startFormattingContent();
241 QXmlSerializer::processingInstruction(name, value);
242 d->canIndent.top() = true;
248 void QXmlFormatter::atomicValue(const QVariant &value)
251 d->canIndent.top() = false;
252 QXmlSerializer::atomicValue(value);
258 void QXmlFormatter::startDocument()
260 QXmlSerializer::startDocument();
266 void QXmlFormatter::endDocument()
268 QXmlSerializer::endDocument();
274 void QXmlFormatter::startOfSequence()
276 QXmlSerializer::startOfSequence();
282 void QXmlFormatter::endOfSequence()
286 /* Flush any buffered content. */
287 if(!d->characterBuffer.isEmpty())
288 QXmlSerializer::characters(QStringRef(&d->characterBuffer));
291 QXmlSerializer::endOfSequence();
297 void QXmlFormatter::item(const QPatternist::Item &item)
301 if(item.isAtomicValue())
303 if(QPatternist::XPathHelper::isWhitespaceOnly(item.stringValue()))
307 d->canIndent.top() = false;
308 startFormattingContent();
312 QXmlSerializer::item(item);
316 Returns the number of spaces QXmlFormatter will output for each
317 indentation level. The default is four.
319 \sa setIndentationDepth()
321 int QXmlFormatter::indentationDepth() const
323 Q_D(const QXmlFormatter);
324 return d->indentationDepth;
328 Sets \a depth to be the number of spaces QXmlFormatter will
329 output for level of indentation. The default is four.
331 \sa indentationDepth()
333 void QXmlFormatter::setIndentationDepth(int depth)
336 d->indentationDepth = depth;