Qt 4.8
qxmlserializer.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include "qdynamiccontext_p.h"
43 #include "qpatternistlocale_p.h"
44 #include "qitem_p.h"
45 #include "qxmlquery_p.h"
46 #include "qxmlserializer_p.h"
47 #include "qxmlserializer.h"
48 
50 
51 using namespace QPatternist;
52 
54  QIODevice *outputDevice)
55  : isPreviousAtomic(false),
56  state(QXmlSerializer::BeforeDocumentElement),
57  np(query.namePool().d),
58  device(outputDevice),
59  codec(QTextCodec::codecForMib(106)), /* UTF-8 */
60  query(query)
61 {
65 
67 
68  /*
69  We push the empty namespace such that first of all
70  namespaceBinding() won't assert on an empty QStack,
71  and such that the empty namespace is in-scope and
72  that the code doesn't attempt to declare it.
73 
74  We push the XML namespace. Although we won't receive
75  declarations for it, we may output attributes by that
76  name.
77  */
78  QVector<QXmlName> defNss;
79  defNss.resize(2);
80  defNss[0] = QXmlName(StandardNamespaces::empty,
81  StandardLocalNames::empty,
82  StandardPrefixes::empty);
83  defNss[1] = QXmlName(StandardNamespaces::xml,
84  StandardLocalNames::empty,
85  StandardPrefixes::xml);
86 
87  namespaces.push(defNss);
88 
89  /* If we don't set this flag, QTextCodec will generate a BOM. */
91 }
92 
160  QIODevice *outputDevice) : QAbstractXmlReceiver(new QXmlSerializerPrivate(query, outputDevice))
161 {
162  if(!outputDevice)
163  {
164  qWarning("outputDevice cannot be null.");
165  return;
166  }
167 
168  if(!outputDevice->isWritable())
169  {
170  qWarning("outputDevice must be opened in write mode.");
171  return;
172  }
173 }
174 
179 {
180 }
181 
186 {
187  Q_D(const QXmlSerializer);
188  return d->state == BeforeDocumentElement ||
189  (d->state == InsideDocumentElement && d->hasClosedElement.size() == 1);
190 }
191 
196 {
198  if (!d->hasClosedElement.top().second) {
199  d->write('>');
200  d->hasClosedElement.top().second = true;
201  }
202 }
203 
208 {
209  if(toEscape.isEmpty()) /* Early exit. */
210  return;
211 
212  QString result;
213  result.reserve(int(toEscape.length() * 1.1));
214  const int length = toEscape.length();
215 
216  for(int i = 0; i < length; ++i)
217  {
218  const QChar c(toEscape.at(i));
219 
220  if(c == QLatin1Char('<'))
221  result += QLatin1String("&lt;");
222  else if(c == QLatin1Char('>'))
223  result += QLatin1String("&gt;");
224  else if(c == QLatin1Char('&'))
225  result += QLatin1String("&amp;");
226  else
227  result += toEscape.at(i);
228  }
229 
230  write(result);
231 }
232 
237 {
238  if(toEscape.isEmpty()) /* Early exit. */
239  return;
240 
241  QString result;
242  result.reserve(int(toEscape.length() * 1.1));
243  const int length = toEscape.length();
244 
245  for(int i = 0; i < length; ++i)
246  {
247  const QChar c(toEscape.at(i));
248 
249  if(c == QLatin1Char('<'))
250  result += QLatin1String("&lt;");
251  else if(c == QLatin1Char('>'))
252  result += QLatin1String("&gt;");
253  else if(c == QLatin1Char('&'))
254  result += QLatin1String("&amp;");
255  else if(c == QLatin1Char('"'))
256  result += QLatin1String("&quot;");
257  else
258  result += toEscape.at(i);
259  }
260 
261  write(result);
262 }
263 
267 void QXmlSerializer::write(const QString &content)
268 {
270  d->device->write(d->codec->fromUnicode(content.constData(), content.length(), &d->converterState));
271 }
272 
277 {
279  const QByteArray &cell = d->nameCache[name.code()];
280 
281  if(cell.isNull())
282  {
283  QByteArray &mutableCell = d->nameCache[name.code()];
284 
285  const QString content(d->np->toLexical(name));
286  mutableCell = d->codec->fromUnicode(content.constData(),
287  content.length(),
288  &d->converterState);
289  d->device->write(mutableCell);
290  }
291  else
292  d->device->write(cell);
293 }
294 
298 void QXmlSerializer::write(const char *const chars)
299 {
301  d->device->write(chars);
302 }
303 
308 {
310  Q_ASSERT(d->device);
311  Q_ASSERT(d->device->isWritable());
312  Q_ASSERT(d->codec);
313  Q_ASSERT(!name.isNull());
314 
315  d->namespaces.push(QVector<QXmlName>());
316 
317  if(atDocumentRoot())
318  {
319  if(d->state == BeforeDocumentElement)
320  d->state = InsideDocumentElement;
321  else if(d->state != InsideDocumentElement)
322  {
323  d->query.d->staticContext()->error(QtXmlPatterns::tr(
324  "Element %1 can't be serialized because it appears outside "
325  "the document element.").arg(formatKeyword(d->np, name)),
326  ReportContext::SENR0001,
327  d->query.d->expression().data());
328  }
329  }
330 
331  startContent();
332  d->write('<');
333  write(name);
334 
335  /* Ensure that the namespace URI used in the name gets outputted. */
336  namespaceBinding(name);
337 
338  d->hasClosedElement.push(qMakePair(name, false));
339  d->isPreviousAtomic = false;
340 }
341 
346 {
348  const QPair<QXmlName, bool> e(d->hasClosedElement.pop());
349  d->namespaces.pop();
350 
351  if(e.second)
352  {
353  write("</");
354  write(e.first);
355  d->write('>');
356  }
357  else
358  write("/>");
359 
360  d->isPreviousAtomic = false;
361 }
362 
367  const QStringRef &value)
368 {
370  Q_ASSERT(!name.isNull());
371 
372  /* Ensure that the namespace URI used in the name gets outputted. */
373  {
374  /* Since attributes doesn't pick up the default namespace, a
375  * namespace declaration would cause trouble if we output it. */
376  if(name.prefix() != StandardPrefixes::empty)
377  namespaceBinding(name);
378  }
379 
380  if(atDocumentRoot())
381  {
382  Q_UNUSED(d);
383  d->query.d->staticContext()->error(QtXmlPatterns::tr(
384  "Attribute %1 can't be serialized because it appears at "
385  "the top level.").arg(formatKeyword(d->np, name)),
386  ReportContext::SENR0001,
387  d->query.d->expression().data());
388  }
389  else
390  {
391  d->write(' ');
392  write(name);
393  write("=\"");
395  d->write('"');
396  }
397 }
398 
403 {
404  Q_D(const QXmlSerializer);
405  const int levelLen = d->namespaces.size();
406 
407  if(nb.prefix() == StandardPrefixes::empty)
408  {
409  for(int lvl = levelLen - 1; lvl >= 0; --lvl)
410  {
411  const QVector<QXmlName> &scope = d->namespaces.at(lvl);
412  const int vectorLen = scope.size();
413 
414  for(int s = vectorLen - 1; s >= 0; --s)
415  {
416  const QXmlName &nsb = scope.at(s);
417 
418  if(nsb.prefix() == StandardPrefixes::empty)
419  return nsb.namespaceURI() == nb.namespaceURI();
420  }
421  }
422  }
423  else
424  {
425  for(int lvl = 0; lvl < levelLen; ++lvl)
426  {
427  const QVector<QXmlName> &scope = d->namespaces.at(lvl);
428  const int vectorLen = scope.size();
429 
430  for(int s = 0; s < vectorLen; ++s)
431  {
432  const QXmlName &n = scope.at(s);
433  if (n.prefix() == nb.prefix() &&
434  n.namespaceURI() == nb.namespaceURI())
435  return true;
436  }
437  }
438  }
439 
440  return false;
441 }
442 
447 {
448  /*
449  * Writes out \a nb.
450  *
451  * Namespace bindings aren't looked up in a cache, because
452  * we typically receive very few.
453  */
454 
457  "It makes no sense to pass a null QXmlName.");
458 
459  Q_ASSERT_X((nb.namespaceURI() != StandardNamespaces::empty) ||
460  (nb.prefix() == StandardPrefixes::empty),
461  Q_FUNC_INFO,
462  "Undeclarations of prefixes aren't allowed in XML 1.0 "
463  "and aren't supposed to be received.");
464 
466  return;
467 
468  if(isBindingInScope(nb))
469  return;
470 
471  d->namespaces.top().append(nb);
472 
473  if(nb.prefix() == StandardPrefixes::empty)
474  write(" xmlns");
475  else
476  {
477  write(" xmlns:");
478  write(d->np->stringForPrefix(nb.prefix()));
479  }
480 
481  write("=\"");
482  writeEscapedAttribute(d->np->stringForNamespace(nb.namespaceURI()));
483  d->write('"');
484 }
485 
490 {
492  Q_ASSERT_X(!value.contains(QLatin1String("--")),
493  Q_FUNC_INFO,
494  "Invalid input; it's the caller's responsibility to ensure "
495  "the input is correct.");
496 
497  startContent();
498  write("<!--");
499  write(value);
500  write("-->");
501  d->isPreviousAtomic = false;
502 }
503 
508 {
510  d->isPreviousAtomic = false;
511  startContent();
512  writeEscaped(value.toString());
513 }
514 
519  const QString &value)
520 {
522  Q_ASSERT_X(!value.contains(QLatin1String("?>")),
523  Q_FUNC_INFO,
524  "Invalid input; it's the caller's responsibility to ensure "
525  "the input is correct.");
526 
527  startContent();
528  write("<?");
529  write(name);
530  d->write(' ');
531  write(value);
532  write("?>");
533 
534  d->isPreviousAtomic = false;
535 }
536 
541 {
543 
544  if(outputItem.isAtomicValue())
545  {
546  if(d->isPreviousAtomic)
547  {
548  startContent();
549  d->write(' ');
550  writeEscaped(outputItem.stringValue());
551  }
552  else
553  {
554  d->isPreviousAtomic = true;
555  const QString value(outputItem.stringValue());
556 
557  if(!value.isEmpty())
558  {
559  startContent();
560  writeEscaped(value);
561  }
562  }
563  }
564  else
565  {
566  startContent();
567  Q_ASSERT(outputItem.isNode());
568  sendAsNode(outputItem);
569  }
570 }
571 
576 {
577  Q_UNUSED(value);
578 }
579 
584 {
586  d->isPreviousAtomic = false;
587 }
588 
593 {
595  d->isPreviousAtomic = false;
596 }
597 
606 {
607  Q_D(const QXmlSerializer);
608  return d->device;
609 }
610 
620 void QXmlSerializer::setCodec(const QTextCodec *outputCodec)
621 {
623  d->codec = outputCodec;
624 }
625 
633 {
634  Q_D(const QXmlSerializer);
635  return d->codec;
636 }
637 
642 {
643 }
644 
649 {
650  /* If this function is changed to flush or close or something like that,
651  * take into consideration QXmlFormatter, especially
652  * QXmlFormatter::endOfSequence().
653  */
654 }
655 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
QBool contains(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition: qstring.h:904
double d
Definition: qnumeric_p.h:62
QIODevice * outputDevice() const
Returns a pointer to the output device.
QString toString() const
Returns a copy of the string reference as a QString object.
Definition: qstring.cpp:8653
virtual void attribute(const QXmlName &name, const QStringRef &value)
Reimplemented Function
const QTextCodec * codec() const
Returns the codec being used by the serializer for encoding its XML output.
unsigned char c[8]
Definition: qnumeric_p.h:62
A push interface for the XPath Data Model. Similar to SAX&#39;s ContentHandler.
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
const QChar at(int i) const
Returns the character at the given index position in the string.
Definition: qstring.h:698
bool isWritable() const
Returns true if data can be written to the device; otherwise returns false.
Definition: qiodevice.cpp:558
virtual void characters(const QStringRef &value)
Reimplemented Function
void writeEscaped(const QString &toEscape)
virtual void comment(const QString &value)
Reimplemented Function
QString formatKeyword(const QString &keyword)
void writeEscapedAttribute(const QString &toEscape)
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
Due to strong interdependencies, this file contains the definitions for the classes Item...
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool isNode() const
Determines whether this item is an atomic value, or a node.
Definition: qitem_p.h:349
virtual void endDocument()
Reimplemented Function
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
void sendAsNode(const QPatternist::Item &outputItem)
Treats outputItem as a node and calls the appropriate function, e.
QTextCodec::ConverterState converterState
#define Q_D(Class)
Definition: qglobal.h:2482
The QChar class provides a 16-bit Unicode character.
Definition: qchar.h:72
void setCodec(const QTextCodec *codec)
Sets the codec the serializer will use for encoding its XML output.
QString prefix(const QXmlNamePool &query) const
Returns the prefix.
Definition: qxmlname.cpp:370
void reserve(int size)
Ensures that the QHash&#39;s internal hash table consists of at least size buckets.
Definition: qhash.h:846
virtual void endElement()
Reimplemented Function
void resize(int size)
Sets the size of the vector to size.
Definition: qvector.h:342
virtual void processingInstruction(const QXmlName &name, const QString &value)
Reimplemented Function
virtual void startOfSequence()
Reimplemented Function
void reserve(int size)
Attempts to allocate memory for at least size characters.
Definition: qstring.h:881
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
The QXmlSerializer class is an implementation of QAbstractXmlReceiver for transforming XQuery output ...
const char * name
The namespace for the internal API of QtXmlPatterns.
Q_CORE_EXPORT void qWarning(const char *,...)
QString stringValue() const
Returns the string value of this Item.
Definition: qitem_p.h:302
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
static QTextCodec * codec(MYSQL *mysql)
Definition: qsql_mysql.cpp:220
QStack< QPair< QXmlName, bool > > hasClosedElement
bool isNull() const
Returns true if this byte array is null; otherwise returns false.
virtual void item(const QPatternist::Item &item)
void push(const T &t)
Adds element t to the top of the stack.
Definition: qstack.h:60
The QStringRef class provides a thin wrapper around QString substrings.
Definition: qstring.h:1099
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
virtual void namespaceBinding(const QXmlName &nb)
Reimplemented Function
ConversionFlags flags
Definition: qtextcodec.h:106
QHash< QXmlName::Code, QByteArray > nameCache
NamespaceCode namespaceURI() const
Definition: qnamepool_p.h:503
bool isAtomicValue() const
Determines whether this item is an atomic value, or a node.
Definition: qitem_p.h:335
#define Q_ASSERT_X(cond, where, what)
Definition: qglobal.h:1837
The QXmlName class represents the name of an XML node, in an efficient, namespace-aware way...
Definition: qxmlname.h:58
Contains functions used for formatting arguments, such as keywords and paths, in translated strings...
Represents an item in the XPath 2.0 Data Model.
Definition: qitem_p.h:182
virtual void endOfSequence()
Reimplemented Function
QXmlSerializerPrivate(const QXmlQuery &q, QIODevice *outputDevice)
Q_OUTOFLINE_TEMPLATE QPair< T1, T2 > qMakePair(const T1 &x, const T2 &y)
Definition: qpair.h:102
bool isBindingInScope(const QXmlName nb) const
virtual void atomicValue(const QVariant &value)
Reimplemented Function
Code code() const
Returns the internal code that contains the id codes for the local name, prefix and namespace URI...
Definition: qnamepool_p.h:528
virtual void startDocument()
Reimplemented Function
void reserve(int size)
Attempts to allocate memory for at least size elements.
Definition: qvector.h:339
QXmlSerializer(const QXmlQuery &query, QIODevice *outputDevice)
Constructs a serializer that uses the name pool and message handler in query, and writes the output t...
The QTextCodec class provides conversions between text encodings.
Definition: qtextcodec.h:62
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
virtual void startElement(const QXmlName &name)
Reimplemented Function
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
int size() const
Returns the number of items in the vector.
Definition: qvector.h:137
bool atDocumentRoot() const
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
const QChar * constData() const
Returns a pointer to the data stored in the QString.
Definition: qstring.h:712
void write(const QXmlName &name)
bool isNull() const
Returns true if this QXmlName is not initialized with a valid combination of {namespace URI}...
Definition: qxmlname.cpp:224
The QXmlQuery class performs XQueries on XML data, or on non-XML data modeled to look like XML...
Definition: qxmlquery.h:79
QStack< QVector< QXmlName > > namespaces
#define Q_FUNC_INFO
Definition: qglobal.h:1871