void KDSoapValue::writeElementContents(KDSoapNamespacePrefixes &namespacePrefixes, QXmlStreamWriter &writer, KDSoapValue::Use use, const QString &messageNamespace) const { const QVariant value = this->value(); if (isNil() && d->m_nillable) { writer.writeAttribute(KDSoapNamespaceManager::xmlSchemaInstance2001(), QLatin1String("nil"), QLatin1String("true")); } if (use == EncodedUse) { // use=encoded means writing out xsi:type attributes. http://www.eherenow.com/soapfight.htm taught me that. QString type; if (!this->type().isEmpty()) { type = namespacePrefixes.resolve(this->typeNs(), this->type()); } if (type.isEmpty() && !value.isNull()) { type = variantToXMLType(value); // fallback } if (!type.isEmpty()) { writer.writeAttribute(KDSoapNamespaceManager::xmlSchemaInstance2001(), QLatin1String("type"), type); } // cppcheck-suppress redundantCopyLocalConst const KDSoapValueList list = this->childValues(); const bool isArray = !list.arrayType().isEmpty(); if (isArray) { writer.writeAttribute(KDSoapNamespaceManager::soapEncoding(), QLatin1String("arrayType"), namespacePrefixes.resolve(list.arrayTypeNs(), list.arrayType()) + QLatin1Char('[') + QString::number(list.count()) + QLatin1Char(']')); } } writeChildren(namespacePrefixes, writer, use, messageNamespace, false); if (!value.isNull()) { writer.writeCharacters(variantToTextValue(value, this->typeNs(), this->type())); } }
// Test parsing of complex replies, like with SugarCRM void testParseComplexReply() { HttpServerThread server(complexTypeResponse(), HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); const KDSoapMessage response = client.call(QLatin1String("getEmployeeCountry"), countryMessage()); QVERIFY(!response.isFault()); QCOMPARE(response.arguments().count(), 1); const KDSoapValueList lst = response.arguments().first().childValues(); QCOMPARE(lst.count(), 3); const KDSoapValue id = lst.first(); QCOMPARE(id.name(), QString::fromLatin1("id")); QCOMPARE(id.value().toString(), QString::fromLatin1("12345")); const KDSoapValue error = lst.at(1); QCOMPARE(error.name(), QString::fromLatin1("error")); const KDSoapValueList errorList = error.childValues(); QCOMPARE(errorList.count(), 3); const KDSoapValue number = errorList.at(0); QCOMPARE(number.name(), QString::fromLatin1("number")); QCOMPARE(number.value().toString(), QString::fromLatin1("0")); const KDSoapValue name = errorList.at(1); QCOMPARE(name.name(), QString::fromLatin1("name")); QCOMPARE(name.value().toString(), QString::fromLatin1("No Error")); const KDSoapValue description = errorList.at(2); QCOMPARE(description.name(), QString::fromLatin1("description")); QCOMPARE(description.value().toString(), QString::fromLatin1("No Error")); const KDSoapValue array = lst.at(2); QCOMPARE(array.name(), QString::fromLatin1("testArray")); //qDebug() << array; // Code from documentation const QString sessionId = response.arguments()[0].value().toString(); Q_UNUSED(sessionId); }
void KDSoapServerObjectInterface::storeFaultAttributes(KDSoapMessage& message) const { // SOAP 1.1 <faultcode>, <faultstring>, <faultfactor>, <detail> message.addArgument(QString::fromLatin1("faultcode"), d->m_faultCode); message.addArgument(QString::fromLatin1("faultstring"), d->m_faultString); message.addArgument(QString::fromLatin1("faultactor"), d->m_faultActor); if (d->m_detailValue.isNil() || d->m_detailValue.isNull()) message.addArgument(QString::fromLatin1("detail"), d->m_detail); else { KDSoapValueList detailAsList; detailAsList.append( d->m_detailValue ); message.addArgument(QString::fromLatin1("detail"), detailAsList); } // TODO : Answer SOAP 1.2 <Code> , <Reason> , <Node> , <Role> , <Detail> }
void KDSoapPendingCall::Private::parseReply() { if (parsed) { return; } const bool doDebug = qgetenv("KDSOAP_DEBUG").toInt(); QNetworkReply *reply = this->reply.data(); #if QT_VERSION >= 0x040600 if (!reply->isFinished()) { qWarning("KDSoap: Parsing reply before it finished!"); return; } #endif parsed = true; const QByteArray data = reply->readAll(); if (doDebug) { qDebug() << data; } if (!data.isEmpty()) { KDSoapMessageReader reader; reader.xmlToMessage(data, &replyMessage, 0, &replyHeaders, this->soapVersion); } if (reply->error()) { if (!replyMessage.isFault()) { replyHeaders.clear(); replyMessage = KDSoapMessage(); replyMessage.setFault(true); if (this->soapVersion == KDSoapClientInterface::SOAP1_2) { replyMessage.setNamespaceUri(QString::fromLatin1("http://www.w3.org/2003/05/soap-envelope")); KDSoapValueList codeValueList; codeValueList.addArgument(QString::fromLatin1("Value"), QString::number(reply->error())); replyMessage.addArgument(QString::fromLatin1("Code"), codeValueList); KDSoapValueList reasonValueList; reasonValueList.addArgument(QString::fromLatin1("Text"), reply->errorString()); replyMessage.addArgument(QString::fromLatin1("Reason"), reasonValueList); } else { replyMessage.addArgument(QString::fromLatin1("faultcode"), QString::number(reply->error())); replyMessage.addArgument(QString::fromLatin1("faultstring"), reply->errorString()); } } } }
void testRequestXml() // this tests the serialization of KDSoapValue[List] in KDSoapClientInterface { HttpServerThread server(emptyResponse(), HttpServerThread::Public); KDSoapClientInterface client(server.endPoint(), countryMessageNamespace()); KDSoapMessage message; message.setUse(KDSoapMessage::EncodedUse); // write out types explicitely // Test simpletype element message.addArgument(QString::fromLatin1("testString"), QString::fromUtf8("Hello Klarälvdalens")); // Test simpletype extended to have an attribute KDSoapValue val(QString::fromLatin1("val"), 5, countryMessageNamespace(), QString::fromLatin1("MyVal")); val.childValues().attributes().append(KDSoapValue(QString::fromLatin1("attr"), QString::fromLatin1("attrValue"))); message.arguments().append(val); // Test complextype with child elements and attributes KDSoapValueList valueList; KDSoapValue orderperson(QString::fromLatin1("orderperson"), QString::fromLatin1("someone"), countryMessageNamespace(), QString::fromLatin1("Person")); valueList.append(orderperson); valueList.attributes().append(KDSoapValue(QString::fromLatin1("attr"), QString::fromLatin1("attrValue"))); message.addArgument(QString::fromLatin1("order"), valueList, countryMessageNamespace(), QString::fromLatin1("MyOrder")); // Code from documentation QRect rect(0, 0, 100, 200); KDSoapValueList rectArgument; rectArgument.addArgument(QLatin1String("x"), rect.x()); rectArgument.addArgument(QLatin1String("y"), rect.y()); rectArgument.addArgument(QLatin1String("width"), rect.width()); rectArgument.addArgument(QLatin1String("height"), rect.height()); message.addArgument(QLatin1String("rect"), rectArgument); // NOTE: type information is missing; setQualified() is missing too. const QString XMLSchemaNS = KDSoapNamespaceManager::xmlSchema2001(); // Test array KDSoapValueList arrayContents; arrayContents.setArrayType(XMLSchemaNS, QString::fromLatin1("string")); arrayContents.append(KDSoapValue(QString::fromLatin1("item"), QString::fromLatin1("kdab"), XMLSchemaNS, QString::fromLatin1("string"))); arrayContents.append(KDSoapValue(QString::fromLatin1("item"), QString::fromLatin1("rocks"), XMLSchemaNS, QString::fromLatin1("string"))); message.addArgument(QString::fromLatin1("testArray"), arrayContents, QString::fromLatin1("http://schemas.xmlsoap.org/soap/encoding/"), QString::fromLatin1("Array")); // Add a header KDSoapMessage header1; header1.setUse(KDSoapMessage::EncodedUse); header1.addArgument(QString::fromLatin1("header1"), QString::fromLatin1("headerValue")); KDSoapHeaders headers; headers << header1; client.call(QLatin1String("test"), message, QString::fromLatin1("MySoapAction"), headers); // Check what we sent QByteArray expectedRequestXml = QByteArray(xmlEnvBegin11()) + " xmlns:n1=\"http://www.kdab.com/xml/MyWsdl/\"" "><soap:Header>" "<n1:header1 xsi:type=\"xsd:string\">headerValue</n1:header1>" "</soap:Header>"; const QByteArray expectedRequestBody = QByteArray("<soap:Body>" "<n1:test>" "<testString xsi:type=\"xsd:string\">Hello Klarälvdalens</testString>" "<val xsi:type=\"n1:MyVal\" attr=\"attrValue\">5</val>" "<order xsi:type=\"n1:MyOrder\" attr=\"attrValue\"><orderperson xsi:type=\"n1:Person\">someone</orderperson></order>" "<rect><x xsi:type=\"xsd:int\">0</x><y xsi:type=\"xsd:int\">0</y><width xsi:type=\"xsd:int\">100</width><height xsi:type=\"xsd:int\">200</height></rect>" "<testArray xsi:type=\"soap-enc:Array\" soap-enc:arrayType=\"xsd:string[2]\">" "<item xsi:type=\"xsd:string\">kdab</item>" "<item xsi:type=\"xsd:string\">rocks</item>" "</testArray>" "</n1:test>" "</soap:Body>") + xmlEnvEnd() + '\n'; // added by QXmlStreamWriter::writeEndDocument QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml + expectedRequestBody)); // Now using persistent headers server.resetReceivedBuffers(); client.setHeader(QLatin1String("header1"), header1); client.call(QLatin1String("test"), message, QString::fromLatin1("MySoapAction")); QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXml + expectedRequestBody)); // Now remove the persistent header (using setHeader + empty message) server.resetReceivedBuffers(); client.setHeader(QLatin1String("header1"), KDSoapMessage()); client.call(QLatin1String("test"), message, QString::fromLatin1("MySoapAction")); const QByteArray expectedRequestXmlNoHeader = QByteArray(xmlEnvBegin11()) + " xmlns:n1=\"http://www.kdab.com/xml/MyWsdl/\"" "><soap:Header/>"; // the empty element does not matter QVERIFY(xmlBufferCompare(server.receivedData(), expectedRequestXmlNoHeader + expectedRequestBody)); }