QXmlStreamWriter: Ensure correct newline handling with auto-formatting
Previously, QXmlStreamWriter would incorrectly insert a newline before the first token when writeStartDocument() was not used, while auto-formatting was enabled. This fix ensures that the first token is written inline without an extra leading newline, while preserving expected formatting for subsequent tokens. To achieve this, two new flags have been introduced: - didWriteStartDocument: Tracks whether writeStartDocument() was called. - didWriteAnyToken: Ensures that at least one token has been written before allowing newlines. Fixes: QTBUG-28721 Pick-to: 6.9 6.8 Change-Id: I8be7e8fc6ac0e63304359d24c6c8372e5ba42bb4 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
d359035c80
commit
c3295bd59c
@ -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
|
||||
|
@ -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 =
|
||||
"<?B?>\n<!--This is a comment-->\n<A xmlns:website=\"http://website.com\" xmlns=\"http://websiteNo2.com\"/>\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 = "<A xmlns:website=\"http://website.com\">\n <!--This is a comment-->\n <?B?>\n</A>\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 = "<!--This is a comment--><A xmlns:website=\"http://website.com\"/>\n<?B?>\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 = "<A xmlns:website=\"http://website.com\" xmlns=\"http://websiteNo2.com\">\n <?B?></A>\n<!--This is a comment-->\n";
|
||||
QCOMPARE(buffer.buffer().data(), str);
|
||||
}
|
||||
|
||||
void tst_QXmlStream::writerAutoEmptyTags() const
|
||||
{
|
||||
QBuffer buffer;
|
||||
|
Loading…
x
Reference in New Issue
Block a user