1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtXmlPatterns module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qxmlschemavalidator.h"
41#include "qxmlschemavalidator_p.h"
42
43#include "qacceltreeresourceloader_p.h"
44#include "qxmlschema.h"
45#include "qxmlschema_p.h"
46#include "qxsdvalidatinginstancereader_p.h"
47
48#include <QtCore/QBuffer>
49#include <QtCore/QIODevice>
50#include <QtCore/QUrl>
51
52QT_BEGIN_NAMESPACE
53
54/*!
55 \class QXmlSchemaValidator
56
57 \brief The QXmlSchemaValidator class validates XML instance documents against a W3C XML Schema.
58
59 \reentrant
60 \since 4.6
61 \ingroup xml-tools
62 \inmodule QtXmlPatterns
63
64 The QXmlSchemaValidator class loads, parses an XML instance document and validates it
65 against a W3C XML Schema that has been compiled with \l{QXmlSchema}.
66
67 The following example shows how to load a XML Schema from a local
68 file, check whether it is a valid schema document and use it for validation
69 of an XML instance document:
70
71 \snippet qxmlschemavalidator/main.cpp 3
72
73 \section1 XML Schema Version
74
75 This class implements schema validation according to the \l{XML Schema} 1.0
76 specification.
77
78 \sa QXmlSchema, {schema}{XML Schema Validation Example}
79*/
80
81/*!
82 Constructs a schema validator.
83 The schema used for validation must be referenced in the XML instance document
84 via the \c xsi:schemaLocation or \c xsi:noNamespaceSchemaLocation attribute.
85 */
86QXmlSchemaValidator::QXmlSchemaValidator()
87 : d(new QXmlSchemaValidatorPrivate(QXmlSchema()))
88{
89}
90
91/*!
92 Constructs a schema validator that will use \a schema for validation.
93 If an empty \l {QXmlSchema} schema is passed to the validator, the schema used
94 for validation must be referenced in the XML instance document
95 via the \c xsi:schemaLocation or \c xsi:noNamespaceSchemaLocation attribute.
96 */
97QXmlSchemaValidator::QXmlSchemaValidator(const QXmlSchema &schema)
98 : d(new QXmlSchemaValidatorPrivate(schema))
99{
100}
101
102/*!
103 Destroys this QXmlSchemaValidator.
104 */
105QXmlSchemaValidator::~QXmlSchemaValidator()
106{
107 delete d;
108}
109
110/*!
111 Sets the \a schema that shall be used for further validation.
112 If the schema is empty, the schema used for validation must be referenced
113 in the XML instance document via the \c xsi:schemaLocation or
114 \c xsi:noNamespaceSchemaLocation attribute.
115 */
116void QXmlSchemaValidator::setSchema(const QXmlSchema &schema)
117{
118 d->setSchema(schema);
119}
120
121/*!
122 Validates the XML instance document read from \a data with the
123 given \a documentUri against the schema.
124
125 Returns \c true if the XML instance document is valid according to the
126 schema, \c false otherwise.
127
128 Example:
129
130 \snippet qxmlschemavalidator/main.cpp 2
131 */
132bool QXmlSchemaValidator::validate(const QByteArray &data, const QUrl &documentUri) const
133{
134 QByteArray localData(data);
135
136 QBuffer buffer(&localData);
137 buffer.open(openMode: QIODevice::ReadOnly);
138
139 return validate(source: &buffer, documentUri);
140}
141
142/*!
143 Validates the XML instance document read from \a source against the schema.
144
145 Returns \c true if the XML instance document is valid according to the
146 schema, \c false otherwise.
147
148 Example:
149
150 \snippet qxmlschemavalidator/main.cpp 0
151 */
152bool QXmlSchemaValidator::validate(const QUrl &source) const
153{
154 d->m_context->setMessageHandler(messageHandler());
155 d->m_context->setUriResolver(uriResolver());
156 d->m_context->setNetworkAccessManager(networkAccessManager());
157 const QUrl resolved = QPatternist::XPathHelper::normalizeQueryURI(uri: source);
158
159 const QPatternist::AutoPtr<QNetworkReply> reply(
160 QPatternist::AccelTreeResourceLoader::load(
161 uri: resolved, networkManager: d->m_context->networkAccessManager(),
162 context: d->m_context, handling: QPatternist::AccelTreeResourceLoader::ContinueOnError));
163
164 return reply && validate(source: reply.data(), documentUri: source);
165}
166
167/*!
168 Validates the XML instance document read from \a source with the
169 given \a documentUri against the schema.
170
171 Returns \c true if the XML instance document is valid according to the
172 schema, \c false otherwise.
173
174 Example:
175
176 \snippet qxmlschemavalidator/main.cpp 1
177 */
178bool QXmlSchemaValidator::validate(QIODevice *source, const QUrl &documentUri) const
179{
180 if (!source) {
181 qWarning(msg: "A null QIODevice pointer cannot be passed.");
182 return false;
183 }
184
185 if (!source->isReadable()) {
186 qWarning(msg: "The device must be readable.");
187 return false;
188 }
189
190 const QUrl normalizedUri = QPatternist::XPathHelper::normalizeQueryURI(uri: documentUri);
191
192 d->m_context->setMessageHandler(messageHandler());
193 d->m_context->setUriResolver(uriResolver());
194 d->m_context->setNetworkAccessManager(networkAccessManager());
195
196 QPatternist::NetworkAccessDelegator::Ptr delegator(new QPatternist::NetworkAccessDelegator(d->m_context->networkAccessManager(),
197 d->m_context->networkAccessManager()));
198
199 QPatternist::AccelTreeResourceLoader loader(d->m_context->namePool(), delegator, QPatternist::AccelTreeBuilder<true>::SourceLocationsFeature);
200
201 QPatternist::Item item;
202 try {
203 item = loader.openDocument(source, documentUri: normalizedUri, context: d->m_context);
204 } catch (QPatternist::Exception) {
205 return false;
206 }
207
208 const QAbstractXmlNodeModel *model = item.asNode().model();
209
210 QPatternist::XsdValidatedXmlNodeModel *validatedModel = new QPatternist::XsdValidatedXmlNodeModel(model);
211
212 QPatternist::XsdValidatingInstanceReader reader(validatedModel, normalizedUri, d->m_context);
213 if (d->m_schema)
214 reader.addSchema(schema: d->m_schema, url: d->m_schemaDocumentUri);
215 try {
216 reader.read();
217 } catch (QPatternist::Exception) {
218 return false;
219 }
220
221 return true;
222}
223
224/*!
225 Returns the name pool used by this QXmlSchemaValidator for constructing \l
226 {QXmlName} {names}. There is no setter for the name pool, because
227 mixing name pools causes errors due to name confusion.
228 */
229QXmlNamePool QXmlSchemaValidator::namePool() const
230{
231 return d->m_namePool;
232}
233
234/*!
235 Returns the schema that is used for validation.
236 */
237QXmlSchema QXmlSchemaValidator::schema() const
238{
239 return d->m_originalSchema;
240}
241
242/*!
243 Changes the \l {QAbstractMessageHandler}{message handler} for this
244 QXmlSchemaValidator to \a handler. The schema validator sends all parsing and
245 validation messages to this message handler. QXmlSchemaValidator does not take
246 ownership of \a handler.
247
248 Normally, the default message handler is sufficient. It writes
249 compile and validation messages to \e stderr. The default message
250 handler includes color codes if \e stderr can render colors.
251
252 When QXmlSchemaValidator calls QAbstractMessageHandler::message(),
253 the arguments are as follows:
254
255 \table
256 \header
257 \li message() argument
258 \li Semantics
259 \row
260 \li QtMsgType type
261 \li Only QtWarningMsg and QtFatalMsg are used. The former
262 identifies a warning, while the latter identifies an error.
263 \row
264 \li const QString & description
265 \li An XHTML document which is the actual message. It is translated
266 into the current language.
267 \row
268 \li const QUrl &identifier
269 \li Identifies the error with a URI, where the fragment is
270 the error code, and the rest of the URI is the error namespace.
271 \row
272 \li const QSourceLocation & sourceLocation
273 \li Identifies where the error occurred.
274 \endtable
275
276 */
277void QXmlSchemaValidator::setMessageHandler(QAbstractMessageHandler *handler)
278{
279 d->m_userMessageHandler = handler;
280}
281
282/*!
283 Returns the message handler that handles parsing and validation
284 messages for this QXmlSchemaValidator.
285 */
286QAbstractMessageHandler *QXmlSchemaValidator::messageHandler() const
287{
288 if (d->m_userMessageHandler)
289 return d->m_userMessageHandler;
290
291 return d->m_messageHandler.data()->value;
292}
293
294/*!
295 Sets the URI resolver to \a resolver. QXmlSchemaValidator does not take
296 ownership of \a resolver.
297
298 \sa uriResolver()
299 */
300void QXmlSchemaValidator::setUriResolver(const QAbstractUriResolver *resolver)
301{
302 d->m_uriResolver = resolver;
303}
304
305/*!
306 Returns the schema's URI resolver. If no URI resolver has been set,
307 Qt XML Patterns will use the URIs in instance documents as they are.
308
309 The URI resolver provides a level of abstraction, or \e{polymorphic
310 URIs}. A resolver can rewrite \e{logical} URIs to physical ones, or
311 it can translate obsolete or invalid URIs to valid ones.
312
313 When Qt XML Patterns calls QAbstractUriResolver::resolve() the
314 absolute URI is the URI mandated by the schema specification, and the
315 relative URI is the URI specified by the user.
316
317 \sa setUriResolver()
318 */
319const QAbstractUriResolver *QXmlSchemaValidator::uriResolver() const
320{
321 return d->m_uriResolver;
322}
323
324/*!
325 Sets the network manager to \a manager.
326 QXmlSchemaValidator does not take ownership of \a manager.
327
328 \sa networkAccessManager()
329 */
330void QXmlSchemaValidator::setNetworkAccessManager(QNetworkAccessManager *manager)
331{
332 d->m_userNetworkAccessManager = manager;
333}
334
335/*!
336 Returns the network manager, or 0 if it has not been set.
337
338 \sa setNetworkAccessManager()
339 */
340QNetworkAccessManager *QXmlSchemaValidator::networkAccessManager() const
341{
342 if (d->m_userNetworkAccessManager)
343 return d->m_userNetworkAccessManager;
344
345 return d->m_networkAccessManager.data()->value;
346}
347
348QT_END_NAMESPACE
349

source code of qtxmlpatterns/src/xmlpatterns/api/qxmlschemavalidator.cpp