diff --git a/src/corelib/serialization/qxmlstream.cpp b/src/corelib/serialization/qxmlstream.cpp index 9dcdf490412..50f87900161 100644 --- a/src/corelib/serialization/qxmlstream.cpp +++ b/src/corelib/serialization/qxmlstream.cpp @@ -2913,6 +2913,8 @@ public: uint hasIoError :1; uint hasEncodingError :1; uint autoFormatting :1; + uint didWriteStartDocument :1; + uint didWriteAnyToken :1; std::string autoFormattingIndent; NamespaceDeclaration emptyNamespace; qsizetype lastNamespaceDeclaration; @@ -2946,6 +2948,8 @@ QXmlStreamWriterPrivate::QXmlStreamWriterPrivate(QXmlStreamWriter *q) lastNamespaceDeclaration = 1; autoFormatting = false; namespacePrefixCount = 0; + didWriteStartDocument = false; + didWriteAnyToken = false; } void QXmlStreamWriterPrivate::write(QAnyStringView s) @@ -3065,6 +3069,7 @@ void QXmlStreamWriterPrivate::writeNamespaceDeclaration(const NamespaceDeclarati write(namespaceDeclaration.namespaceUri); write("\""); } + didWriteAnyToken = true; } bool QXmlStreamWriterPrivate::finishStartElement(bool contents) @@ -3084,6 +3089,7 @@ bool QXmlStreamWriterPrivate::finishStartElement(bool contents) } inStartElement = inEmptyElement = false; lastNamespaceDeclaration = namespaceDeclarations.size(); + didWriteAnyToken = true; return hadSomethingWritten; } @@ -3149,7 +3155,8 @@ QXmlStreamPrivateTagStack::NamespaceDeclaration &QXmlStreamWriterPrivate::findNa void QXmlStreamWriterPrivate::indent(int level) { - write("\n"); + if (didWriteStartDocument || didWriteAnyToken) + write("\n"); for (int i = 0; i < level; ++i) write(autoFormattingIndent); } @@ -3375,6 +3382,7 @@ void QXmlStreamWriter::writeAttribute(QAnyStringView qualifiedName, QAnyStringVi d->write("=\""); d->writeEscaped(value, true); d->write("\""); + d->didWriteAnyToken = true; } /*! Writes an attribute with \a name and \a value, prefixed for @@ -3403,6 +3411,7 @@ void QXmlStreamWriter::writeAttribute(QAnyStringView namespaceUri, QAnyStringVie d->write("=\""); d->writeEscaped(value, true); d->write("\""); + d->didWriteAnyToken = true; } /*! @@ -3610,7 +3619,8 @@ void QXmlStreamWriter::writeEndDocument() Q_D(QXmlStreamWriter); while (d->tagStack.size()) writeEndElement(); - d->write("\n"); + if (d->didWriteStartDocument || d->didWriteAnyToken) + d->write("\n"); } /*! @@ -3621,6 +3631,7 @@ void QXmlStreamWriter::writeEndDocument() void QXmlStreamWriter::writeEndElement() { Q_D(QXmlStreamWriter); + Q_ASSERT(d->didWriteAnyToken); if (d->tagStack.isEmpty()) return; @@ -3744,6 +3755,7 @@ void QXmlStreamWriter::writeProcessingInstruction(QAnyStringView target, QAnyStr d->write(data); } d->write("?>"); + d->didWriteAnyToken = true; } @@ -3778,6 +3790,7 @@ void QXmlStreamWriter::writeStartDocument(QAnyStringView version) if (d->device) // stringDevice does not get any encoding d->write("\" encoding=\"UTF-8"); d->write("\"?>"); + d->didWriteStartDocument = true; } /*! Writes a document start with the XML version number \a version @@ -3801,6 +3814,7 @@ void QXmlStreamWriter::writeStartDocument(QAnyStringView version, bool standalon d->write("\" standalone=\"yes\"?>"); else d->write("\" standalone=\"no\"?>"); + d->didWriteStartDocument = true; } @@ -3862,6 +3876,7 @@ void QXmlStreamWriterPrivate::writeStartElement(QAnyStringView namespaceUri, QAn writeNamespaceDeclaration(namespaceDeclarations[i]); } tag.namespaceDeclarationsSize = lastNamespaceDeclaration; + didWriteAnyToken = true; } /*! Writes the current state of the \a reader. All possible valid diff --git a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp index b90d05b0fa1..d40cb8fa8d0 100644 --- a/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp +++ b/tests/auto/corelib/serialization/qxmlstream/tst_qxmlstream.cpp @@ -559,6 +559,10 @@ private slots: void writerAutoFormattingWithProcessingInstructions() const; void writerAutoEmptyTags() const; void writeAttributesWithSpace() const; + void writerAutoFormattingProcessingInstructionFirst() const; + void writerAutoFormattingStartElementFirst() const; + void writerAutoFormattingCommentFirst() const; + void writerAutoFormattingNamespaceFirst() const; void addExtraNamespaceDeclarations(); void setEntityResolver(); void readFromQBuffer() const; @@ -1075,6 +1079,74 @@ void tst_QXmlStream::writeAttributesWithSpace() const QCOMPARE(buffer.buffer().data(), s.toUtf8().data()); } +void tst_QXmlStream::writerAutoFormattingProcessingInstructionFirst() const +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.setAutoFormatting(true); + writer.writeProcessingInstruction("B"); + writer.writeComment("This is a comment"); + writer.writeStartElement("A"); + writer.writeNamespace("http://website.com", "website"); + writer.writeDefaultNamespace("http://websiteNo2.com"); + writer.writeEndElement(); + writer.writeEndDocument(); + const char *str = + "\n\n\n"; + QCOMPARE(buffer.buffer().data(), str); +} +void tst_QXmlStream::writerAutoFormattingStartElementFirst() const +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.setAutoFormatting(true); + writer.writeStartElement("A"); + writer.writeNamespace("http://website.com", "website"); + writer.writeComment("This is a comment"); + writer.writeProcessingInstruction("B"); + writer.writeDefaultNamespace("http://websiteNo2.com"); + writer.writeEndElement(); + writer.writeEndDocument(); + const char *str = "\n \n \n\n"; + QCOMPARE(buffer.buffer().data(), str); +} + +void tst_QXmlStream::writerAutoFormattingCommentFirst() const +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.setAutoFormatting(true); + writer.writeComment("This is a comment"); + writer.writeStartElement("A"); + writer.writeNamespace("http://website.com", "website"); + writer.writeEndElement(); + writer.writeDefaultNamespace("http://websiteNo2.com"); + writer.writeProcessingInstruction("B"); + writer.writeEndDocument(); + const char *str = "\n\n"; + QCOMPARE(buffer.buffer().data(), str); +} + +void tst_QXmlStream::writerAutoFormattingNamespaceFirst() const +{ + QBuffer buffer; + buffer.open(QIODevice::WriteOnly); + QXmlStreamWriter writer(&buffer); + writer.setAutoFormatting(true); + writer.writeNamespace("http://website.com", "website"); + writer.writeStartElement("A"); + writer.writeDefaultNamespace("http://websiteNo2.com"); + writer.writeProcessingInstruction("B"); + writer.writeEndElement(); + writer.writeComment("This is a comment"); + writer.writeEndDocument(); + const char *str = "\n \n\n"; + QCOMPARE(buffer.buffer().data(), str); +} + void tst_QXmlStream::writerAutoEmptyTags() const { QBuffer buffer;