KD SOAP API Documentation 2.2
Loading...
Searching...
No Matches
KDSoapValue.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** This file is part of the KD Soap project.
4**
5** SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6**
7** SPDX-License-Identifier: MIT
8**
9****************************************************************************/
10#include "KDSoapValue.h"
11#include "KDDateTime.h"
14#include <QDateTime>
15#include <QDebug>
16#include <QStringList>
17#include <QUrl>
18
19class KDSoapValue::Private : public QSharedData
20{
21public:
22 Private()
23 : m_qualified(false)
24 , m_nillable(false)
25 {
26 }
27 Private(const QString &n, const QVariant &v, const QString &typeNameSpace, const QString &typeName)
28 : m_name(n)
29 , m_value(v)
30 , m_typeNamespace(typeNameSpace)
31 , m_typeName(typeName)
32 , m_qualified(false)
33 , m_nillable(false)
34 {
35 }
36
37 QString m_name;
38 QString m_nameNamespace;
39 QVariant m_value;
40 QString m_typeNamespace;
41 QString m_typeName;
42 KDSoapValueList m_childValues;
43 bool m_qualified;
44 bool m_nillable;
45 QXmlStreamNamespaceDeclarations m_environmentNamespaceDeclarations;
46 QXmlStreamNamespaceDeclarations m_localNamespaceDeclarations;
47};
48
49uint qHash(const KDSoapValue &value)
50{
51 return qHash(value.name());
52}
53
55 : d(new Private)
56{
57}
58
59KDSoapValue::KDSoapValue(const QString &n, const QVariant &v, const QString &typeNameSpace, const QString &typeName)
60 : d(new Private(n, v, typeNameSpace, typeName))
61{
62}
63
64KDSoapValue::KDSoapValue(const QString &n, const KDSoapValueList &children, const QString &typeNameSpace, const QString &typeName)
65 : d(new Private(n, QVariant(), typeNameSpace, typeName))
66{
67 d->m_childValues = children;
68}
69
73
75 : d(other.d)
76{
77}
78
80{
81 return d->m_name.isEmpty() && isNil();
82}
83
85{
86 return d->m_value.isNull() && d->m_childValues.isEmpty() && d->m_childValues.attributes().isEmpty();
87}
88
89void KDSoapValue::setNillable(bool nillable)
90{
91 d->m_nillable = nillable;
92}
93
95{
96 return d->m_name;
97}
98
100{
101 d->m_name = name;
102}
103
105{
106 return d->m_value;
107}
108
110{
111 d->m_value = value;
112}
113
115{
116 return d->m_qualified;
117}
118
119void KDSoapValue::setQualified(bool qualified)
120{
121 d->m_qualified = qualified;
122}
123
124void KDSoapValue::setNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &namespaceDeclarations)
125{
126 d->m_localNamespaceDeclarations = namespaceDeclarations;
127}
128
130{
131 d->m_localNamespaceDeclarations.append(namespaceDeclaration);
132}
133
134QXmlStreamNamespaceDeclarations KDSoapValue::namespaceDeclarations() const
135{
136 return d->m_localNamespaceDeclarations;
137}
138
139void KDSoapValue::setEnvironmentNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &environmentNamespaceDeclarations)
140{
141 d->m_environmentNamespaceDeclarations = environmentNamespaceDeclarations;
142}
143
144QXmlStreamNamespaceDeclarations KDSoapValue::environmentNamespaceDeclarations() const
145{
146 return d->m_environmentNamespaceDeclarations;
147}
148
150{
151 // I want to fool the QSharedDataPointer mechanism here...
152 return const_cast<KDSoapValueList &>(d->m_childValues);
153}
154
155bool KDSoapValue::operator==(const KDSoapValue &other) const
156{
157 return d == other.d;
158}
159
160bool KDSoapValue::operator!=(const KDSoapValue &other) const
161{
162 return d != other.d;
163}
164
165static QString variantToTextValue(const QVariant &value, const QString &typeNs, const QString &type)
166{
167 switch (value.userType()) {
168 case QVariant::Char:
169 // fall-through
170 case QVariant::String:
171 return value.toString();
172 case QVariant::Url:
173 // xmlpatterns/data/qatomicvalue.cpp says to do this:
174 return value.toUrl().toString();
175 case QVariant::ByteArray: {
176 const QByteArray data = value.toByteArray();
178 if (type == QLatin1String("hexBinary")) {
179 const QByteArray hb = data.toHex();
180 return QString::fromLatin1(hb.constData(), hb.size());
181 }
182 }
183 // default to base64Binary, like variantToXMLType() does.
184 const QByteArray b64 = value.toByteArray().toBase64();
185 return QString::fromLatin1(b64.constData(), b64.size());
186 }
187 case QVariant::Int:
188 // fall-through
190 // fall-through
191 case QVariant::UInt:
192 return QString::number(value.toLongLong());
194 return QString::number(value.toULongLong());
195 case QVariant::Bool:
196 case QMetaType::Float:
197 case QVariant::Double:
198 return value.toString();
199 case QVariant::Time: {
200 const QTime time = value.toTime();
201 if (time.msec()) {
202 // include milli-seconds
203 return time.toString(QLatin1String("hh:mm:ss.zzz"));
204 } else {
205 return time.toString(Qt::ISODate);
206 }
207 }
208 case QVariant::Date:
209 return value.toDate().toString(Qt::ISODate);
210 case QVariant::DateTime: // https://www.w3.org/TR/xmlschema-2/#dateTime
211 return KDDateTime(value.toDateTime()).toDateString();
213 qDebug() << "ERROR: Got invalid QVariant in a KDSoapValue";
214 return QString();
215 default:
216 if (value.canConvert<KDDateTime>()) {
217 return value.value<KDDateTime>().toDateString();
218 }
219
220 if (value.userType() == qMetaTypeId<float>()) {
221 return QString::number(value.value<float>());
222 }
223
224 qDebug() << QString::fromLatin1("QVariants of type %1 are not supported in "
225 "KDSoap, see the documentation")
226 .arg(QLatin1String(value.typeName()));
227 return value.toString();
228 }
229}
230
231// See also xmlTypeToVariant in serverlib
233{
234 switch (value.userType()) {
235 case QVariant::Char:
236 // fall-through
237 case QVariant::String:
238 // fall-through
239 case QVariant::Url:
240 return QLatin1String("xsd:string");
242 return QLatin1String("xsd:base64Binary");
243 case QVariant::Int:
244 // fall-through
246 // fall-through
247 case QVariant::UInt:
248 return QLatin1String("xsd:int");
250 return QLatin1String("xsd:unsignedInt");
251 case QVariant::Bool:
252 return QLatin1String("xsd:boolean");
253 case QMetaType::Float:
254 return QLatin1String("xsd:float");
255 case QVariant::Double:
256 return QLatin1String("xsd:double");
257 case QVariant::Time:
258 return QLatin1String("xsd:time"); // correct? xmlpatterns fallsback to datetime because of missing timezone
259 case QVariant::Date:
260 return QLatin1String("xsd:date");
262 return QLatin1String("xsd:dateTime");
263 default:
264 if (value.userType() == qMetaTypeId<float>()) {
265 return QLatin1String("xsd:float");
266 }
267 if (value.canConvert<KDDateTime>()) {
268 return QLatin1String("xsd:dateTime");
269 }
270
271 qDebug() << value;
272
273 qDebug() << QString::fromLatin1("variantToXmlType: QVariants of type %1 are not supported in "
274 "KDSoap, see the documentation")
275 .arg(QLatin1String(value.typeName()));
276 return QString();
277 }
278}
279
280void KDSoapValue::writeElement(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, KDSoapValue::Use use,
281 const QString &messageNamespace, bool forceQualified) const
282{
283 Q_ASSERT(!name().isEmpty());
284 if (!d->m_nameNamespace.isEmpty() && d->m_nameNamespace != messageNamespace) {
285 forceQualified = true;
286 }
287
288 if (d->m_qualified || forceQualified) {
289 const QString ns = d->m_nameNamespace.isEmpty() ? messageNamespace : d->m_nameNamespace;
290
291 // TODO: if the prefix is new, we want to do namespacePrefixes.insert()
292 // But this means figuring out n2/n3/n4 the same way Qt does...
293
294 writer.writeStartElement(ns, name());
295 } else {
296 writer.writeStartElement(name());
297 }
298 writeElementContents(namespacePrefixes, writer, use, messageNamespace);
299 writer.writeEndElement();
300}
301
302void KDSoapValue::writeElementContents(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, KDSoapValue::Use use,
303 const QString &messageNamespace) const
304{
305 const QVariant value = this->value();
306
307 for (const QXmlStreamNamespaceDeclaration &decl : qAsConst(d->m_localNamespaceDeclarations)) {
308 writer.writeNamespace(decl.namespaceUri().toString(), decl.prefix().toString());
309 }
310
311 if (isNil() && d->m_nillable) {
313 }
314
315 if (use == EncodedUse) {
316 // use=encoded means writing out xsi:type attributes
318 if (!this->type().isEmpty()) {
319 type = namespacePrefixes.resolve(this->typeNs(), this->type());
320 }
321 if (type.isEmpty() && !value.isNull()) {
322 type = variantToXMLType(value); // fallback
323 }
324 if (!type.isEmpty()) {
326 }
327
328 const KDSoapValueList list = this->childValues();
329 const bool isArray = !list.arrayType().isEmpty();
330 if (isArray) {
332 namespacePrefixes.resolve(list.arrayTypeNs(), list.arrayType()) + QLatin1Char('[') + QString::number(list.count())
333 + QLatin1Char(']'));
334 }
335 }
336 writeChildren(namespacePrefixes, writer, use, messageNamespace, false);
337
338 if (!value.isNull()) {
339 const QString txt = variantToTextValue(value, this->typeNs(), this->type());
340 if (!txt.isEmpty()) { // In Qt6, a null string doesn't lead to a null variant anymore
341 writer.writeCharacters(txt);
342 }
343 }
344}
345
346void KDSoapValue::writeChildren(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, KDSoapValue::Use use,
347 const QString &messageNamespace, bool forceQualified) const
348{
349 const KDSoapValueList &args = childValues();
350 const auto &attributes = args.attributes();
351 for (const KDSoapValue &attr : attributes) {
352 // Q_ASSERT(!attr.value().isNull());
353
354 const QString attributeNamespace = attr.namespaceUri();
355 if (attr.isQualified() || forceQualified) {
356 writer.writeAttribute(attributeNamespace, attr.name(), variantToTextValue(attr.value(), attr.typeNs(), attr.type()));
357 } else {
358 writer.writeAttribute(attr.name(), variantToTextValue(attr.value(), attr.typeNs(), attr.type()));
359 }
360 }
362 while (it.hasNext()) {
363 const KDSoapValue &element = it.next();
364 element.writeElement(namespacePrefixes, writer, use, messageNamespace, forceQualified);
365 }
366}
367
369
371{
372 dbg.space() << value.name() << value.value();
373 if (!value.childValues().isEmpty()) {
374 dbg << "<children>";
376 while (it.hasNext()) {
377 const KDSoapValue &child = it.next();
378 dbg << child;
379 }
380 dbg << "</children>";
381 }
382 if (!value.childValues().attributes().isEmpty()) {
383 dbg << "<attributes>";
385 while (it.hasNext()) {
386 const KDSoapValue &child = it.next();
387 dbg << child;
388 }
389 dbg << "</attributes>";
390 }
391 return dbg;
392}
393
394void KDSoapValue::setType(const QString &nameSpace, const QString &type)
395{
396 d->m_typeNamespace = nameSpace;
397 d->m_typeName = type;
398}
399
401{
402 return d->m_typeNamespace;
403}
404
406{
407 return d->m_typeName;
408}
409
411{
412 KDSoapValueList valueList;
413#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
415#else
417#endif
418 valueList.reserve(list.count());
419 for (const QString &part : qAsConst(list)) {
420 KDSoapValue value(*this);
421 value.setValue(part);
422 valueList << value;
423 }
424 return valueList;
425}
426
428{
429 for (const KDSoapValue &val : qAsConst(*this)) {
430 if (val.name() == name) {
431 return val;
432 }
433 }
434 return KDSoapValue();
435}
436
437void KDSoapValueList::setArrayType(const QString &nameSpace, const QString &type)
438{
439 m_arrayType = qMakePair(nameSpace, type);
440}
441
443{
444 return m_arrayType.first;
445}
446
448{
449 return m_arrayType.second;
450}
451
452void KDSoapValueList::addArgument(const QString &argumentName, const QVariant &argumentValue, const QString &typeNameSpace, const QString &typeName)
453{
454 append(KDSoapValue(argumentName, argumentValue, typeNameSpace, typeName));
455}
456
458{
459 return d->m_nameNamespace;
460}
461
463{
464 d->m_nameNamespace = ns;
465}
466
467QByteArray KDSoapValue::toXml(KDSoapValue::Use use, const QString &messageNamespace) const
468{
469 QByteArray data;
470 QXmlStreamWriter writer(&data);
471 writer.writeStartDocument();
472
473 KDSoapNamespacePrefixes namespacePrefixes;
474 namespacePrefixes.writeStandardNamespaces(writer);
475
476 writeElement(namespacePrefixes, writer, use, messageNamespace, false);
477 writer.writeEndDocument();
478
479 return data;
480}
static QString variantToTextValue(const QVariant &value, const QString &typeNs, const QString &type)
static QString variantToXMLType(const QVariant &value)
QDebug operator<<(QDebug dbg, const KDSoapValue &value)
uint qHash(const KDSoapValue &value)
QString toDateString() const
void writeStandardNamespaces(QXmlStreamWriter &writer, KDSoap::SoapVersion version=KDSoap::SOAP1_1, bool messageAddressingEnabled=false, KDSoapMessageAddressingProperties::KDSoapAddressingNamespace messageAddressingNamespace=KDSoapMessageAddressingProperties::Addressing200508)
QString resolve(const QString &ns, const QString &localName) const
QString arrayTypeNs() const
KDSoapValue child(const QString &name) const
QList< KDSoapValue > & attributes()
QString arrayType() const
void addArgument(const QString &argumentName, const QVariant &argumentValue, const QString &typeNameSpace=QString(), const QString &typeName=QString())
void setArrayType(const QString &nameSpace, const QString &type)
KDSoapValueList & childValues() const
@ EncodedUse
each message part references an abstract type using the xsi:type attribute
QXmlStreamNamespaceDeclarations environmentNamespaceDeclarations() const
void addNamespaceDeclaration(const QXmlStreamNamespaceDeclaration &namespaceDeclaration)
QXmlStreamNamespaceDeclarations namespaceDeclarations() const
void setNamespaceUri(const QString &ns)
void setName(const QString &name)
QString namespaceUri() const
void setNillable(bool nillable)
void setType(const QString &nameSpace, const QString &type)
QVariant value() const
void setNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &namespaceDeclarations)
QString typeNs() const
QString name() const
bool operator==(const KDSoapValue &other) const
void setValue(const QVariant &value)
bool isNull() const
QString type() const
void setEnvironmentNamespaceDeclarations(const QXmlStreamNamespaceDeclarations &environmentNamespaceDeclarations)
bool isQualified() const
QByteArray toXml(Use use=LiteralUse, const QString &messageNamespace=QString()) const
bool isNil() const
KDSoapValueList split() const
bool operator!=(const KDSoapValue &other) const
void setQualified(bool qualified)
const char * constData() const const
int size() const const
QByteArray toBase64(QByteArray::Base64Options options) const const
QByteArray toHex() const const
QString toString(Qt::DateFormat format) const const
QDebug & space()
void append(const T &value)
int count(const T &value) const const
bool isEmpty() const const
void reserve(int alloc)
bool hasNext() const const
const T & next()
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString fromLatin1(const char *str, int size)
bool isEmpty() const const
QString number(int n, int base)
SkipEmptyParts
int msec() const const
QString toString(Qt::DateFormat format) const const
QString toString(QUrl::FormattingOptions options) const const
bool canConvert(int targetTypeId) const const
bool isNull() const const
void setValue(const T &value)
QByteArray toByteArray() const const
QDate toDate() const const
QDateTime toDateTime() const const
qlonglong toLongLong(bool *ok) const const
QString toString() const const
QTime toTime() const const
qulonglong toULongLong(bool *ok) const const
QUrl toUrl() const const
const char * typeName() const const
int userType() const const
T value() const const
void writeAttribute(const QString &qualifiedName, const QString &value)
void writeCharacters(const QString &text)
void writeEndDocument()
void writeEndElement()
void writeNamespace(const QString &namespaceUri, const QString &prefix)
void writeStartDocument()
void writeStartElement(const QString &qualifiedName)

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-soap/
Generated on Sat Apr 20 2024 00:04:25 for KD SOAP API Documentation by doxygen 1.9.8