diff options
author | Sona Kurazyan <sona.kurazyan@qt.io> | 2019-11-08 16:49:12 +0100 |
---|---|---|
committer | Sona Kurazyan <sona.kurazyan@qt.io> | 2020-01-08 14:43:09 +0100 |
commit | 9e6943370585bdc791caae6c83555b3aa5efe063 (patch) | |
tree | 174f3087a38ccbb6f9143311a6436248cbda9d1e /src/linguist | |
parent | e3f1d3fef117d6dbf7952995506ef1dec9423067 (diff) |
Stop using SAX classes
SAX classes for parsing XML documents will be deprecated soon.
Re-implemented SAX-based xml parsing classes using QXmlStreamReader.
All the parsers now inherit from XmlParser, which drives the parsing
loop and allows overriding the methods for handling different XML tokens
in a specific way depending on the use-case.
Task-number: QTBUG-76177
Change-Id: I5393cc7218beffb4e48187e435c89d1d179deb37
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'src/linguist')
-rw-r--r-- | src/linguist/linguist/linguist.pro | 2 | ||||
-rw-r--r-- | src/linguist/linguist/messagemodel.h | 2 | ||||
-rw-r--r-- | src/linguist/linguist/phrase.cpp | 80 | ||||
-rw-r--r-- | src/linguist/lupdate/ui.cpp | 99 | ||||
-rw-r--r-- | src/linguist/shared/formats.pri | 10 | ||||
-rw-r--r-- | src/linguist/shared/xliff.cpp | 122 | ||||
-rw-r--r-- | src/linguist/shared/xmlparser.cpp | 109 | ||||
-rw-r--r-- | src/linguist/shared/xmlparser.h | 63 |
8 files changed, 323 insertions, 164 deletions
diff --git a/src/linguist/linguist/linguist.pro b/src/linguist/linguist/linguist.pro index af74df8ec..d083896c3 100644 --- a/src/linguist/linguist/linguist.pro +++ b/src/linguist/linguist/linguist.pro @@ -1,4 +1,4 @@ -QT += core-private gui-private widgets xml uitools-private printsupport +QT += core-private gui-private widgets uitools-private printsupport DEFINES += QT_NO_CAST_FROM_ASCII QT_NO_CAST_TO_ASCII diff --git a/src/linguist/linguist/messagemodel.h b/src/linguist/linguist/messagemodel.h index 5c2d95ec2..32f868d51 100644 --- a/src/linguist/linguist/messagemodel.h +++ b/src/linguist/linguist/messagemodel.h @@ -37,8 +37,6 @@ #include <QtCore/QLocale> #include <QtGui/QColor> #include <QtGui/QBitmap> -#include <QtXml/QXmlDefaultHandler> - QT_BEGIN_NAMESPACE diff --git a/src/linguist/linguist/phrase.cpp b/src/linguist/linguist/phrase.cpp index b7b9835f5..064e79f40 100644 --- a/src/linguist/linguist/phrase.cpp +++ b/src/linguist/linguist/phrase.cpp @@ -28,6 +28,7 @@ #include "phrase.h" #include "translator.h" +#include "xmlparser.h" #include <QApplication> #include <QFile> @@ -36,9 +37,7 @@ #include <QRegExp> #include <QTextCodec> #include <QTextStream> -#include <QXmlAttributes> -#include <QXmlDefaultHandler> -#include <QXmlParseException> +#include <QXmlStreamReader> QT_BEGIN_NAMESPACE @@ -104,24 +103,26 @@ bool operator==(const Phrase &p, const Phrase &q) p.definition() == q.definition() && p.phraseBook() == q.phraseBook(); } -class QphHandler : public QXmlDefaultHandler +class QphHandler : public XmlParser { public: - QphHandler(PhraseBook *phraseBook) - : pb(phraseBook), ferrorCount(0) { } - - virtual bool startElement(const QString &namespaceURI, - const QString &localName, const QString &qName, - const QXmlAttributes &atts); - virtual bool endElement(const QString &namespaceURI, - const QString &localName, const QString &qName); - virtual bool characters(const QString &ch); - virtual bool fatalError(const QXmlParseException &exception); + QphHandler(PhraseBook *phraseBook, QXmlStreamReader &reader) + : XmlParser(reader), pb(phraseBook), ferrorCount(0) + { + } + ~QphHandler() override = default; QString language() const { return m_language; } QString sourceLanguage() const { return m_sourceLanguage; } private: + bool startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts) override; + bool endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName) override; + bool characters(const QStringRef &ch) override; + bool fatalError(qint64 line, qint64 column, const QString &message) override; + PhraseBook *pb; QString source; QString target; @@ -133,14 +134,15 @@ private: int ferrorCount; }; -bool QphHandler::startElement(const QString & /* namespaceURI */, - const QString & /* localName */, - const QString &qName, - const QXmlAttributes &atts) +bool QphHandler::startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts) { + Q_UNUSED(namespaceURI) + Q_UNUSED(localName) + if (qName == QLatin1String("QPH")) { - m_language = atts.value(QLatin1String("language")); - m_sourceLanguage = atts.value(QLatin1String("sourcelanguage")); + m_language = atts.value(QLatin1String("language")).toString(); + m_sourceLanguage = atts.value(QLatin1String("sourcelanguage")).toString(); } else if (qName == QLatin1String("phrase")) { source.truncate(0); target.truncate(0); @@ -150,10 +152,12 @@ bool QphHandler::startElement(const QString & /* namespaceURI */, return true; } -bool QphHandler::endElement(const QString & /* namespaceURI */, - const QString & /* localName */, - const QString &qName) +bool QphHandler::endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName) { + Q_UNUSED(namespaceURI) + Q_UNUSED(localName) + if (qName == QLatin1String("source")) source = accum; else if (qName == QLatin1String("target")) @@ -165,20 +169,20 @@ bool QphHandler::endElement(const QString & /* namespaceURI */, return true; } -bool QphHandler::characters(const QString &ch) +bool QphHandler::characters(const QStringRef &ch) { accum += ch; return true; } -bool QphHandler::fatalError(const QXmlParseException &exception) +bool QphHandler::fatalError(qint64 line, qint64 column, const QString &message) { if (ferrorCount++ == 0) { QString msg = PhraseBook::tr("Parse error at line %1, column %2 (%3).") - .arg(exception.lineNumber()).arg(exception.columnNumber()) - .arg(exception.message()); - QMessageBox::information(0, - QObject::tr("Qt Linguist"), msg); + .arg(line) + .arg(column) + .arg(message); + QMessageBox::information(nullptr, QObject::tr("Qt Linguist"), msg); } return false; } @@ -223,20 +227,10 @@ bool PhraseBook::load(const QString &fileName, bool *langGuessed) m_fileName = fileName; - QXmlInputSource in(&f); - QXmlSimpleReader reader; - // don't click on these! - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false); - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true); - reader.setFeature(QLatin1String("http://trolltech.com/xml/features/report-whitespace" - "-only-CharData"), false); - QphHandler *hand = new QphHandler(this); - reader.setContentHandler(hand); - reader.setErrorHandler(hand); - - bool ok = reader.parse(in); - reader.setContentHandler(0); - reader.setErrorHandler(0); + QXmlStreamReader reader(&f); + QphHandler *hand = new QphHandler(this, reader); + reader.setNamespaceProcessing(false); + bool ok = hand->parse(); Translator::languageAndCountry(hand->language(), &m_language, &m_country); *langGuessed = false; diff --git a/src/linguist/lupdate/ui.cpp b/src/linguist/lupdate/ui.cpp index ce4ecc045..f91ffac5b 100644 --- a/src/linguist/lupdate/ui.cpp +++ b/src/linguist/lupdate/ui.cpp @@ -29,40 +29,41 @@ #include "lupdate.h" #include <translator.h> +#include <xmlparser.h> #include <QtCore/QCoreApplication> #include <QtCore/QDebug> #include <QtCore/QFile> #include <QtCore/QString> - -#include <QtXml/QXmlAttributes> -#include <QtXml/QXmlDefaultHandler> -#include <QtXml/QXmlLocator> -#include <QtXml/QXmlParseException> - +#include <QtCore/QXmlStreamReader> QT_BEGIN_NAMESPACE -class UiReader : public QXmlDefaultHandler +class UiReader : public XmlParser { public: - UiReader(Translator &translator, ConversionData &cd) - : m_translator(translator), m_cd(cd), m_lineNumber(-1), m_isTrString(false), - m_insideStringList(false), m_idBasedTranslations(false) - {} - - bool startElement(const QString &namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &atts); - bool endElement(const QString &namespaceURI, const QString &localName, - const QString &qName); - bool characters(const QString &ch); - bool fatalError(const QXmlParseException &exception); - - void setDocumentLocator(QXmlLocator *locator) { m_locator = locator; } + UiReader(Translator &translator, ConversionData &cd, QXmlStreamReader &reader) + : XmlParser(reader), + m_translator(translator), + m_cd(cd), + m_lineNumber(-1), + m_isTrString(false), + m_insideStringList(false), + m_idBasedTranslations(false) + { + } + ~UiReader() override = default; private: + bool startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts) override; + bool endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName) override; + bool characters(const QStringRef &ch) override; + bool fatalError(qint64 line, qint64 column, const QString &message) override; + void flush(); - void readTranslationAttributes(const QXmlAttributes &atts); + void readTranslationAttributes(const QXmlStreamAttributes &atts); Translator &m_translator; ConversionData &m_cd; @@ -71,7 +72,6 @@ private: QString m_comment; QString m_extracomment; QString m_id; - QXmlLocator *m_locator; QString m_accum; int m_lineNumber; @@ -80,8 +80,8 @@ private: bool m_idBasedTranslations; }; -bool UiReader::startElement(const QString &namespaceURI, - const QString &localName, const QString &qName, const QXmlAttributes &atts) +bool UiReader::startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); @@ -95,16 +95,16 @@ bool UiReader::startElement(const QString &namespaceURI, m_insideStringList = true; readTranslationAttributes(atts); } else if (qName == QLatin1String("ui")) { // UI "header" - const int translationTypeIndex = atts.index(QStringLiteral("idbasedtr")); - m_idBasedTranslations = translationTypeIndex >= 0 - && atts.value(translationTypeIndex) == QLatin1String("true"); + const auto attr = QStringLiteral("idbasedtr"); + m_idBasedTranslations = + atts.hasAttribute(attr) && atts.value(attr) == QLatin1String("true"); } m_accum.clear(); return true; } -bool UiReader::endElement(const QString &namespaceURI, - const QString &localName, const QString &qName) +bool UiReader::endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName) { Q_UNUSED(namespaceURI); Q_UNUSED(localName); @@ -127,17 +127,18 @@ bool UiReader::endElement(const QString &namespaceURI, return true; } -bool UiReader::characters(const QString &ch) +bool UiReader::characters(const QStringRef &ch) { - m_accum += ch; + m_accum += ch.toString(); return true; } -bool UiReader::fatalError(const QXmlParseException &exception) +bool UiReader::fatalError(qint64 line, qint64 column, const QString &message) { QString msg = LU::tr("XML error: Parse error at line %1, column %2 (%3).") - .arg(exception.lineNumber()).arg(exception.columnNumber()) - .arg(exception.message()); + .arg(line) + .arg(column) + .arg(message); m_cd.appendError(msg); return false; } @@ -160,17 +161,17 @@ void UiReader::flush() } } -void UiReader::readTranslationAttributes(const QXmlAttributes &atts) +void UiReader::readTranslationAttributes(const QXmlStreamAttributes &atts) { - const QString notr = atts.value(QStringLiteral("notr")); + const auto notr = atts.value(QStringLiteral("notr")); if (notr.isEmpty() || notr != QStringLiteral("true")) { m_isTrString = true; - m_comment = atts.value(QStringLiteral("comment")); - m_extracomment = atts.value(QStringLiteral("extracomment")); + m_comment = atts.value(QStringLiteral("comment")).toString(); + m_extracomment = atts.value(QStringLiteral("extracomment")).toString(); if (m_idBasedTranslations) - m_id = atts.value(QStringLiteral("id")); + m_id = atts.value(QStringLiteral("id")).toString(); if (!m_cd.m_noUiLines) - m_lineNumber = m_locator->lineNumber(); + m_lineNumber = static_cast<int>(reader.lineNumber()); } else { m_isTrString = false; } @@ -184,20 +185,14 @@ bool loadUI(Translator &translator, const QString &filename, ConversionData &cd) cd.appendError(LU::tr("Cannot open %1: %2").arg(filename, file.errorString())); return false; } - QXmlInputSource in(&file); - QXmlSimpleReader reader; - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespaces"), false); - reader.setFeature(QLatin1String("http://xml.org/sax/features/namespace-prefixes"), true); - reader.setFeature(QLatin1String( - "http://trolltech.com/xml/features/report-whitespace-only-CharData"), false); - UiReader handler(translator, cd); - reader.setContentHandler(&handler); - reader.setErrorHandler(&handler); - bool result = reader.parse(in); + + QXmlStreamReader reader(&file); + reader.setNamespaceProcessing(false); + + UiReader uiReader(translator, cd, reader); + bool result = uiReader.parse(); if (!result) cd.appendError(LU::tr("Parse error in UI file")); - reader.setContentHandler(0); - reader.setErrorHandler(0); return result; } diff --git a/src/linguist/shared/formats.pri b/src/linguist/shared/formats.pri index e5f388f2a..d77dacac5 100644 --- a/src/linguist/shared/formats.pri +++ b/src/linguist/shared/formats.pri @@ -1,17 +1,15 @@ - -# infrastructure -QT *= xml - INCLUDEPATH *= $$PWD SOURCES += \ $$PWD/numerus.cpp \ $$PWD/translator.cpp \ - $$PWD/translatormessage.cpp + $$PWD/translatormessage.cpp \ + $$PWD/xmlparser.cpp HEADERS += \ $$PWD/translator.h \ - $$PWD/translatormessage.h + $$PWD/translatormessage.h \ + $$PWF/xmlparser.h # "real" formats readers and writers SOURCES += \ diff --git a/src/linguist/shared/xliff.cpp b/src/linguist/shared/xliff.cpp index c499e9ea5..bc47289b4 100644 --- a/src/linguist/shared/xliff.cpp +++ b/src/linguist/shared/xliff.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "translator.h" +#include "xmlparser.h" #include <QtCore/QDebug> #include <QtCore/QMap> @@ -36,11 +37,6 @@ #include <QtCore/QTextCodec> #include <QtCore/QTextStream> -#include <QtXml/QXmlAttributes> -#include <QtXml/QXmlDefaultHandler> -#include <QtXml/QXmlParseException> - - // The string value is historical and reflects the main purpose: Keeping // obsolete entries separate from the magic file message (which both have // no location information, but typically reside at opposite ends of the file). @@ -368,22 +364,22 @@ static void writeMessage(QTextStream &ts, const TranslatorMessage &msg, const QR } } - -class XLIFFHandler : public QXmlDefaultHandler +class XLIFFHandler : public XmlParser { public: - XLIFFHandler(Translator &translator, ConversionData &cd); + XLIFFHandler(Translator &translator, ConversionData &cd, QXmlStreamReader &reader); + ~XLIFFHandler() override = default; - bool startElement(const QString& namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &atts ); - bool endElement(const QString& namespaceURI, const QString &localName, - const QString &qName ); - bool characters(const QString &ch); - bool fatalError(const QXmlParseException &exception); +private: + bool startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts) override; + bool endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName) override; + bool characters(const QStringRef &ch) override; + bool fatalError(qint64 line, qint64 column, const QString &message) override; - bool endDocument(); + bool endDocument() override; -private: enum XliffContext { XC_xliff, XC_group, @@ -442,14 +438,16 @@ private: QStack<int> m_contextStack; }; -XLIFFHandler::XLIFFHandler(Translator &translator, ConversionData &cd) - : m_translator(translator), m_cd(cd), - m_translate(true), - m_approved(true), - m_lineNumber(-1), - m_URITT(QLatin1String(TrollTsNamespaceURI)), - m_URI(QLatin1String(XLIFF11namespaceURI)), - m_URI12(QLatin1String(XLIFF12namespaceURI)) +XLIFFHandler::XLIFFHandler(Translator &translator, ConversionData &cd, QXmlStreamReader &reader) + : XmlParser(reader, true), + m_translator(translator), + m_cd(cd), + m_translate(true), + m_approved(true), + m_lineNumber(-1), + m_URITT(QLatin1String(TrollTsNamespaceURI)), + m_URI(QLatin1String(XLIFF11namespaceURI)), + m_URI12(QLatin1String(XLIFF12namespaceURI)) {} @@ -485,33 +483,35 @@ bool XLIFFHandler::hasContext(XliffContext ctx) const return false; } -bool XLIFFHandler::startElement(const QString& namespaceURI, - const QString &localName, const QString &qName, const QXmlAttributes &atts ) +bool XLIFFHandler::startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts) { Q_UNUSED(qName); if (namespaceURI == m_URITT) goto bail; - if (namespaceURI != m_URI && namespaceURI != m_URI12) - return false; + if (namespaceURI != m_URI && namespaceURI != m_URI12) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Unknown namespace in the XLIFF file")); + } if (localName == QLatin1String("xliff")) { // make sure that the stack is not empty during parsing pushContext(XC_xliff); } else if (localName == QLatin1String("file")) { - m_fileName = atts.value(QLatin1String("original")); - m_language = atts.value(QLatin1String("target-language")); + m_fileName = atts.value(QLatin1String("original")).toString(); + m_language = atts.value(QLatin1String("target-language")).toString(); m_language.replace(QLatin1Char('-'), QLatin1Char('_')); - m_sourceLanguage = atts.value(QLatin1String("source-language")); + m_sourceLanguage = atts.value(QLatin1String("source-language")).toString(); m_sourceLanguage.replace(QLatin1Char('-'), QLatin1Char('_')); if (m_sourceLanguage == QLatin1String("en")) m_sourceLanguage.clear(); } else if (localName == QLatin1String("group")) { if (atts.value(QLatin1String("restype")) == QLatin1String(restypeContext)) { - m_context = atts.value(QLatin1String("resname")); + m_context = atts.value(QLatin1String("resname")).toString(); pushContext(XC_restype_context); } else { if (atts.value(QLatin1String("restype")) == QLatin1String(restypePlurals)) { pushContext(XC_restype_plurals); - m_id = atts.value(QLatin1String("id")); + m_id = atts.value(QLatin1String("id")).toString(); if (atts.value(QLatin1String("translate")) == QLatin1String("no")) m_translate = false; } else { @@ -523,7 +523,7 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, if (atts.value(QLatin1String("translate")) == QLatin1String("no")) m_translate = false; if (!hasContext(XC_restype_plurals)) { - m_id = atts.value(QLatin1String("id")); + m_id = atts.value(QLatin1String("id")).toString(); if (m_id.startsWith(QLatin1String("_msg"))) m_id.clear(); } @@ -539,19 +539,18 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, if (atts.value(QLatin1String("restype")) != QLatin1String(restypeDummy)) pushContext(XC_restype_translation); } else if (localName == QLatin1String("context-group")) { - QString purpose = atts.value(QLatin1String("purpose")); - if (purpose == QLatin1String("location")) + if (atts.value(QLatin1String("purpose")) == QLatin1String("location")) pushContext(XC_context_group); else pushContext(XC_context_group_any); } else if (currentContext() == XC_context_group && localName == QLatin1String("context")) { - QString ctxtype = atts.value(QLatin1String("context-type")); + const auto ctxtype = atts.value(QLatin1String("context-type")); if (ctxtype == QLatin1String("linenumber")) pushContext(XC_context_linenumber); else if (ctxtype == QLatin1String("sourcefile")) pushContext(XC_context_filename); } else if (currentContext() == XC_context_group_any && localName == QLatin1String("context")) { - QString ctxtype = atts.value(QLatin1String("context-type")); + const auto ctxtype = atts.value(QLatin1String("context-type")); if (ctxtype == QLatin1String(contextMsgctxt)) pushContext(XC_context_comment); else if (ctxtype == QLatin1String(contextOldMsgctxt)) @@ -563,7 +562,7 @@ bool XLIFFHandler::startElement(const QString& namespaceURI, else pushContext(XC_translator_comment); } else if (localName == QLatin1String("ph")) { - QString ctype = atts.value(QLatin1String("ctype")); + QString ctype = atts.value(QLatin1String("ctype")).toString(); if (ctype.startsWith(QLatin1String("x-ch-"))) m_ctype = ctype.mid(5); pushContext(XC_ph); @@ -574,19 +573,21 @@ bail: return true; } -bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localName, - const QString &qName) +bool XLIFFHandler::endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName) { Q_UNUSED(qName); if (namespaceURI == m_URITT) { if (hasContext(XC_trans_unit) || hasContext(XC_restype_plurals)) - m_extra[localName] = accum; + m_extra[localName.toString()] = accum; else - m_translator.setExtra(localName, accum); + m_translator.setExtra(localName.toString(), accum); return true; } - if (namespaceURI != m_URI && namespaceURI != m_URI12) - return false; + if (namespaceURI != m_URI && namespaceURI != m_URI12) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Unknown namespace in the XLIFF file")); + } //qDebug() << "URI:" << namespaceURI << "QNAME:" << qName; if (localName == QLatin1String("xliff")) { popContext(XC_xliff); @@ -640,15 +641,19 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN if (!m_hadAlt) m_oldSources.append(QString()); if (!hasContext(XC_restype_plurals)) { - if (!finalizeMessage(false)) - return false; + if (!finalizeMessage(false)) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Element processing failed")); + } } } else if (localName == QLatin1String("alt-trans")) { popContext(XC_alt_trans); } else if (localName == QLatin1String("group")) { if (popContext(XC_restype_plurals)) { - if (!finalizeMessage(true)) - return false; + if (!finalizeMessage(true)) { + return fatalError(reader.lineNumber(), reader.columnNumber(), + QLatin1String("Element processing failed")); + } } else if (popContext(XC_restype_context)) { m_context.clear(); } else { @@ -658,7 +663,7 @@ bool XLIFFHandler::endElement(const QString &namespaceURI, const QString& localN return true; } -bool XLIFFHandler::characters(const QString &ch) +bool XLIFFHandler::characters(const QStringRef &ch) { if (currentContext() == XC_ph) { // handle the content of <ph> elements @@ -670,7 +675,7 @@ bool XLIFFHandler::characters(const QString &ch) accum.append(chr); } } else { - QString t = ch; + QString t = ch.toString(); t.replace(QLatin1String("\r"), QLatin1String("")); accum.append(t); } @@ -730,23 +735,20 @@ bool XLIFFHandler::finalizeMessage(bool isPlural) return true; } -bool XLIFFHandler::fatalError(const QXmlParseException &exception) +bool XLIFFHandler::fatalError(qint64 line, qint64 column, const QString &message) { QString msg = QString::asprintf("XML error: Parse error at line %d, column %d (%s).\n", - exception.lineNumber(), exception.columnNumber(), - exception.message().toLatin1().data()); + static_cast<int>(line), static_cast<int>(column), + message.toLatin1().data()); m_cd.appendError(msg); return false; } bool loadXLIFF(Translator &translator, QIODevice &dev, ConversionData &cd) { - QXmlInputSource in(&dev); - QXmlSimpleReader reader; - XLIFFHandler hand(translator, cd); - reader.setContentHandler(&hand); - reader.setErrorHandler(&hand); - return reader.parse(in); + QXmlStreamReader reader(&dev); + XLIFFHandler hand(translator, cd, reader); + return hand.parse(); } bool saveXLIFF(const Translator &translator, QIODevice &dev, ConversionData &cd) diff --git a/src/linguist/shared/xmlparser.cpp b/src/linguist/shared/xmlparser.cpp new file mode 100644 index 000000000..bcdca12bb --- /dev/null +++ b/src/linguist/shared/xmlparser.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "xmlparser.h" + +QT_BEGIN_NAMESPACE + +bool XmlParser::parse() +{ + while (!reader.atEnd()) { + reader.readNext(); + if (reader.hasError()) { + fatalError(reader.lineNumber(), reader.columnNumber(), reader.errorString()); + return false; + } + + switch (reader.tokenType()) { + case QXmlStreamReader::StartElement: + if (!startElement(reader.namespaceUri(), reader.name(), reader.qualifiedName(), + reader.attributes())) { + return false; + } + break; + case QXmlStreamReader::EndElement: + if (!endElement(reader.namespaceUri(), reader.name(), reader.qualifiedName())) { + return false; + } + break; + case QXmlStreamReader::Characters: + if (reportWhitespaceOnlyData + || (!reader.isWhitespace() && !reader.text().toString().trimmed().isEmpty())) { + if (!characters(reader.text())) + return false; + } + break; + default: + break; + } + } + if (reader.isEndDocument() && !endDocument()) + return false; + + return true; +} + +bool XmlParser::startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts) +{ + Q_UNUSED(namespaceURI) + Q_UNUSED(localName) + Q_UNUSED(qName) + Q_UNUSED(atts) + return true; +} + +bool XmlParser::endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName) +{ + Q_UNUSED(namespaceURI) + Q_UNUSED(localName) + Q_UNUSED(qName) + return true; +} + +bool XmlParser::characters(const QStringRef &text) +{ + Q_UNUSED(text) + return true; +} + +bool XmlParser::fatalError(qint64 line, qint64 column, const QString &message) +{ + Q_UNUSED(line) + Q_UNUSED(column) + Q_UNUSED(message) + return true; +} + +bool XmlParser::endDocument() +{ + return true; +} + +QT_END_NAMESPACE diff --git a/src/linguist/shared/xmlparser.h b/src/linguist/shared/xmlparser.h new file mode 100644 index 000000000..4028c7067 --- /dev/null +++ b/src/linguist/shared/xmlparser.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Linguist of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef XMLPARSER_H +#define XMLPARSER_H + +#include <QtCore/qglobal.h> +#include <QtCore/qxmlstream.h> + +QT_BEGIN_NAMESPACE + +class XmlParser +{ +public: + XmlParser(QXmlStreamReader &r, bool whitespaceOnlyData = false) + : reader(r), reportWhitespaceOnlyData(whitespaceOnlyData) + { + } + virtual ~XmlParser() = default; + + bool parse(); + +protected: + virtual bool startElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName, const QXmlStreamAttributes &atts); + virtual bool endElement(const QStringRef &namespaceURI, const QStringRef &localName, + const QStringRef &qName); + virtual bool characters(const QStringRef &text); + virtual bool endDocument(); + virtual bool fatalError(qint64 line, qint64 column, const QString &message); + + QXmlStreamReader &reader; + bool reportWhitespaceOnlyData; +}; + +QT_END_NAMESPACE + +#endif // XMLPARSER_H |