5#include <QtXml/qtxmlglobal.h>
9#include "qdomhelpers_p.h"
12#include <QtCore/qshareddata.h>
13#include "qxmlstream.h"
14#include "private/qxmlstream_p.h"
18using namespace Qt::StringLiterals;
21
22
23
24
26QDomBuilder::QDomBuilder(QDomDocumentPrivate *d, QXmlStreamReader *r,
27 QDomDocument::ParseOptions options)
28 : doc(d), node(d), reader(r), parseOptions(options)
34QDomBuilder::~QDomBuilder() {}
36bool QDomBuilder::endDocument()
44bool QDomBuilder::startDTD(
const QString &name,
const QString &publicId,
const QString &systemId)
46 doc->doctype()->name = name;
47 doc->doctype()->publicId = publicId;
48 doc->doctype()->systemId = systemId;
52QString QDomBuilder::dtdInternalSubset(
const QString &dtd)
56 const QString &name = doc->doctype()->name;
57 QStringView tmp = QStringView(dtd).sliced(dtd.indexOf(name) + name.size());
59 const QString &publicId = doc->doctype()->publicId;
60 if (!publicId.isEmpty())
61 tmp = tmp.sliced(tmp.indexOf(publicId) + publicId.size());
63 const QString &systemId = doc->doctype()->systemId;
64 if (!systemId.isEmpty())
65 tmp = tmp.sliced(tmp.indexOf(systemId) + systemId.size());
67 const qsizetype obra = tmp.indexOf(u'[');
68 const qsizetype cbra = tmp.lastIndexOf(u']');
69 if (obra >= 0 && cbra >= 0)
70 return tmp.left(cbra).sliced(obra + 1).toString();
75bool QDomBuilder::parseDTD(
const QString &dtd)
77 doc->doctype()->internalSubset = dtdInternalSubset(dtd);
81bool QDomBuilder::startElement(
const QString &nsURI,
const QString &qName,
82 const QXmlStreamAttributes &atts)
84 const bool nsProcessing =
85 parseOptions.testFlag(QDomDocument::ParseOption::UseNamespaceProcessing);
87 nsProcessing ? doc->createElementNS(nsURI, qName) : doc->createElement(qName);
91 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
97 for (
const auto &attr : atts) {
98 auto domElement =
static_cast<QDomElementPrivate *>(node);
100 domElement->setAttributeNS(attr.namespaceUri().toString(),
101 attr.qualifiedName().toString(),
102 attr.value().toString());
104 domElement->setAttribute(attr.qualifiedName().toString(),
105 attr.value().toString());
112bool QDomBuilder::endElement()
114 if (!node || node == doc)
116 node = node->parent();
121bool QDomBuilder::characters(
const QString &characters,
bool cdata)
127 QExplicitlySharedDataPointer<QDomNodePrivate> n;
129 n.reset(doc->createCDATASection(characters));
131 n.reset(doc->createTextNode(characters));
135 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
136 node->appendChild(n.get());
141bool QDomBuilder::processingInstruction(
const QString &target,
const QString &data)
144 n = doc->createProcessingInstruction(target, data);
146 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
147 node->appendChild(n);
153bool QDomBuilder::skippedEntity(
const QString &name)
155 QDomNodePrivate *n = doc->createEntityReference(name);
158 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
159 node->appendChild(n);
163void QDomBuilder::fatalError(
const QString &message)
165 parseResult.errorMessage = message;
166 parseResult.errorLine = reader->lineNumber();
167 parseResult.errorColumn = reader->columnNumber();
170bool QDomBuilder::comment(
const QString &characters)
173 n = doc->createComment(characters);
176 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
177 node->appendChild(n);
181bool QDomBuilder::unparsedEntityDecl(
const QString &name,
const QString &publicId,
182 const QString &systemId,
const QString ¬ationName)
184 QDomEntityPrivate *e =
185 new QDomEntityPrivate(doc,
nullptr, name, publicId, systemId, notationName);
188 doc->doctype()->appendChild(e);
192bool QDomBuilder::externalEntityDecl(
const QString &name,
const QString &publicId,
193 const QString &systemId)
195 return unparsedEntityDecl(name, publicId, systemId, QString());
198bool QDomBuilder::notationDecl(
const QString &name,
const QString &publicId,
199 const QString &systemId)
201 QDomNotationPrivate *n =
new QDomNotationPrivate(doc,
nullptr, name, publicId, systemId);
204 doc->doctype()->appendChild(n);
209
210
211
212
214QDomParser::QDomParser(QDomDocumentPrivate *d, QXmlStreamReader *r,
215 QDomDocument::ParseOptions options)
216 : reader(r), domBuilder(d, r, options)
220bool QDomParser::parse()
222 return parseProlog() && parseBody();
225bool QDomParser::parseProlog()
229 while (!reader->atEnd()) {
232 if (reader->hasError()) {
233 domBuilder.fatalError(reader->errorString());
237 switch (reader->tokenType()) {
238 case QXmlStreamReader::StartDocument:
239 if (!reader->documentVersion().isEmpty()) {
240 QString value(u"version='"_s);
241 value += reader->documentVersion();
243 if (!reader->documentEncoding().isEmpty()) {
244 value += u" encoding='"_s;
245 value += reader->documentEncoding();
248 if (reader->isStandaloneDocument()) {
249 value += u" standalone='yes'"_s;
252 if (reader->hasStandaloneDeclaration())
253 value += u" standalone='no'"_s;
256 if (!domBuilder.processingInstruction(u"xml"_s, value)) {
257 domBuilder.fatalError(
258 QDomParser::tr(
"Error occurred while processing XML declaration"));
263 case QXmlStreamReader::DTD:
264 if (!domBuilder.startDTD(reader->dtdName().toString(),
265 reader->dtdPublicId().toString(),
266 reader->dtdSystemId().toString())) {
267 domBuilder.fatalError(
268 QDomParser::tr(
"Error occurred while processing document type declaration"));
271 if (!domBuilder.parseDTD(reader->text().toString()))
273 if (!parseMarkupDecl())
276 case QXmlStreamReader::Comment:
277 if (!domBuilder.comment(reader->text().toString())) {
278 domBuilder.fatalError(QDomParser::tr(
"Error occurred while processing comment"));
282 case QXmlStreamReader::ProcessingInstruction:
283 if (!domBuilder.processingInstruction(reader->processingInstructionTarget().toString(),
284 reader->processingInstructionData().toString())) {
285 domBuilder.fatalError(
286 QDomParser::tr(
"Error occurred while processing a processing instruction"));
299bool QDomParser::parseBody()
303 while (!reader->atEnd() && !reader->hasError()) {
304 switch (reader->tokenType()) {
305 case QXmlStreamReader::StartElement:
306 if (!domBuilder.startElement(reader->namespaceUri().toString(),
307 reader->qualifiedName().toString(),
308 reader->attributes())) {
309 domBuilder.fatalError(
310 QDomParser::tr(
"Error occurred while processing a start element"));
314 case QXmlStreamReader::EndElement:
315 if (!domBuilder.endElement()) {
316 domBuilder.fatalError(
317 QDomParser::tr(
"Error occurred while processing an end element"));
321 case QXmlStreamReader::Characters:
324 if (reader->isCDATA() || domBuilder.preserveSpacingOnlyNodes()
325 || !(reader->isWhitespace() || reader->text().trimmed().isEmpty())) {
326 if (!domBuilder.characters(reader->text().toString(), reader->isCDATA())) {
327 domBuilder.fatalError(
328 QDomParser::tr(
"Error occurred while processing the element content"));
333 case QXmlStreamReader::Comment:
334 if (!domBuilder.comment(reader->text().toString())) {
335 domBuilder.fatalError(QDomParser::tr(
"Error occurred while processing comments"));
339 case QXmlStreamReader::ProcessingInstruction:
340 if (!domBuilder.processingInstruction(reader->processingInstructionTarget().toString(),
341 reader->processingInstructionData().toString())) {
342 domBuilder.fatalError(
343 QDomParser::tr(
"Error occurred while processing a processing instruction"));
347 case QXmlStreamReader::EntityReference:
348 if (!domBuilder.skippedEntity(reader->name().toString())) {
349 domBuilder.fatalError(
350 QDomParser::tr(
"Error occurred while processing an entity reference"));
355 domBuilder.fatalError(QDomParser::tr(
"Unexpected token"));
362 if (reader->hasError()) {
363 domBuilder.fatalError(reader->errorString());
371bool QDomParser::parseMarkupDecl()
375 const auto entities = reader->entityDeclarations();
376 for (
const auto &entityDecl : entities) {
380 if (!entityDecl.publicId().isEmpty() || !entityDecl.systemId().isEmpty()) {
382 if (!domBuilder.unparsedEntityDecl(entityDecl.name().toString(),
383 entityDecl.publicId().toString(),
384 entityDecl.systemId().toString(),
385 entityDecl.notationName().toString())) {
386 domBuilder.fatalError(
387 QDomParser::tr(
"Error occurred while processing entity declaration"));
393 const auto notations = reader->notationDeclarations();
394 for (
const auto ¬ationDecl : notations) {
395 if (!domBuilder.notationDecl(notationDecl.name().toString(),
396 notationDecl.publicId().toString(),
397 notationDecl.systemId().toString())) {
398 domBuilder.fatalError(
399 QDomParser::tr(
"Error occurred while processing notation declaration"));