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()
44void QDomBuilder::startDTD(QStringView name, QStringView publicId, QStringView systemId)
46 QDomDocumentTypePrivate *
const dt = doc->doctype();
48 dt->name = name.toString();
49 dt->publicId = publicId.toString();
50 dt->systemId = systemId.toString();
53QString QDomBuilder::dtdInternalSubset(
const QString &dtd)
57 const QString &name = doc->doctype()->name;
58 QStringView tmp = QStringView(dtd).sliced(dtd.indexOf(name) + name.size());
60 const QString &publicId = doc->doctype()->publicId;
61 if (!publicId.isEmpty())
62 tmp = tmp.sliced(tmp.indexOf(publicId) + publicId.size());
64 const QString &systemId = doc->doctype()->systemId;
65 if (!systemId.isEmpty())
66 tmp = tmp.sliced(tmp.indexOf(systemId) + systemId.size());
68 const qsizetype obra = tmp.indexOf(u'[');
69 const qsizetype cbra = tmp.lastIndexOf(u']');
70 if (obra >= 0 && cbra >= 0)
71 return tmp.left(cbra).sliced(obra + 1).toString();
76bool QDomBuilder::parseDTD(
const QString &dtd)
78 doc->doctype()->internalSubset = dtdInternalSubset(dtd);
82bool QDomBuilder::startElement(
const QString &nsURI,
const QString &qName,
83 const QXmlStreamAttributes &atts)
85 const bool nsProcessing =
86 parseOptions.testFlag(QDomDocument::ParseOption::UseNamespaceProcessing);
88 nsProcessing ? doc->createElementNS(nsURI, qName) : doc->createElement(qName);
92 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
98 for (
const auto &attr : atts) {
99 auto domElement =
static_cast<QDomElementPrivate *>(node);
101 domElement->setAttributeNS(attr.namespaceUri().toString(),
102 attr.qualifiedName().toString(),
103 attr.value().toString());
105 domElement->setAttribute(attr.qualifiedName().toString(),
106 attr.value().toString());
113bool QDomBuilder::endElement()
115 if (!node || node == doc)
117 node = node->parent();
122bool QDomBuilder::characters(
const QString &characters,
bool cdata)
128 QExplicitlySharedDataPointer<QDomNodePrivate> n;
130 n.reset(doc->createCDATASection(characters));
132 n.reset(doc->createTextNode(characters));
136 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
137 node->appendChild(n.get());
142bool QDomBuilder::processingInstruction(
const QString &target,
const QString &data)
145 n = doc->createProcessingInstruction(target, data);
147 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
148 node->appendChild(n);
154bool QDomBuilder::skippedEntity(
const QString &name)
156 QDomNodePrivate *n = doc->createEntityReference(name);
159 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
160 node->appendChild(n);
164void QDomBuilder::fatalError(
const QString &message)
166 parseResult.errorMessage = message;
167 parseResult.errorLine = reader->lineNumber();
168 parseResult.errorColumn = reader->columnNumber();
171bool QDomBuilder::comment(
const QString &characters)
174 n = doc->createComment(characters);
177 n->setLocation(
int(reader->lineNumber()),
int(reader->columnNumber()));
178 node->appendChild(n);
182bool QDomBuilder::unparsedEntityDecl(
const QString &name,
const QString &publicId,
183 const QString &systemId,
const QString ¬ationName)
185 QDomEntityPrivate *e =
186 new QDomEntityPrivate(doc,
nullptr, name, publicId, systemId, notationName);
189 doc->doctype()->appendChild(e);
193bool QDomBuilder::externalEntityDecl(
const QString &name,
const QString &publicId,
194 const QString &systemId)
196 return unparsedEntityDecl(name, publicId, systemId, QString());
199bool QDomBuilder::notationDecl(
const QString &name,
const QString &publicId,
200 const QString &systemId)
202 QDomNotationPrivate *n =
new QDomNotationPrivate(doc,
nullptr, name, publicId, systemId);
205 doc->doctype()->appendChild(n);
210
211
212
213
215QDomParser::QDomParser(QDomDocumentPrivate *d, QXmlStreamReader *r,
216 QDomDocument::ParseOptions options)
217 : reader(r), domBuilder(d, r, options)
221bool QDomParser::parse()
223 return parseProlog() && parseBody();
226bool QDomParser::parseProlog()
230 while (!reader->atEnd()) {
233 if (reader->hasError()) {
234 domBuilder.fatalError(reader->errorString());
238 switch (reader->tokenType()) {
239 case QXmlStreamReader::StartDocument:
240 if (!reader->documentVersion().isEmpty()) {
241 QString value(u"version='"_s);
242 value += reader->documentVersion();
244 if (!reader->documentEncoding().isEmpty()) {
245 value += u" encoding='"_s;
246 value += reader->documentEncoding();
249 if (reader->isStandaloneDocument()) {
250 value += u" standalone='yes'"_s;
253 if (reader->hasStandaloneDeclaration())
254 value += u" standalone='no'"_s;
257 if (!domBuilder.processingInstruction(u"xml"_s, value)) {
258 domBuilder.fatalError(
259 QDomParser::tr(
"Error occurred while processing XML declaration"));
264 case QXmlStreamReader::DTD:
265 domBuilder.startDTD(reader->dtdName(),
266 reader->dtdPublicId(),
267 reader->dtdSystemId());
268 if constexpr (
false) {
270 domBuilder.fatalError(
271 QDomParser::tr(
"Error occurred while processing document type declaration"));
273 if (!domBuilder.parseDTD(reader->text().toString()))
275 if (!parseMarkupDecl())
278 case QXmlStreamReader::Comment:
279 if (!domBuilder.comment(reader->text().toString())) {
280 domBuilder.fatalError(QDomParser::tr(
"Error occurred while processing comment"));
284 case QXmlStreamReader::ProcessingInstruction:
285 if (!domBuilder.processingInstruction(reader->processingInstructionTarget().toString(),
286 reader->processingInstructionData().toString())) {
287 domBuilder.fatalError(
288 QDomParser::tr(
"Error occurred while processing a processing instruction"));
301bool QDomParser::parseBody()
305 while (!reader->atEnd() && !reader->hasError()) {
306 switch (reader->tokenType()) {
307 case QXmlStreamReader::StartElement:
308 if (!domBuilder.startElement(reader->namespaceUri().toString(),
309 reader->qualifiedName().toString(),
310 reader->attributes())) {
311 domBuilder.fatalError(
312 QDomParser::tr(
"Error occurred while processing a start element"));
316 case QXmlStreamReader::EndElement:
317 if (!domBuilder.endElement()) {
318 domBuilder.fatalError(
319 QDomParser::tr(
"Error occurred while processing an end element"));
323 case QXmlStreamReader::Characters:
326 if (reader->isCDATA() || domBuilder.preserveSpacingOnlyNodes()
327 || !(reader->isWhitespace() || reader->text().trimmed().isEmpty())) {
328 if (!domBuilder.characters(reader->text().toString(), reader->isCDATA())) {
329 domBuilder.fatalError(
330 QDomParser::tr(
"Error occurred while processing the element content"));
335 case QXmlStreamReader::Comment:
336 if (!domBuilder.comment(reader->text().toString())) {
337 domBuilder.fatalError(QDomParser::tr(
"Error occurred while processing comments"));
341 case QXmlStreamReader::ProcessingInstruction:
342 if (!domBuilder.processingInstruction(reader->processingInstructionTarget().toString(),
343 reader->processingInstructionData().toString())) {
344 domBuilder.fatalError(
345 QDomParser::tr(
"Error occurred while processing a processing instruction"));
349 case QXmlStreamReader::EntityReference:
350 if (!domBuilder.skippedEntity(reader->name().toString())) {
351 domBuilder.fatalError(
352 QDomParser::tr(
"Error occurred while processing an entity reference"));
357 domBuilder.fatalError(QDomParser::tr(
"Unexpected token"));
364 if (reader->hasError()) {
365 domBuilder.fatalError(reader->errorString());
373bool QDomParser::parseMarkupDecl()
377 const auto entities = reader->entityDeclarations();
378 for (
const auto &entityDecl : entities) {
382 if (!entityDecl.publicId().isEmpty() || !entityDecl.systemId().isEmpty()) {
384 if (!domBuilder.unparsedEntityDecl(entityDecl.name().toString(),
385 entityDecl.publicId().toString(),
386 entityDecl.systemId().toString(),
387 entityDecl.notationName().toString())) {
388 domBuilder.fatalError(
389 QDomParser::tr(
"Error occurred while processing entity declaration"));
395 const auto notations = reader->notationDeclarations();
396 for (
const auto ¬ationDecl : notations) {
397 if (!domBuilder.notationDecl(notationDecl.name().toString(),
398 notationDecl.publicId().toString(),
399 notationDecl.systemId().toString())) {
400 domBuilder.fatalError(
401 QDomParser::tr(
"Error occurred while processing notation declaration"));